rtp meged with lots of AP2 stuff still commented out. But it still works.
This commit is contained in:
@@ -43,6 +43,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <netpacket/packet.h>
|
||||||
|
|
||||||
#ifdef COMPILE_FOR_OSX
|
#ifdef COMPILE_FOR_OSX
|
||||||
#include <CoreServices/CoreServices.h>
|
#include <CoreServices/CoreServices.h>
|
||||||
#include <mach/mach.h>
|
#include <mach/mach.h>
|
||||||
@@ -266,6 +269,148 @@ uint16_t nextFreeUDPPort() {
|
|||||||
return UDPPortIndex;
|
return UDPPortIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if port is zero, pick any port
|
||||||
|
// otherwise, try the given port only
|
||||||
|
int bind_socket_and_port(int type, int ip_family, const char *self_ip_address, uint32_t scope_id,
|
||||||
|
uint16_t *port, int *sock) {
|
||||||
|
int ret = 0; // no error
|
||||||
|
int local_socket = socket(ip_family, type, 0);
|
||||||
|
if (local_socket == -1)
|
||||||
|
ret = errno;
|
||||||
|
if (ret == 0) {
|
||||||
|
SOCKADDR myaddr;
|
||||||
|
memset(&myaddr, 0, sizeof(myaddr));
|
||||||
|
if (ip_family == AF_INET) {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&myaddr;
|
||||||
|
sa->sin_family = AF_INET;
|
||||||
|
sa->sin_port = ntohs(*port);
|
||||||
|
inet_pton(AF_INET, self_ip_address, &(sa->sin_addr));
|
||||||
|
ret = bind(local_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
#ifdef AF_INET6
|
||||||
|
if (ip_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&myaddr;
|
||||||
|
sa6->sin6_family = AF_INET6;
|
||||||
|
sa6->sin6_port = ntohs(*port);
|
||||||
|
inet_pton(AF_INET6, self_ip_address, &(sa6->sin6_addr));
|
||||||
|
sa6->sin6_scope_id = scope_id;
|
||||||
|
ret = bind(local_socket, (struct sockaddr *)sa6, sizeof(struct sockaddr_in6));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = errno;
|
||||||
|
close(local_socket);
|
||||||
|
char errorstring[1024];
|
||||||
|
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
|
||||||
|
warn("error %d: \"%s\". Could not bind a port!", errno, errorstring);
|
||||||
|
} else {
|
||||||
|
uint16_t sport;
|
||||||
|
SOCKADDR local;
|
||||||
|
socklen_t local_len = sizeof(local);
|
||||||
|
ret = getsockname(local_socket, (struct sockaddr *)&local, &local_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
ret = errno;
|
||||||
|
close(local_socket);
|
||||||
|
char errorstring[1024];
|
||||||
|
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
|
||||||
|
warn("error %d: \"%s\". Could not retrieve socket's port!", errno, errorstring);
|
||||||
|
} else {
|
||||||
|
#ifdef AF_INET6
|
||||||
|
if (local.SAFAMILY == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&local;
|
||||||
|
sport = ntohs(sa6->sin6_port);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&local;
|
||||||
|
sport = ntohs(sa->sin_port);
|
||||||
|
}
|
||||||
|
*sock = local_socket;
|
||||||
|
*port = sport;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bind_UDP_port(int ip_family, const char *self_ip_address, uint32_t scope_id, int *sock) {
|
||||||
|
// look for a port in the range, if any was specified.
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
int local_socket = socket(ip_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (local_socket == -1)
|
||||||
|
die("Could not allocate a socket.");
|
||||||
|
|
||||||
|
/*
|
||||||
|
int val = 1;
|
||||||
|
ret = setsockopt(local_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||||
|
if (ret < 0) {
|
||||||
|
char errorstring[1024];
|
||||||
|
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
|
||||||
|
debug(1, "Error %d: \"%s\". Couldn't set SO_REUSEADDR");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
SOCKADDR myaddr;
|
||||||
|
int tryCount = 0;
|
||||||
|
uint16_t desired_port;
|
||||||
|
do {
|
||||||
|
tryCount++;
|
||||||
|
desired_port = nextFreeUDPPort();
|
||||||
|
memset(&myaddr, 0, sizeof(myaddr));
|
||||||
|
if (ip_family == AF_INET) {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&myaddr;
|
||||||
|
sa->sin_family = AF_INET;
|
||||||
|
sa->sin_port = ntohs(desired_port);
|
||||||
|
inet_pton(AF_INET, self_ip_address, &(sa->sin_addr));
|
||||||
|
ret = bind(local_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
#ifdef AF_INET6
|
||||||
|
if (ip_family == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&myaddr;
|
||||||
|
sa6->sin6_family = AF_INET6;
|
||||||
|
sa6->sin6_port = ntohs(desired_port);
|
||||||
|
inet_pton(AF_INET6, self_ip_address, &(sa6->sin6_addr));
|
||||||
|
sa6->sin6_scope_id = scope_id;
|
||||||
|
ret = bind(local_socket, (struct sockaddr *)sa6, sizeof(struct sockaddr_in6));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} while ((ret < 0) && (errno == EADDRINUSE) && (desired_port != 0) &&
|
||||||
|
(tryCount < config.udp_port_range));
|
||||||
|
|
||||||
|
// debug(1,"UDP port chosen: %d.",desired_port);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
close(local_socket);
|
||||||
|
char errorstring[1024];
|
||||||
|
strerror_r(errno, (char *)errorstring, sizeof(errorstring));
|
||||||
|
die("error %d: \"%s\". Could not bind a UDP port! Check the udp_port_range is large enough -- "
|
||||||
|
"it must be "
|
||||||
|
"at least 3, and 10 or more is suggested -- or "
|
||||||
|
"check for restrictive firewall settings or a bad router! UDP base is %u, range is %u and "
|
||||||
|
"current suggestion is %u.",
|
||||||
|
errno, errorstring, config.udp_port_base, config.udp_port_range, desired_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t sport;
|
||||||
|
SOCKADDR local;
|
||||||
|
socklen_t local_len = sizeof(local);
|
||||||
|
getsockname(local_socket, (struct sockaddr *)&local, &local_len);
|
||||||
|
#ifdef AF_INET6
|
||||||
|
if (local.SAFAMILY == AF_INET6) {
|
||||||
|
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&local;
|
||||||
|
sport = ntohs(sa6->sin6_port);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&local;
|
||||||
|
sport = ntohs(sa->sin_port);
|
||||||
|
}
|
||||||
|
*sock = local_socket;
|
||||||
|
return sport;
|
||||||
|
}
|
||||||
|
|
||||||
int get_requested_connection_state_to_output() { return requested_connection_state_to_output; }
|
int get_requested_connection_state_to_output() { return requested_connection_state_to_output; }
|
||||||
|
|
||||||
void set_requested_connection_state_to_output(int v) { requested_connection_state_to_output = v; }
|
void set_requested_connection_state_to_output(int v) { requested_connection_state_to_output = v; }
|
||||||
|
|||||||
@@ -447,4 +447,10 @@ int string_update_with_size(char **str, int *flag, char *s, size_t len);
|
|||||||
// from https://stackoverflow.com/questions/13663617/memdup-function-in-c, with thanks
|
// from https://stackoverflow.com/questions/13663617/memdup-function-in-c, with thanks
|
||||||
void *memdup(const void *mem, size_t size);
|
void *memdup(const void *mem, size_t size);
|
||||||
|
|
||||||
|
int bind_socket_and_port(int type, int ip_family, const char *self_ip_address, uint32_t scope_id,
|
||||||
|
uint16_t *port, int *sock);
|
||||||
|
|
||||||
|
uint16_t bind_UDP_port(int ip_family, const char *self_ip_address, uint32_t scope_id, int *sock);
|
||||||
|
|
||||||
|
|
||||||
#endif // _COMMON_H
|
#endif // _COMMON_H
|
||||||
|
|||||||
@@ -117,13 +117,6 @@ uint32_t modulo_32_offset(uint32_t from, uint32_t to) {
|
|||||||
return UINT32_MAX - from + to + 1;
|
return UINT32_MAX - from + to + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t modulo_64_offset(uint64_t from, uint64_t to) {
|
|
||||||
if (from <= to)
|
|
||||||
return to - from;
|
|
||||||
else
|
|
||||||
return UINT64_MAX - from + to + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void do_flush(uint32_t timestamp, rtsp_conn_info *conn);
|
void do_flush(uint32_t timestamp, rtsp_conn_info *conn);
|
||||||
|
|
||||||
static void ab_resync(rtsp_conn_info *conn) {
|
static void ab_resync(rtsp_conn_info *conn) {
|
||||||
@@ -1589,7 +1582,7 @@ void player_thread_cleanup_handler(void *arg) {
|
|||||||
if (conn->stream.type == ast_apple_lossless)
|
if (conn->stream.type == ast_apple_lossless)
|
||||||
terminate_decoders(conn);
|
terminate_decoders(conn);
|
||||||
|
|
||||||
clear_reference_timestamp(conn);
|
reset_anchor_info(conn);
|
||||||
conn->rtp_running = 0;
|
conn->rtp_running = 0;
|
||||||
pthread_setcancelstate(oldState, NULL);
|
pthread_setcancelstate(oldState, NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,11 @@
|
|||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_AIRPLAY_2
|
||||||
|
#include "pair_ap/pair-internal.h"
|
||||||
|
#include "plist/plist.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "alac.h"
|
#include "alac.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
@@ -76,6 +81,11 @@ typedef enum {
|
|||||||
ast_apple_lossless,
|
ast_apple_lossless,
|
||||||
} audio_stream_type;
|
} audio_stream_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ts_ntp,
|
||||||
|
ts_ptp
|
||||||
|
} timing_source_type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int encrypted;
|
int encrypted;
|
||||||
uint8_t aesiv[16], aeskey[16];
|
uint8_t aesiv[16], aeskey[16];
|
||||||
@@ -83,8 +93,20 @@ typedef struct {
|
|||||||
audio_stream_type type;
|
audio_stream_type type;
|
||||||
} stream_cfg;
|
} stream_cfg;
|
||||||
|
|
||||||
|
#ifdef CONFIG_AIRPLAY_2
|
||||||
|
typedef struct file_cipher_context {
|
||||||
|
struct pair_cipher_context *cipher_context;
|
||||||
|
int active; // can be created during a pair setup but not activated until next read
|
||||||
|
int fd;
|
||||||
|
void *input_plaintext_buffer;
|
||||||
|
void *input_plaintext_buffer_toq;
|
||||||
|
size_t input_plaintext_buffer_bytes_occupied;
|
||||||
|
} file_cipher_context;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int connection_number; // for debug ID purposes, nothing else...
|
int connection_number; // for debug ID purposes, nothing else...
|
||||||
|
timing_source_type type_of_timing; // are we using NTP or PTP?
|
||||||
int resend_interval; // this is really just for debugging
|
int resend_interval; // this is really just for debugging
|
||||||
char *UserAgent; // free this on teardown
|
char *UserAgent; // free this on teardown
|
||||||
int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency
|
int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency
|
||||||
@@ -94,7 +116,7 @@ typedef struct {
|
|||||||
uint32_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero
|
uint32_t maximum_latency; // set if an a=max-latency: line appears in the ANNOUNCE message; zero
|
||||||
// otherwise
|
// otherwise
|
||||||
int software_mute_enabled; // if we don't have a real mute that we can use
|
int software_mute_enabled; // if we don't have a real mute that we can use
|
||||||
int unachievable_audio_backend_latency_offset_notified; // set when a latency warning is issued
|
|
||||||
|
|
||||||
int fd;
|
int fd;
|
||||||
int authorized; // set if a password is required and has been supplied
|
int authorized; // set if a password is required and has been supplied
|
||||||
@@ -214,8 +236,56 @@ typedef struct {
|
|||||||
|
|
||||||
// this is what connects an rtp timestamp to the remote time
|
// this is what connects an rtp timestamp to the remote time
|
||||||
|
|
||||||
uint32_t reference_timestamp;
|
int anchor_remote_info_is_valid;
|
||||||
uint64_t remote_reference_timestamp_time;
|
uint64_t anchor_clock;
|
||||||
|
uint64_t anchor_time; // this is the time according to the clock
|
||||||
|
uint32_t anchor_rtptime;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_AIRPLAY_2
|
||||||
|
pthread_t rtp_event_thread;
|
||||||
|
pthread_t rtp_ap2_control_thread;
|
||||||
|
pthread_t rtp_realtime_audio_thread;
|
||||||
|
pthread_t rtp_buffered_audio_thread;
|
||||||
|
|
||||||
|
int pairing_mode;
|
||||||
|
file_cipher_context control_cipher_context;
|
||||||
|
struct verifier_setup_context *server_setup_ctx;
|
||||||
|
|
||||||
|
int last_anchor_info_is_valid;
|
||||||
|
uint64_t last_anchor_clock_offset;
|
||||||
|
uint64_t last_anchor_time_of_update;
|
||||||
|
uint64_t last_anchor_clock;
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t ap2_audio_buffer_size;
|
||||||
|
int ap2_flush_requested;
|
||||||
|
uint32_t ap2_flush_rtp_timestamp;
|
||||||
|
uint32_t ap2_flush_sequence_number;
|
||||||
|
int ap2_rate; // protect with flush mutex, 0 means don't play, 1 means play
|
||||||
|
int ap2_play_enabled; // protect with flush mutex
|
||||||
|
|
||||||
|
int event_socket;
|
||||||
|
SOCKADDR ap2_remote_control_socket_addr; // a socket pointing to the control port of the client
|
||||||
|
socklen_t ap2_remote_control_socket_addr_length;
|
||||||
|
int ap2_control_socket;
|
||||||
|
int realtime_audio_socket;
|
||||||
|
int buffered_audio_socket;
|
||||||
|
|
||||||
|
uint16_t local_event_port;
|
||||||
|
uint16_t local_ap2_control_port;
|
||||||
|
uint16_t local_realtime_audio_port;
|
||||||
|
uint16_t local_buffered_audio_port;
|
||||||
|
|
||||||
|
plist_t client_setup_plist;
|
||||||
|
uint64_t audio_format;
|
||||||
|
uint64_t compression;
|
||||||
|
unsigned char *session_key; // needs to be free'd at the end
|
||||||
|
uint64_t frames_packet;
|
||||||
|
uint64_t type;
|
||||||
|
uint64_t networkTimeTimelineID; // the clock ID used by the player
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// used as the initials values for calculating the rate at which the source thinks it's sending
|
// used as the initials values for calculating the rate at which the source thinks it's sending
|
||||||
// frames
|
// frames
|
||||||
@@ -272,7 +342,6 @@ typedef struct {
|
|||||||
} rtsp_conn_info;
|
} rtsp_conn_info;
|
||||||
|
|
||||||
uint32_t modulo_32_offset(uint32_t from, uint32_t to);
|
uint32_t modulo_32_offset(uint32_t from, uint32_t to);
|
||||||
uint64_t modulo_64_offset(uint64_t from, uint64_t to);
|
|
||||||
|
|
||||||
int player_play(rtsp_conn_info *conn);
|
int player_play(rtsp_conn_info *conn);
|
||||||
int player_stop(rtsp_conn_info *conn);
|
int player_stop(rtsp_conn_info *conn);
|
||||||
|
|||||||
@@ -17,17 +17,11 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, uint16_t controlport, uint16_t
|
|||||||
void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn);
|
void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn);
|
||||||
void rtp_request_client_pause(rtsp_conn_info *conn); // ask the client to pause
|
void rtp_request_client_pause(rtsp_conn_info *conn); // ask the client to pause
|
||||||
|
|
||||||
void get_reference_timestamp_stuff(uint32_t *timestamp, uint64_t *timestamp_time,
|
void reset_anchor_info(rtsp_conn_info *conn);
|
||||||
uint64_t *remote_timestamp_time, rtsp_conn_info *conn);
|
|
||||||
void clear_reference_timestamp(rtsp_conn_info *conn);
|
|
||||||
|
|
||||||
int have_timestamp_timing_information(rtsp_conn_info *conn);
|
int have_timestamp_timing_information(rtsp_conn_info *conn);
|
||||||
|
|
||||||
int get_frame_play_time(int64_t timestamp, int sample_ratio, uint64_t *time_to_play);
|
|
||||||
|
|
||||||
int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn);
|
int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn);
|
||||||
int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn);
|
int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn);
|
||||||
|
|
||||||
int sanitised_source_rate_information(uint32_t *frames, uint64_t *time, rtsp_conn_info *conn);
|
|
||||||
|
|
||||||
#endif // _RTP_H
|
#endif // _RTP_H
|
||||||
|
|||||||
Reference in New Issue
Block a user