From ab42a1a457bdf90915bd08e304ef89a7d4866ec1 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Sat, 25 Feb 2017 18:05:46 +0000 Subject: [PATCH 01/17] Version 3.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1386880d..ec06680f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Shairport Sync ============= -**Welcome to Version 3 of Shairport Sync. This is a big update from version 2. Please see the Release Notes for more information.** +**Welcome to Version 3 of Shairport Sync. This is a big update from Version 2. Please see the Release Notes for more information.** Shairport Sync is an AirPlay audio player – it plays audio streamed from iTunes, iOS devices and other AirPlay sources such as Quicktime Player and ForkedDaapd, among others. Audio played by a Shairport Sync-powered device stays synchronised with the source and hence with similar devices playing the same source. In this way, synchronised multi-room audio is possible without difficulty. (Hence the name Shairport Sync, BTW.) From 7d672bcf561f37e4711b6fe8b6547e9636b0d20d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Tue, 7 Mar 2017 22:42:23 +0000 Subject: [PATCH 02/17] Untested, probably not working --- player.c | 97 +++++++++++++++++++++++++------------------------------- player.h | 49 +++++++++++++++++++++++++--- rtp.c | 16 +++++----- rtp.h | 2 -- rtsp.c | 15 ++------- 5 files changed, 98 insertions(+), 81 deletions(-) diff --git a/player.c b/player.c index 9b265279..9faa2031 100644 --- a/player.c +++ b/player.c @@ -76,11 +76,6 @@ #include "apple_alac.h" #endif -// parameters from the source -static unsigned char *aesiv; -#ifdef HAVE_LIBSSL -static AES_KEY aes; -#endif static int input_rate, input_bit_depth, input_num_channels, max_frames_per_packet; static uint32_t timestamp_epoch, last_timestamp, @@ -99,17 +94,8 @@ static int max_frame_size_change; // maximal resampling shift - conservative //#define OUTFRAME_BYTES(max_frames_per_packet) (4 * (max_frames_per_packet + 3)) -#ifdef HAVE_LIBMBEDTLS -static mbedtls_aes_context dctx; -#endif - -#ifdef HAVE_LIBPOLARSSL -static aes_context dctx; -#endif - // static pthread_t player_thread = NULL; static int please_stop; -static int encrypted; // Normally the audio is encrypted, but it may not be static int connection_state_to_output; // if true, then play incoming stuff; if false drop everything @@ -118,7 +104,6 @@ static alac_file *decoder_info; // debug variables static int late_packet_message_sent; -static uint64_t packet_count = 0; static int32_t last_seqno_read; static int decoder_in_use = 0; @@ -305,7 +290,7 @@ static inline int seq32_order(uint32_t a, uint32_t b) { return (C & 0x80000000) == 0; } -static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) { +static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_conn_info* conn) { // parameters: where the decoded stuff goes, its length in samples, // the incoming packet, the length of the incoming packet in bytes // destlen should contain the allowed max number of samples on entry @@ -322,18 +307,18 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) { int outsize = input_bytes_per_frame * (*destlen); // the size the output should be, in bytes int toutsize = outsize; - if (encrypted) { + if (conn->stream.encrypted) { unsigned char iv[16]; int aeslen = len & ~0xf; - memcpy(iv, aesiv, sizeof(iv)); + memcpy(iv, conn->stream.aesiv, sizeof(iv)); #ifdef HAVE_LIBMBEDTLS - mbedtls_aes_crypt_cbc(&dctx, MBEDTLS_AES_DECRYPT, aeslen, iv, buf, packet); + mbedtls_aes_crypt_cbc(&conn->dctx, MBEDTLS_AES_DECRYPT, aeslen, iv, buf, packet); #endif #ifdef HAVE_LIBPOLARSSL - aes_crypt_cbc(&dctx, AES_DECRYPT, aeslen, iv, buf, packet); + aes_crypt_cbc(&conn->dctx, AES_DECRYPT, aeslen, iv, buf, packet); #endif #ifdef HAVE_LIBSSL - AES_cbc_encrypt(buf, packet, aeslen, &aes, iv, AES_DECRYPT); + AES_cbc_encrypt(buf, packet, aeslen, &conn->aes, iv, AES_DECRYPT); #endif memcpy(packet + aeslen, buf + aeslen, len - aeslen); #ifdef HAVE_APPLE_ALAC @@ -377,7 +362,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) { if (outsize > toutsize) { debug(2, "Output from alac_decode larger (%d bytes, not frames) than expected (%d bytes) -- " "truncated, but buffer overflow possible! Encrypted = %d.", - outsize, toutsize, encrypted); + outsize, toutsize, conn->stream.encrypted); reply = -1; // output packet is the wrong size } @@ -524,14 +509,14 @@ static void free_buffer(void) { free(audio_buffer[i].data); } -void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info *itr) { // all timestamps are done at the output rate int64_t ltimestamp = timestamp * output_sample_ratio; // ignore a request to flush that has been made before the first packet... - if (packet_count == 0) { + if (itr->packet_count == 0) { pthread_mutex_lock(&flush_mutex); flush_requested = 0; flush_rtp_timestamp = 0; @@ -539,7 +524,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { } pthread_mutex_lock(&ab_mutex); - packet_count++; + itr->packet_count++; time_of_last_audio_packet = get_absolute_time_in_fp(); if (connection_state_to_output) { // if we are supposed to be processing these packets @@ -603,7 +588,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { if (abuf) { int datalen = max_frames_per_packet; - if (alac_decode(abuf->data, &datalen, data, len) == 0) { + if (alac_decode(abuf->data, &datalen, data, len, itr) == 0) { abuf->ready = 1; abuf->length = datalen; abuf->timestamp = ltimestamp; @@ -1490,8 +1475,28 @@ typedef struct stats { // statistics for running averages } stats_t; static void *player_thread_func(void *arg) { - struct inter_threads_record itr; - itr.please_stop = 0; + + rtsp_conn_info *conn = (rtsp_conn_info *)arg; + + conn->please_stop = 0; + conn->packet_count = 0; + + if (conn->stream.encrypted) { +#ifdef HAVE_LIBMBEDTLS + memset(&conn->dctx, 0, sizeof(mbedtls_aes_context)); + mbedtls_aes_setkey_dec(&conn->dctx, conn->stream.aeskey, 128); +#endif + +#ifdef HAVE_LIBPOLARSSL + memset(&conn->dctx, 0, sizeof(aes_context)); + aes_setkey_dec(&conn->dctx, conn->stream.aeskey, 128); +#endif + +#ifdef HAVE_LIBSSL + AES_set_decrypt_key(conn->stream.aeskey, 128, &conn->aes); +#endif + } + timestamp_epoch = 0; // indicate that the next timestamp will be the first one. maximum_timestamp_interval = input_rate * 60; // actually there shouldn't be more than about 13v // seconds of a gap between successive rtptimes, at @@ -1522,9 +1527,9 @@ static void *player_thread_func(void *arg) { // create and start the timing, control and audio receiver threads pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread; - pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)&itr); - pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, (void *)&itr); - pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)&itr); + pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn); + pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn); + pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn); session_corrections = 0; play_segment_reference_frame = 0; // zero signals that we are not in a play segment @@ -2211,7 +2216,7 @@ static void *player_thread_func(void *arg) { if (sbuf) free(sbuf); debug(1, "Shut down audio, control and timing threads"); - itr.please_stop = 1; + conn->please_stop = 1; pthread_kill(rtp_audio_thread, SIGUSR1); pthread_kill(rtp_control_thread, SIGUSR1); pthread_kill(rtp_timing_thread, SIGUSR1); @@ -2430,31 +2435,15 @@ void player_flush(int64_t timestamp) { #endif } -int player_play(stream_cfg *stream, pthread_t *player_thread) { +int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { + +// need to use conn in place of streram below. Need to put the stream as a parameter to he // if (*player_thread!=NULL) // die("Trying to create a second player thread for this RTSP session"); - packet_count = 0; - encrypted = stream->encrypted; if (config.buffer_start_fill > BUFFER_FRAMES) die("specified buffer starting fill %d > buffer size %d", config.buffer_start_fill, BUFFER_FRAMES); - if (encrypted) { -#ifdef HAVE_LIBMBEDTLS - memset(&dctx, 0, sizeof(mbedtls_aes_context)); - mbedtls_aes_setkey_dec(&dctx, stream->aeskey, 128); -#endif - -#ifdef HAVE_LIBPOLARSSL - memset(&dctx, 0, sizeof(aes_context)); - aes_setkey_dec(&dctx, stream->aeskey, 128); -#endif - -#ifdef HAVE_LIBSSL - AES_set_decrypt_key(stream->aeskey, 128, &aes); -#endif - aesiv = stream->aesiv; - } - init_decoder(stream->fmtp); // this sets up incoming rate, bit depth, channels + init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels // must be after decoder init init_buffer(); please_stop = 0; @@ -2482,12 +2471,12 @@ int player_play(stream_cfg *stream, pthread_t *player_thread) { rc = pthread_attr_setstacksize(&tattr, size); if (rc) debug(1, "Error setting stack size for player_thread: %s", strerror(errno)); - pthread_create(player_thread, &tattr, player_thread_func, NULL); + pthread_create(player_thread, &tattr, player_thread_func, (void*)conn); pthread_attr_destroy(&tattr); return 0; } -void player_stop(pthread_t *player_thread) { +void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { // if (*thread==NULL) // debug(1,"Trying to stop a non-existent player thread"); // else { diff --git a/player.h b/player.h index eba97e8e..8ffd153b 100644 --- a/player.h +++ b/player.h @@ -1,6 +1,22 @@ #ifndef _PLAYER_H #define _PLAYER_H +#include "config.h" + +#ifdef HAVE_LIBMBEDTLS +#include +#include +#endif + +#ifdef HAVE_LIBPOLARSSL +#include +#include +#endif + +#ifdef HAVE_LIBSSL +#include +#endif + #include "audio.h" typedef struct { @@ -9,18 +25,43 @@ typedef struct { int32_t fmtp[12]; } stream_cfg; +typedef struct { + int fd; + int authorized; // set if a password is required and has been supplied + stream_cfg stream; + SOCKADDR remote, local; + int stop; + int running; + pthread_t thread; + pthread_t player_thread; + + uint32_t please_stop; + uint64_t packet_count; +#ifdef HAVE_LIBMBEDTLS + mbedtls_aes_context dctx; +#endif + +#ifdef HAVE_LIBPOLARSSL + aes_context dctx; +#endif + +#ifdef HAVE_LIBSSL + AES_KEY aes; +#endif +} rtsp_conn_info; + + typedef uint16_t seq_t; // wrapped number between two seq_t. int32_t seq_diff(seq_t a, seq_t b); -int player_play(stream_cfg *cfg, pthread_t *thread); -void player_stop(pthread_t *thread); +int player_play(pthread_t *thread, rtsp_conn_info* conn); +void player_stop(pthread_t *thread, rtsp_conn_info* conn); void player_volume(double f); void player_flush(int64_t timestamp); - -void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len); +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info* conn); int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic // timestamp guaranteed to start between 2^32 2^33 diff --git a/rtp.c b/rtp.c index dcaf28d4..4f17e6e0 100644 --- a/rtp.c +++ b/rtp.c @@ -98,7 +98,7 @@ void *rtp_audio_receiver(void *arg) { debug(2, "Audio receiver -- Server RTP thread starting."); // we inherit the signal mask (SIGUSR1) - struct inter_threads_record *itr = arg; + rtsp_conn_info *conn = arg; int32_t last_seqno = -1; uint8_t packet[2048], *pktp; @@ -114,7 +114,7 @@ void *rtp_audio_receiver(void *arg) { float stat_M2 = 0.0; ssize_t nread; - while (itr->please_stop == 0) { + while (conn->please_stop == 0) { nread = recv(audio_socket, packet, sizeof(packet), 0); uint64_t local_time_now_fp = get_absolute_time_in_fp(); @@ -174,7 +174,7 @@ void *rtp_audio_receiver(void *arg) { // check if packet contains enough content to be reasonable if (plen >= 16) { - player_put_packet(seqno, timestamp, pktp, plen); + player_put_packet(seqno, timestamp, pktp, plen,conn); continue; } if (type == 0x56 && seqno == 0) { @@ -197,7 +197,7 @@ void *rtp_control_receiver(void *arg) { // we inherit the signal mask (SIGUSR1) debug(2, "Control receiver -- Server RTP thread starting."); - struct inter_threads_record *itr = arg; + rtsp_conn_info *conn = arg; reference_timestamp = 0; // nothing valid received yet uint8_t packet[2048], *pktp; @@ -205,7 +205,7 @@ void *rtp_control_receiver(void *arg) { uint64_t remote_time_of_sync, local_time_now, remote_time_now; int64_t sync_rtp_timestamp, rtp_timestamp_less_latency; ssize_t nread; - while (itr->please_stop == 0) { + while (conn->please_stop == 0) { nread = recv(control_socket, packet, sizeof(packet), 0); local_time_now = get_absolute_time_in_fp(); // clock_gettime(CLOCK_MONOTONIC,&tn); @@ -281,7 +281,7 @@ void *rtp_control_receiver(void *arg) { // check if packet contains enough content to be reasonable if (plen >= 16) { - player_put_packet(seqno, timestamp, pktp, plen); + player_put_packet(seqno, timestamp, pktp, plen, conn); continue; } else { debug(1, "Too-short retransmitted audio packet received in control port, ignored."); @@ -356,7 +356,7 @@ void *rtp_timing_receiver(void *arg) { debug(2, "Timing receiver -- Server RTP thread starting."); // we inherit the signal mask (SIGUSR1) - struct inter_threads_record *itr = arg; + rtsp_conn_info *conn = arg; uint8_t packet[2048], *pktp; ssize_t nread; @@ -374,7 +374,7 @@ void *rtp_timing_receiver(void *arg) { uint64_t first_local_to_remote_time_difference = 0; uint64_t first_local_to_remote_time_difference_time; uint64_t l2rtd = 0; - while (itr->please_stop == 0) { + while (conn->please_stop == 0) { nread = recv(timing_socket, packet, sizeof(packet), 0); arrival_time = get_absolute_time_in_fp(); // clock_gettime(CLOCK_MONOTONIC,&att); diff --git a/rtp.h b/rtp.h index f4c8ab0b..4f6da117 100644 --- a/rtp.h +++ b/rtp.h @@ -5,8 +5,6 @@ #include "player.h" -typedef struct inter_threads_record { uint32_t please_stop; } inter_threads_record; - void *rtp_audio_receiver(void *arg); void *rtp_control_receiver(void *arg); void *rtp_timing_receiver(void *arg); diff --git a/rtsp.c b/rtsp.c index 59594019..164c8e8b 100644 --- a/rtsp.c +++ b/rtsp.c @@ -90,17 +90,6 @@ static pthread_mutex_t reference_counter_lock = PTHREAD_MUTEX_INITIALIZER; // static int please_shutdown = 0; // static pthread_t playing_thread = 0; -typedef struct { - int fd; - int authorized; // set is a password is required and has been supplied - stream_cfg stream; - SOCKADDR remote, local; - int stop; - int running; - pthread_t thread; - pthread_t player_thread; -} rtsp_conn_info; - static rtsp_conn_info *playing_conn = NULL; // the data structure representing the connection that has the player. static rtsp_conn_info **conns = NULL; @@ -819,7 +808,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * strcat(hdr, q); // should unsplice the timing port entry } - player_play(&conn->stream, &conn->player_thread); // the thread better be 0 + player_play(&conn->player_thread,conn); // the thread better be 0 char *resphdr = alloca(200); *resphdr = 0; @@ -1764,7 +1753,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { debug(1, "Closing down RTSP conversation thread..."); if (rtsp_playing()) { - player_stop(&conn->player_thread); // might be less noisy doing this first + player_stop(&conn->player_thread,conn); // might be less noisy doing this first rtp_shutdown(); // usleep(400000); // let an angel pass... pthread_mutex_unlock(&play_lock); From cbcda67f64674d04de5f8edfa0edfed89c834ae0 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 8 Mar 2017 16:17:35 +0000 Subject: [PATCH 03/17] Fix a bug to ensure a silent frame is supplied to replace a missing frame. --- player.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/player.c b/player.c index 9faa2031..77092228 100644 --- a/player.c +++ b/player.c @@ -1166,8 +1166,7 @@ static abuf_t *buffer_get_frame(void) { if (!curframe->ready) { // debug(1, "Supplying a silent frame for frame %u", read); missing_packets++; - memset(curframe->data, 0, input_bytes_per_frame * max_frames_per_packet); - curframe->timestamp = 0; + curframe->timestamp = 0; // indicate a silent frame should be substituted } curframe->ready = 0; ab_read = SUCCESSOR(ab_read); @@ -1698,19 +1697,11 @@ static void *player_thread_func(void *arg) { inbuflength = inframe->length; if (inbuf) { play_number++; - // if it's a supplied silent frame, let us know... if (inframe->timestamp == 0) { // debug(1,"Player has a supplied silent frame."); last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder - if (inbuf == NULL) - debug(1, "NULL inbuf to play -- skipping it."); - else { - if (inbuflength == 0) - debug(1, "empty frame to play -- skipping it (1)."); - else - config.output->play(inbuf, inbuflength); - } + config.output->play(silence, max_frames_per_packet * output_sample_ratio); } else { int enable_dither = 0; @@ -2067,6 +2058,7 @@ static void *player_thread_func(void *arg) { } } } + // mark the frame as finished inframe->timestamp = 0; From 498c1d6e1836c7fd054b60feba690aee653b84b5 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 8 Mar 2017 19:58:02 +0000 Subject: [PATCH 04/17] Move buffer inside player thread --- player.c | 64 +++++++++++++++++++++++++------------------------------- player.h | 18 +++++++++++++--- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/player.c b/player.c index 77092228..aa782931 100644 --- a/player.c +++ b/player.c @@ -113,20 +113,13 @@ static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; // default buffer size // needs to be a power of 2 because of the way BUFIDX(seqno) works -#define BUFFER_FRAMES 512 +//#define BUFFER_FRAMES 512 #define MAX_PACKET 2048 // DAC buffer occupancy stuff #define DAC_BUFFER_QUEUE_MINIMUM_LENGTH 600 -typedef struct audio_buffer_entry { // decoded audio packets - int ready; - int64_t timestamp; - seq_t sequence_number; - signed short *data; - int length; // the length of the decoded data -} abuf_t; -static abuf_t audio_buffer[BUFFER_FRAMES]; +//static abuf_t audio_buffer[BUFFER_FRAMES]; #define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES) // mutex-protected variables @@ -205,11 +198,11 @@ int64_t monotonic_timestamp(uint32_t timestamp) { // add an epoch to the seq_no. Uses the accompanying timestamp to determine the correct epoch uint64_t monotonic_seqno(uint16_t seq_no) {} -static void ab_resync(void) { +static void ab_resync(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) { - audio_buffer[i].ready = 0; - audio_buffer[i].sequence_number = 0; + conn->audio_buffer[i].ready = 0; + conn->audio_buffer[i].sequence_number = 0; } ab_synced = 0; last_seqno_read = -1; @@ -495,28 +488,28 @@ static void terminate_decoders(void) { #endif } -static void init_buffer(void) { +static void init_buffer(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) - audio_buffer[i].data = + conn->audio_buffer[i].data = malloc(input_bytes_per_frame * (max_frames_per_packet + max_frame_size_change)); - ab_resync(); + ab_resync(conn); } -static void free_buffer(void) { +static void free_buffer(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) - free(audio_buffer[i].data); + free(conn->audio_buffer[i].data); } -void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info *itr) { +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info *conn) { // all timestamps are done at the output rate int64_t ltimestamp = timestamp * output_sample_ratio; // ignore a request to flush that has been made before the first packet... - if (itr->packet_count == 0) { + if (conn->packet_count == 0) { pthread_mutex_lock(&flush_mutex); flush_requested = 0; flush_rtp_timestamp = 0; @@ -524,7 +517,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r } pthread_mutex_lock(&ab_mutex); - itr->packet_count++; + conn->packet_count++; time_of_last_audio_packet = get_absolute_time_in_fp(); if (connection_state_to_output) { // if we are supposed to be processing these packets @@ -550,7 +543,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r ab_synced = 1; } if (ab_write == seqno) { // expected packet - abuf = audio_buffer + BUFIDX(seqno); + abuf = conn->audio_buffer + BUFIDX(seqno); ab_write = SUCCESSOR(seqno); } else if (seq_order(ab_write, seqno)) { // newer than expected // if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8) @@ -561,19 +554,19 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r debug(1, "Unexpected gap size: %d.", gap); int i; for (i = 0; i < gap; i++) { - abuf = audio_buffer + BUFIDX(seq_sum(ab_write, i)); + abuf = conn->audio_buffer + BUFIDX(seq_sum(ab_write, i)); abuf->ready = 0; // to be sure, to be sure abuf->timestamp = 0; abuf->sequence_number = 0; } // debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write); - abuf = audio_buffer + BUFIDX(seqno); + abuf = conn->audio_buffer + BUFIDX(seqno); // rtp_request_resend(ab_write, gap); // resend_requests++; ab_write = SUCCESSOR(seqno); } else if (seq_order(ab_read, seqno)) { // late but not yet played late_packets++; - abuf = audio_buffer + BUFIDX(seqno); + abuf = conn->audio_buffer + BUFIDX(seqno); } else { // too late. too_late_packets++; /* @@ -588,7 +581,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r if (abuf) { int datalen = max_frames_per_packet; - if (alac_decode(abuf->data, &datalen, data, len, itr) == 0) { + if (alac_decode(abuf->data, &datalen, data, len, conn) == 0) { abuf->ready = 1; abuf->length = datalen; abuf->timestamp = ltimestamp; @@ -776,7 +769,7 @@ static inline short dithered_vol(short sample) { } // get the next frame, when available. return 0 if underrun/stream reset. -static abuf_t *buffer_get_frame(void) { +static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { int16_t buf_fill; uint64_t local_time_now; // struct timespec tn; @@ -823,7 +816,7 @@ static abuf_t *buffer_get_frame(void) { if (flush_requested == 1) { if (config.output->flush) config.output->flush(); - ab_resync(); + ab_resync(conn); first_packet_timestamp = 0; first_packet_time_to_play = 0; time_since_play_started = 0; @@ -834,7 +827,7 @@ static abuf_t *buffer_get_frame(void) { uint32_t flush_limit = 0; if (ab_synced) { do { - curframe = audio_buffer + BUFIDX(ab_read); + curframe = conn->audio_buffer + BUFIDX(ab_read); if ((ab_read != ab_write) && (curframe->ready)) { // it could be synced and empty, under // exceptional circumstances, with the // frame unused, thus apparently ready @@ -869,7 +862,7 @@ static abuf_t *buffer_get_frame(void) { flush_limit = 0; } - curframe = audio_buffer + BUFIDX(ab_read); + curframe = conn->audio_buffer + BUFIDX(ab_read); if (curframe->ready) { notified_buffer_empty = 0; // at least one buffer now -- diagnostic only. @@ -968,7 +961,7 @@ static abuf_t *buffer_get_frame(void) { if (config.output->flush) config.output->flush(); - ab_resync(); + ab_resync(conn); first_packet_timestamp = 0; first_packet_time_to_play = 0; time_since_play_started = 0; @@ -993,7 +986,7 @@ static abuf_t *buffer_get_frame(void) { // ab_write)); if (config.output->flush) config.output->flush(); - ab_resync(); + ab_resync(conn); first_packet_timestamp = 0; first_packet_time_to_play = 0; } else { @@ -1154,7 +1147,7 @@ static abuf_t *buffer_get_frame(void) { if (!ab_buffering) { for (i = 8; i < (seq_diff(ab_read, ab_write) / 2); i = (i * 2)) { seq_t next = seq_sum(ab_read, i); - abuf = audio_buffer + BUFIDX(next); + abuf = conn->audio_buffer + BUFIDX(next); if (!abuf->ready) { rtp_request_resend(next, 1); // debug(1,"Resend %u.",next); @@ -1521,6 +1514,8 @@ static void *player_thread_func(void *arg) { output_bytes_per_frame = 8; break; } + + init_buffer(conn); debug(1, "Output frame bytes is %d.", output_bytes_per_frame); @@ -1691,7 +1686,7 @@ static void *player_thread_func(void *arg) { uint64_t tens_of_seconds = 0; while (!please_stop) { - abuf_t *inframe = buffer_get_frame(); + abuf_t *inframe = buffer_get_frame(conn); if (inframe) { inbuf = inframe->data; inbuflength = inframe->length; @@ -2218,6 +2213,7 @@ static void *player_thread_func(void *arg) { debug(1, "audio thread joined"); pthread_join(rtp_control_thread, NULL); debug(1, "control thread joined"); + free_buffer(conn); debug(1, "Player thread exit"); return 0; } @@ -2437,7 +2433,6 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { BUFFER_FRAMES); init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels // must be after decoder init - init_buffer(); please_stop = 0; command_start(); #ifdef CONFIG_METADATA @@ -2479,7 +2474,6 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { send_ssnc_metadata('pend', NULL, 0, 1); #endif command_stop(); - free_buffer(); terminate_decoders(); int rc = pthread_cond_destroy(&flowcontrol); if (rc) diff --git a/player.h b/player.h index 8ffd153b..9564d0bd 100644 --- a/player.h +++ b/player.h @@ -19,6 +19,20 @@ #include "audio.h" +typedef uint16_t seq_t; + +typedef struct audio_buffer_entry { // decoded audio packets + int ready; + int64_t timestamp; + seq_t sequence_number; + signed short *data; + int length; // the length of the decoded data +} abuf_t; + +// default buffer size +// needs to be a power of 2 because of the way BUFIDX(seqno) works +#define BUFFER_FRAMES 512 + typedef struct { int encrypted; uint8_t aesiv[16], aeskey[16]; @@ -35,6 +49,7 @@ typedef struct { pthread_t thread; pthread_t player_thread; + abuf_t audio_buffer[BUFFER_FRAMES]; uint32_t please_stop; uint64_t packet_count; #ifdef HAVE_LIBMBEDTLS @@ -50,9 +65,6 @@ typedef struct { #endif } rtsp_conn_info; - -typedef uint16_t seq_t; - // wrapped number between two seq_t. int32_t seq_diff(seq_t a, seq_t b); From ea072ec2490ab1565004ca3bbc29e1abd5573151 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Wed, 8 Mar 2017 20:13:10 +0000 Subject: [PATCH 05/17] Move init and terminate decoder calls inside the player thread -- still using globals though --- player.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/player.c b/player.c index aa782931..bec24faa 100644 --- a/player.c +++ b/player.c @@ -1515,6 +1515,8 @@ static void *player_thread_func(void *arg) { break; } + init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels + // must be after decoder init init_buffer(conn); debug(1, "Output frame bytes is %d.", output_bytes_per_frame); @@ -2214,6 +2216,7 @@ static void *player_thread_func(void *arg) { pthread_join(rtp_control_thread, NULL); debug(1, "control thread joined"); free_buffer(conn); + terminate_decoders(); debug(1, "Player thread exit"); return 0; } @@ -2431,8 +2434,6 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { if (config.buffer_start_fill > BUFFER_FRAMES) die("specified buffer starting fill %d > buffer size %d", config.buffer_start_fill, BUFFER_FRAMES); - init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels - // must be after decoder init please_stop = 0; command_start(); #ifdef CONFIG_METADATA @@ -2474,7 +2475,6 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { send_ssnc_metadata('pend', NULL, 0, 1); #endif command_stop(); - terminate_decoders(); int rc = pthread_cond_destroy(&flowcontrol); if (rc) debug(1, "Error destroying condition variable."); From d90fd0df500d571f37bc9d4b3f14b13ef8896669 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 14:08:06 +0000 Subject: [PATCH 06/17] Change the order of initialisation back to waht it was before de-globalising the init_decoder, etc. --- player.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/player.c b/player.c index bec24faa..3b96f954 100644 --- a/player.c +++ b/player.c @@ -1473,6 +1473,12 @@ static void *player_thread_func(void *arg) { conn->please_stop = 0; conn->packet_count = 0; + init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels + // must be after decoder init + init_buffer(conn); + + debug(1, "Output frame bytes is %d.", output_bytes_per_frame); + if (conn->stream.encrypted) { #ifdef HAVE_LIBMBEDTLS memset(&conn->dctx, 0, sizeof(mbedtls_aes_context)); @@ -1515,12 +1521,6 @@ static void *player_thread_func(void *arg) { break; } - init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels - // must be after decoder init - init_buffer(conn); - - debug(1, "Output frame bytes is %d.", output_bytes_per_frame); - // create and start the timing, control and audio receiver threads pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread; pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn); From cae9337dc49331275adc98be9761db0933ec0ed4 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 14:26:28 +0000 Subject: [PATCH 07/17] De-globalise max_frames_per_packet,input_num_channels,input_bit_depth,input_rate --- player.c | 54 ++++++++++++++++++++++++++---------------------------- player.h | 1 + 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/player.c b/player.c index 3b96f954..455ad466 100644 --- a/player.c +++ b/player.c @@ -76,8 +76,6 @@ #include "apple_alac.h" #endif -static int input_rate, input_bit_depth, input_num_channels, max_frames_per_packet; - static uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 // or 1. @@ -367,7 +365,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co return reply; } -static int init_decoder(int32_t fmtp[12]) { +static int init_decoder(int32_t fmtp[12],rtsp_conn_info* conn) { // This is a guess, but the format of the fmtp looks identical to the format of an // ALACSpecificCOnfig @@ -448,22 +446,22 @@ static int init_decoder(int32_t fmtp[12]) { alac_file *alac; - max_frames_per_packet = fmtp[1]; // number of audio frames per packet. + conn->max_frames_per_packet = fmtp[1]; // number of audio frames per packet. - input_rate = fmtp[11]; - input_num_channels = fmtp[7]; - input_bit_depth = fmtp[3]; + conn->input_rate = fmtp[11]; + conn->input_num_channels = fmtp[7]; + conn->input_bit_depth = fmtp[3]; - input_bytes_per_frame = input_num_channels * ((input_bit_depth + 7) / 8); + input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8); - alac = alac_create(input_bit_depth, input_num_channels); + alac = alac_create(conn->input_bit_depth, conn->input_num_channels); if (!alac) return 1; decoder_info = alac; - alac->setinfo_max_samples_per_frame = max_frames_per_packet; + alac->setinfo_max_samples_per_frame = conn->max_frames_per_packet; alac->setinfo_7a = fmtp[2]; - alac->setinfo_sample_size = input_bit_depth; + alac->setinfo_sample_size = conn->input_bit_depth; alac->setinfo_rice_historymult = fmtp[4]; alac->setinfo_rice_initialhistory = fmtp[5]; alac->setinfo_rice_kmodifier = fmtp[6]; @@ -492,7 +490,7 @@ static void init_buffer(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) conn->audio_buffer[i].data = - malloc(input_bytes_per_frame * (max_frames_per_packet + max_frame_size_change)); + malloc(input_bytes_per_frame * (conn->max_frames_per_packet + max_frame_size_change)); ab_resync(conn); } @@ -580,7 +578,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // pthread_mutex_unlock(&ab_mutex); if (abuf) { - int datalen = max_frames_per_packet; + int datalen = conn->max_frames_per_packet; if (alac_decode(abuf->data, &datalen, data, len, conn) == 0) { abuf->ready = 1; abuf->length = datalen; @@ -998,7 +996,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { max_dac_delay, dac_delay); fs = 0; } - if ((exact_frame_gap <= fs) || (exact_frame_gap <= max_frames_per_packet * 2)) { + if ((exact_frame_gap <= fs) || (exact_frame_gap <= conn->max_frames_per_packet * 2)) { fs = exact_frame_gap; // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, // with %d packets, ab_read is %04x, ab_write is @@ -1105,7 +1103,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (wait) { uint64_t time_to_wait_for_wakeup_fp = - ((uint64_t)1 << 32) / input_rate; // this is time period of one frame + ((uint64_t)1 << 32) / conn->input_rate; // this is time period of one frame time_to_wait_for_wakeup_fp *= 4 * 352; // four full 352-frame packets time_to_wait_for_wakeup_fp /= 3; // four thirds of a packet time @@ -1473,7 +1471,7 @@ static void *player_thread_func(void *arg) { conn->please_stop = 0; conn->packet_count = 0; - init_decoder((int32_t *)&conn->stream.fmtp); // this sets up incoming rate, bit depth, channels + init_decoder((int32_t *)&conn->stream.fmtp,conn); // this sets up incoming rate, bit depth, channels // must be after decoder init init_buffer(conn); @@ -1496,11 +1494,11 @@ static void *player_thread_func(void *arg) { } timestamp_epoch = 0; // indicate that the next timestamp will be the first one. - maximum_timestamp_interval = input_rate * 60; // actually there shouldn't be more than about 13v + maximum_timestamp_interval = conn->input_rate * 60; // actually there shouldn't be more than about 13v // seconds of a gap between successive rtptimes, at // worst - output_sample_ratio = config.output_rate / input_rate; + output_sample_ratio = config.output_rate / conn->input_rate; debug(1, "Output sample ratio is %d.", output_sample_ratio); @@ -1532,7 +1530,7 @@ static void *player_thread_func(void *arg) { // check that there are enough buffers to accommodate the desired latency and the latency offset - int maximum_latency = config.latency + config.audio_backend_latency_offset * input_rate; + int maximum_latency = config.latency + config.audio_backend_latency_offset * conn->input_rate; if ((maximum_latency + (352 - 1)) / 352 + 10 > BUFFER_FRAMES) die("Not enough buffers available for a total latency of %d frames. A maximum of %d 352-frame " "packets may be accommodated.", @@ -1599,7 +1597,7 @@ static void *player_thread_func(void *arg) { debug(1, "Output bit depth is %d.", output_bit_depth); - if (input_bit_depth > output_bit_depth) { + if (conn->input_bit_depth > output_bit_depth) { debug(1, "Dithering will be enabled because the input bit depth is greater than the output bit " "depth"); } @@ -1616,13 +1614,13 @@ static void *player_thread_func(void *arg) { // debug(1,"Define tbuf of length // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change)); tbuf = malloc(sizeof(int32_t) * 2 * - (max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); if (tbuf == NULL) debug(1, "Failed to allocate memory for the transition buffer."); sbuf = 0; if (config.packet_stuffing == ST_soxr) { // needed for stuffing sbuf = malloc(sizeof(int32_t) * 2 * - (max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); if (sbuf == NULL) debug(1, "Failed to allocate memory for the transition buffer."); } @@ -1634,13 +1632,13 @@ static void *player_thread_func(void *arg) { // The size of these dependents on the number of frames, the size of each frame and the maximum // size change outbuf = malloc(output_bytes_per_frame * - (max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); if (outbuf == NULL) debug(1, "Failed to allocate memory for an output buffer."); - silence = malloc(output_bytes_per_frame * max_frames_per_packet * output_sample_ratio); + silence = malloc(output_bytes_per_frame * conn->max_frames_per_packet * output_sample_ratio); if (silence == NULL) debug(1, "Failed to allocate memory for a silence buffer."); - memset(silence, 0, output_bytes_per_frame * max_frames_per_packet * output_sample_ratio); + memset(silence, 0, output_bytes_per_frame * conn->max_frames_per_packet * output_sample_ratio); late_packet_message_sent = 0; first_packet_timestamp = 0; missing_packets = late_packets = too_late_packets = resend_requests = 0; @@ -1698,17 +1696,17 @@ static void *player_thread_func(void *arg) { // debug(1,"Player has a supplied silent frame."); last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder - config.output->play(silence, max_frames_per_packet * output_sample_ratio); + config.output->play(silence, conn->max_frames_per_packet * output_sample_ratio); } else { int enable_dither = 0; - if ((fix_volume != 0x10000) || (input_bit_depth > output_bit_depth)) + if ((fix_volume != 0x10000) || (conn->input_bit_depth > output_bit_depth)) enable_dither = 1; // here, let's transform the frame of data, if necessary if (tbuf != NULL) { // this will be null if no changes are needed - switch (input_bit_depth) { + switch (conn->input_bit_depth) { case 16: { int i, j; int16_t ls, rs; diff --git a/player.h b/player.h index 9564d0bd..81922f35 100644 --- a/player.h +++ b/player.h @@ -50,6 +50,7 @@ typedef struct { pthread_t player_thread; abuf_t audio_buffer[BUFFER_FRAMES]; + int max_frames_per_packet,input_num_channels,input_bit_depth,input_rate; uint32_t please_stop; uint64_t packet_count; #ifdef HAVE_LIBMBEDTLS From 600cebacd4ae2d8fdffa8c5499067dff517c6901 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 14:43:41 +0000 Subject: [PATCH 08/17] De-globalise previous_random_number --- player.c | 218 ++++++++++--------------------------------------------- player.h | 1 + 2 files changed, 39 insertions(+), 180 deletions(-) diff --git a/player.c b/player.c index 455ad466..7ef8b0d0 100644 --- a/player.c +++ b/player.c @@ -84,7 +84,6 @@ static int input_bytes_per_frame = 4; static int output_bytes_per_frame; static int output_sample_ratio; static int output_rate; -static int64_t previous_random_number = 0; // The maximum frame size change there can be is +/- 1; static int max_frame_size_change; @@ -612,7 +611,7 @@ int32_t rand_in_range(int32_t exclusive_range_limit) { } static inline void process_sample(int32_t sample, char **outp, enum sps_format_t format, int volume, - int dither) { + int dither,rtsp_conn_info *conn) { int64_t hyper_sample = sample; int result; int64_t hyper_volume = (int64_t)volume << 16; @@ -659,8 +658,8 @@ static inline void process_sample(int32_t sample, char **outp, enum sps_format_t // calculating them on the fly. Should be easier on low-powered // processors - int64_t tpdf = (r & dither_mask) - (previous_random_number & dither_mask); - previous_random_number = r; + int64_t tpdf = (r & dither_mask) - (conn->previous_random_number & dither_mask); + conn->previous_random_number = r; // add dither, allowing for clipping if (tpdf >= 0) { if (INT64_MAX - tpdf >= hyper_sample) @@ -1194,7 +1193,7 @@ static inline int32_t mean_32(int32_t a, int32_t b) { // stuff: 1 means add 1; 0 means do nothing; -1 means remove 1 static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l_output_format, - char *outptr, int stuff, int dither) { + char *outptr, int stuff, int dither,rtsp_conn_info *conn) { int tstuff = stuff; char *l_outptr = outptr; if ((stuff > 1) || (stuff < -1) || (length < 100)) { @@ -1211,15 +1210,15 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l pthread_mutex_lock(&vol_mutex); for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither); - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither); + process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); }; if (tstuff) { if (tstuff == 1) { // debug(3, "+++++++++"); // interpolate one sample - process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, fix_volume, dither); - process_sample(mean_32(inptr[-1], inptr[1]), &l_outptr, l_output_format, fix_volume, dither); + process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(mean_32(inptr[-1], inptr[1]), &l_outptr, l_output_format, fix_volume, dither,conn); } else if (stuff == -1) { // debug(3, "---------"); inptr++; @@ -1233,8 +1232,8 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l remainder = remainder + tstuff; // don't run over the correct end of the output buffer for (i = stuffsamp; i < remainder; i++) { - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither); - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither); + process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); } } pthread_mutex_unlock(&vol_mutex); @@ -1242,53 +1241,6 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l return length + tstuff; } -static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff) { - int tstuff = stuff; - if ((stuff > 1) || (stuff < -1) || (length < 100)) { - // debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100."); - tstuff = 0; // if any of these conditions hold, don't stuff anything/ - } - int i; - int stuffsamp = length; - if (tstuff) - // stuffsamp = rand() % (length - 1); - stuffsamp = - (rand() % (length - 2)) + 1; // ensure there's always a sample before and after the item - - pthread_mutex_lock(&vol_mutex); - for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing - *outptr++ = dithered_vol(*inptr++); - *outptr++ = dithered_vol(*inptr++); - }; - if (tstuff) { - if (tstuff == 1) { - // debug(3, "+++++++++"); - // interpolate one sample - //*outptr++ = dithered_vol(((long)inptr[-2] + (long)inptr[0]) >> 1); - //*outptr++ = dithered_vol(((long)inptr[-1] + (long)inptr[1]) >> 1); - *outptr++ = dithered_vol(shortmean(inptr[-2], inptr[0])); - *outptr++ = dithered_vol(shortmean(inptr[-1], inptr[1])); - } else if (stuff == -1) { - // debug(3, "---------"); - inptr++; - inptr++; - } - - // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the - // rest. - int remainder = length; - if (tstuff < 0) - remainder = remainder + tstuff; // don't run over the correct end of the output buffer - - for (i = stuffsamp; i < remainder; i++) { - *outptr++ = dithered_vol(*inptr++); - *outptr++ = dithered_vol(*inptr++); - } - } - pthread_mutex_unlock(&vol_mutex); - - return length + tstuff; -} #ifdef HAVE_LIBSOXR // this takes an array of signed 32-bit integers and @@ -1302,7 +1254,7 @@ static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length, enum sps_format_t l_output_format, char *outptr, int stuff, - int dither) { + int dither,rtsp_conn_info *conn) { if (scratchBuffer == NULL) { die("soxr scratchBuffer not initialised."); } @@ -1359,8 +1311,8 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng ip = scratchBuffer; char *l_outptr = outptr; for (i = 0; i < length + tstuff; i++) { - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither); - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither); + process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); //*op = dithered_vol(*op); // op++; //*op = dithered_vol(*op); @@ -1375,89 +1327,14 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng int i; for (i = 0; i < length; i++) { - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither); - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither); + process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); //*op++ = dithered_vol(*ip++); //*op++ = dithered_vol(*ip++); }; } return length + tstuff; } -// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1 -static int stuff_buffer_soxr(short *inptr, int length, short *outptr, int stuff) { - int tstuff = stuff; - if ((stuff > 1) || (stuff < -1) || (length < 100)) { - // debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100."); - tstuff = 0; // if any of these conditions hold, don't stuff anything/ - } - int i; - short *ip, *op; - ip = inptr; - op = outptr; - - if (tstuff) { - // debug(1,"Stuff %d.",stuff); - soxr_io_spec_t io_spec; - io_spec.itype = SOXR_INT16_I; - io_spec.otype = SOXR_INT16_I; - io_spec.scale = 1.0; // this seems to crash if not = 1.0 - io_spec.e = NULL; - io_spec.flags = 0; - - size_t odone; - - soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, /* Rates and # of chans. */ - inptr, length, NULL, /* Input. */ - outptr, length + tstuff, &odone, /* Output. */ - &io_spec, /* Input, output and transfer spec. */ - NULL, NULL); /* Default configuration.*/ - - if (error) - die("soxr error: %s\n", "error: %s\n", soxr_strerror(error)); - - if (odone > length + 1) - die("odone = %d!\n", odone); - - const int gpm = 5; - - // keep the first (dpm) samples, to mitigate the Gibbs phenomenon - for (i = 0; i < gpm; i++) { - *op++ = *ip++; - *op++ = *ip++; - } - - // keep the last (dpm) samples, to mitigate the Gibbs phenomenon - op = outptr + (length + tstuff - gpm) * sizeof(short); - ip = inptr + (length - gpm) * sizeof(short); - for (i = 0; i < gpm; i++) { - *op++ = *ip++; - *op++ = *ip++; - } - - // finally, adjust the volume, if necessary - if (fix_volume != 65536.0) { - // pthread_mutex_lock(&vol_mutex); - op = outptr; - for (i = 0; i < length + tstuff; i++) { - *op = dithered_vol(*op); - op++; - *op = dithered_vol(*op); - op++; - }; - // pthread_mutex_unlock(&vol_mutex); - } - - } else { // the whole frame, if no stuffing - - // pthread_mutex_lock(&vol_mutex); - for (i = 0; i < length; i++) { - *op++ = dithered_vol(*ip++); - *op++ = dithered_vol(*ip++); - }; - // pthread_mutex_unlock(&vol_mutex); - } - return length + tstuff; -} #endif typedef struct stats { // statistics for running averages @@ -1470,6 +1347,8 @@ static void *player_thread_func(void *arg) { conn->please_stop = 0; conn->packet_count = 0; + conn->previous_random_number = 0; + init_decoder((int32_t *)&conn->stream.fmtp,conn); // this sets up incoming rate, bit depth, channels // must be after decoder init @@ -1605,28 +1484,22 @@ static void *player_thread_func(void *arg) { debug(1, "Dithering will be enabled the output volume is being altered in software"); } - // if we are changing any of the parameters of the input, like sample rate or sample depth, then - // we - // need an intermediate "transition" buffer - - if (1) { - // if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) { - // debug(1,"Define tbuf of length - // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change)); - tbuf = malloc(sizeof(int32_t) * 2 * - (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); - if (tbuf == NULL) - debug(1, "Failed to allocate memory for the transition buffer."); - sbuf = 0; - if (config.packet_stuffing == ST_soxr) { // needed for stuffing - sbuf = malloc(sizeof(int32_t) * 2 * - (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); - if (sbuf == NULL) - debug(1, "Failed to allocate memory for the transition buffer."); - } - } else { - tbuf = 0; - } + // we need an intermediate "transition" buffer + + // if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) { + // debug(1,"Define tbuf of length + // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change)); + tbuf = malloc(sizeof(int32_t) * 2 * + (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + if (tbuf == NULL) + debug(1, "Failed to allocate memory for the transition buffer."); + sbuf = 0; + if (config.packet_stuffing == ST_soxr) { // needed for stuffing + sbuf = malloc(sizeof(int32_t) * 2 * + (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + if (sbuf == NULL) + debug(1, "Failed to allocate memory for the transition buffer."); + } // We might need an output buffer and a buffer of silence. // The size of these dependents on the number of frames, the size of each frame and the maximum @@ -1942,34 +1815,22 @@ static void *player_thread_func(void *arg) { switch (config.packet_stuffing) { case ST_basic: // if (amount_to_stuff) debug(1,"Basic stuff..."); - if (tbuf) { play_samples = stuff_buffer_basic_32((int32_t *)tbuf, inbuflength, config.output_format, - outbuf, amount_to_stuff, enable_dither); - } else - play_samples = - stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff); + outbuf, amount_to_stuff, enable_dither, conn); break; case ST_soxr: // if (amount_to_stuff) debug(1,"Soxr stuff..."); - if (tbuf) play_samples = stuff_buffer_soxr_32((int32_t *)tbuf, (int32_t *)sbuf, inbuflength, config.output_format, outbuf, amount_to_stuff, - enable_dither); - else - play_samples = - stuff_buffer_soxr(inbuf, inbuflength, (short *)outbuf, amount_to_stuff); + enable_dither,conn); break; } #else // if (amount_to_stuff) debug(1,"Standard stuff..."); - if (tbuf) play_samples = stuff_buffer_basic_32((int32_t *)tbuf, inbuflength, config.output_format, outbuf, - amount_to_stuff, enable_dither); - else - play_samples = - stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff); + amount_to_stuff, enable_dither,conn); #endif /* @@ -2036,12 +1897,9 @@ static void *player_thread_func(void *arg) { config.output->play(inbuf, inbuflength); } else { - if (tbuf) + play_samples = stuff_buffer_basic_32( - (int32_t *)tbuf, inbuflength, config.output_format, outbuf, 0, enable_dither); - else - play_samples = stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, - 0); // no stuffing, but volume adjustment + (int32_t *)tbuf, inbuflength, config.output_format, outbuf, 0, enable_dither,conn); if (outbuf == NULL) debug(1, "NULL outbuf to play -- skipping it."); diff --git a/player.h b/player.h index 81922f35..b257ac30 100644 --- a/player.h +++ b/player.h @@ -51,6 +51,7 @@ typedef struct { abuf_t audio_buffer[BUFFER_FRAMES]; int max_frames_per_packet,input_num_channels,input_bit_depth,input_rate; + int64_t previous_random_number; uint32_t please_stop; uint64_t packet_count; #ifdef HAVE_LIBMBEDTLS From 05305e15816c15f3474e5387dcf70e4b035ababc Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 16:10:39 +0000 Subject: [PATCH 09/17] De-globalise input_bytes_per_frame,output_bytes_per_frame,output_sample_ratio,max_frame_size_change,decoder_info,shutdown_requested,connection_state_to_output,player_thread_please_stop --- player.c | 182 ++++++++++++++++++------------------------------------- player.h | 8 +++ rtp.c | 2 +- 3 files changed, 68 insertions(+), 124 deletions(-) diff --git a/player.c b/player.c index 7ef8b0d0..6a92585d 100644 --- a/player.c +++ b/player.c @@ -80,27 +80,13 @@ static uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 // or 1. -static int input_bytes_per_frame = 4; -static int output_bytes_per_frame; -static int output_sample_ratio; -static int output_rate; - -// The maximum frame size change there can be is +/- 1; -static int max_frame_size_change; // #define FRAME_BYTES(max_frames_per_packet) (4 * max_frames_per_packet) // maximal resampling shift - conservative //#define OUTFRAME_BYTES(max_frames_per_packet) (4 * (max_frames_per_packet + 3)) // static pthread_t player_thread = NULL; -static int please_stop; - -static int - connection_state_to_output; // if true, then play incoming stuff; if false drop everything - -static alac_file *decoder_info; // debug variables -static int late_packet_message_sent; static int32_t last_seqno_read; static int decoder_in_use = 0; @@ -126,7 +112,6 @@ static int64_t first_packet_timestamp = 0; static int flush_requested = 0; static int64_t flush_rtp_timestamp; static uint64_t time_of_last_audio_packet; -static int shutdown_requested; // mutexes and condition variables static pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -294,7 +279,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co unsigned char packetp[MAX_PACKET]; assert(len <= MAX_PACKET); int reply = 0; // everything okay - int outsize = input_bytes_per_frame * (*destlen); // the size the output should be, in bytes + int outsize = conn->input_bytes_per_frame * (*destlen); // the size the output should be, in bytes int toutsize = outsize; if (conn->stream.encrypted) { @@ -326,7 +311,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co debug(1, "Hammerton Decoder used on encrypted audio."); decoder_in_use = 1 << decoder_hammerton; } - alac_decode_frame(decoder_info, packet, (unsigned char *)dest, &outsize); + alac_decode_frame(conn->decoder_info, packet, (unsigned char *)dest, &outsize); } } else { // not encrypted @@ -345,7 +330,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co debug(1, "Hammerton Decoder used on unencrypted audio."); decoder_in_use = 1 << decoder_hammerton; } - alac_decode_frame(decoder_info, buf, dest, &outsize); + alac_decode_frame(conn->decoder_info, buf, dest, &outsize); } } @@ -356,11 +341,11 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co reply = -1; // output packet is the wrong size } - *destlen = outsize / input_bytes_per_frame; - if ((outsize % input_bytes_per_frame) != 0) + *destlen = outsize / conn->input_bytes_per_frame; + if ((outsize % conn->input_bytes_per_frame) != 0) debug(1, "Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) " "and the audio frame size (%d).", - *destlen, outsize, input_bytes_per_frame); + *destlen, outsize, conn->input_bytes_per_frame); return reply; } @@ -451,12 +436,12 @@ static int init_decoder(int32_t fmtp[12],rtsp_conn_info* conn) { conn->input_num_channels = fmtp[7]; conn->input_bit_depth = fmtp[3]; - input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8); + conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8); alac = alac_create(conn->input_bit_depth, conn->input_num_channels); if (!alac) return 1; - decoder_info = alac; + conn->decoder_info = alac; alac->setinfo_max_samples_per_frame = conn->max_frames_per_packet; alac->setinfo_7a = fmtp[2]; @@ -478,8 +463,8 @@ static int init_decoder(int32_t fmtp[12],rtsp_conn_info* conn) { return 0; } -static void terminate_decoders(void) { - alac_free(decoder_info); +static void terminate_decoders(rtsp_conn_info* conn) { + alac_free(conn->decoder_info); #ifdef HAVE_APPLE_ALAC apple_alac_terminate(); #endif @@ -489,7 +474,7 @@ static void init_buffer(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) conn->audio_buffer[i].data = - malloc(input_bytes_per_frame * (conn->max_frames_per_packet + max_frame_size_change)); + malloc(conn->input_bytes_per_frame * (conn->max_frames_per_packet + conn->max_frame_size_change)); ab_resync(conn); } @@ -503,7 +488,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // all timestamps are done at the output rate - int64_t ltimestamp = timestamp * output_sample_ratio; + int64_t ltimestamp = timestamp * conn->output_sample_ratio; // ignore a request to flush that has been made before the first packet... if (conn->packet_count == 0) { @@ -516,7 +501,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r pthread_mutex_lock(&ab_mutex); conn->packet_count++; time_of_last_audio_packet = get_absolute_time_in_fp(); - if (connection_state_to_output) { // if we are supposed to be processing these packets + if (conn->connection_state_to_output) { // if we are supposed to be processing these packets // if (flush_rtp_timestamp != 0) // debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp); @@ -566,13 +551,6 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r abuf = conn->audio_buffer + BUFIDX(seqno); } else { // too late. too_late_packets++; - /* - if (!late_packet_message_sent) { - debug(1, "too-late packet received: %u; ab_read: %u; ab_write: %u.", seqno, ab_read, - ab_write); - late_packet_message_sent=1; - } - */ } // pthread_mutex_unlock(&ab_mutex); @@ -730,41 +708,6 @@ static inline void process_sample(int32_t sample, char **outp, enum sps_format_t *outp += result; } -static inline short dithered_vol(short sample) { - long out; - - out = (long)sample * fix_volume; - if (fix_volume < 0x10000) { - - // add a TPDF dither -- see - // http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf - // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25 - - // I think, for a 32 --> 16 bits, the range of - // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from - // -32768 to +32767 - - // See the original paper at - // http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf - // by Lipshitz, Wannamaker and Vanderkooy, 1992. - - long tpdf = rand_in_range(65536 + 1) - rand_in_range(65536 + 1); - // Check there's no clipping -- if there is, - if (tpdf >= 0) { - if (LONG_MAX - tpdf >= out) - out += tpdf; - else - out = LONG_MAX; - } else { - if (LONG_MIN - tpdf <= out) - out += tpdf; - else - out = LONG_MIN; - } - } - return out >> 16; -} - // get the next frame, when available. return 0 if underrun/stream reset. static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { int16_t buf_fill; @@ -787,22 +730,22 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // config.timeout of zero means don't check..., but iTunes may be confused by a long gap // followed by a resumption... - if ((time_of_last_audio_packet != 0) && (shutdown_requested == 0) && + if ((time_of_last_audio_packet != 0) && (conn->shutdown_requested == 0) && (config.dont_check_timeout == 0)) { uint64_t ct = config.timeout; // go from int to 64-bit int if ((local_time_now > time_of_last_audio_packet) && (local_time_now - time_of_last_audio_packet >= ct << 32)) { debug(1, "As Yeats almost said, \"Too long a silence / can make a stone of the heart\""); rtsp_request_shutdown_stream(); - shutdown_requested = 1; + conn->shutdown_requested = 1; } } int rco = get_requested_connection_state_to_output(); - if (connection_state_to_output != rco) { - connection_state_to_output = rco; + if (conn->connection_state_to_output != rco) { + conn->connection_state_to_output = rco; // change happening - if (connection_state_to_output == 0) { // going off + if (conn->connection_state_to_output == 0) { // going off pthread_mutex_lock(&flush_mutex); flush_requested = 1; pthread_mutex_unlock(&flush_mutex); @@ -870,7 +813,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { uint64_t reference_timestamp_time, remote_reference_timestamp_time; get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); - reference_timestamp *= output_sample_ratio; + reference_timestamp *= conn->output_sample_ratio; if (first_packet_timestamp == 0) { // if this is the very first packet // debug(1,"First frame seen, time %u, with %d // frames...",curframe->timestamp,seq_diff(ab_read, ab_write)); @@ -903,10 +846,10 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // if would be in sync. To do this, we would give it a latency offset of -100 ms, i.e. // -4410 frames. - debug(1, "Output sample ratio is %d", output_sample_ratio); + debug(1, "Output sample ratio is %d", conn->output_sample_ratio); int64_t delta = (first_packet_timestamp - reference_timestamp) + - config.latency * output_sample_ratio + + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate; if (delta >= 0) { @@ -924,7 +867,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { debug( 1, "First packet is late! It should have played before now. Flushing 0.1 seconds"); - player_flush(first_packet_timestamp + 4410 * output_sample_ratio); + player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio); } } } @@ -932,7 +875,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (first_packet_time_to_play != 0) { // recalculate first_packet_time_to_play -- the latency might change int64_t delta = (first_packet_timestamp - reference_timestamp) + - config.latency * output_sample_ratio + + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate; if (delta >= 0) { @@ -1011,11 +954,11 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // ouotputting frames for a while -- it could get loaded up but not start responding // for many milliseconds. if (fs != 0) { - silence = malloc(output_bytes_per_frame * fs); + silence = malloc(conn->output_bytes_per_frame * fs); if (silence == NULL) debug(1, "Failed to allocate %d byte silence buffer.", fs); else { - memset(silence, 0, output_bytes_per_frame * fs); + memset(silence, 0, conn->output_bytes_per_frame * fs); // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, // with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); config.output->play(silence, fs); @@ -1031,7 +974,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { uint64_t reference_timestamp_time; // don't need this... get_reference_timestamp_stuff(&play_segment_reference_frame, &reference_timestamp_time, &play_segment_reference_frame_remote_time); - play_segment_reference_frame *= output_sample_ratio; + play_segment_reference_frame *= conn->output_sample_ratio; #ifdef CONFIG_METADATA send_ssnc_metadata('prsm', NULL, 0, 0); // "resume", but don't wait if the queue is locked @@ -1061,12 +1004,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { uint64_t reference_timestamp_time, remote_reference_timestamp_time; get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); // all types okay - reference_timestamp *= output_sample_ratio; + reference_timestamp *= conn->output_sample_ratio; if (reference_timestamp) { // if we have a reference time int64_t packet_timestamp = curframe->timestamp; // types okay int64_t delta = packet_timestamp - reference_timestamp; int64_t offset = - config.latency * output_sample_ratio + + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate - config.audio_backend_buffer_desired_length * config.output_rate; // all arguments are int32_t, so expression promotion okay @@ -1098,7 +1041,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } do_wait = 1; } - wait = (ab_buffering || (do_wait != 0) || (!ab_synced)) && (!please_stop); + wait = (ab_buffering || (do_wait != 0) || (!ab_synced)) && (!conn->player_thread_please_stop); if (wait) { uint64_t time_to_wait_for_wakeup_fp = @@ -1131,7 +1074,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } } while (wait); - if (please_stop) { + if (conn->player_thread_please_stop) { pthread_mutex_unlock(&ab_mutex); return 0; } @@ -1313,10 +1256,6 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng for (i = 0; i < length + tstuff; i++) { process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); - //*op = dithered_vol(*op); - // op++; - //*op = dithered_vol(*op); - // op++; }; } else { // the whole frame, if no stuffing @@ -1329,8 +1268,6 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng for (i = 0; i < length; i++) { process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); - //*op++ = dithered_vol(*ip++); - //*op++ = dithered_vol(*ip++); }; } return length + tstuff; @@ -1348,13 +1285,14 @@ static void *player_thread_func(void *arg) { conn->please_stop = 0; conn->packet_count = 0; conn->previous_random_number = 0; - + conn->input_bytes_per_frame = 4; + conn->player_thread_please_stop = 0; init_decoder((int32_t *)&conn->stream.fmtp,conn); // this sets up incoming rate, bit depth, channels // must be after decoder init init_buffer(conn); - debug(1, "Output frame bytes is %d.", output_bytes_per_frame); + debug(1, "Output frame bytes is %d.", conn->output_bytes_per_frame); if (conn->stream.encrypted) { #ifdef HAVE_LIBMBEDTLS @@ -1377,24 +1315,24 @@ static void *player_thread_func(void *arg) { // seconds of a gap between successive rtptimes, at // worst - output_sample_ratio = config.output_rate / conn->input_rate; + conn->output_sample_ratio = config.output_rate / conn->input_rate; - debug(1, "Output sample ratio is %d.", output_sample_ratio); + debug(1, "Output sample ratio is %d.", conn->output_sample_ratio); - max_frame_size_change = 1 * output_sample_ratio; // we add or subtract one frame at the nominal + conn->max_frame_size_change = 1 * conn->output_sample_ratio; // we add or subtract one frame at the nominal // rate, multiply it by the frame ratio. - output_bytes_per_frame = 4; + conn->output_bytes_per_frame = 4; switch (config.output_format) { case SPS_FORMAT_S24_3LE: case SPS_FORMAT_S24_3BE: - output_bytes_per_frame = 6; + conn->output_bytes_per_frame = 6; break; case SPS_FORMAT_S24: - output_bytes_per_frame = 8; + conn->output_bytes_per_frame = 8; break; case SPS_FORMAT_S32: - output_bytes_per_frame = 8; + conn->output_bytes_per_frame = 8; break; } @@ -1414,7 +1352,7 @@ static void *player_thread_func(void *arg) { die("Not enough buffers available for a total latency of %d frames. A maximum of %d 352-frame " "packets may be accommodated.", maximum_latency, BUFFER_FRAMES); - connection_state_to_output = get_requested_connection_state_to_output(); + conn->connection_state_to_output = get_requested_connection_state_to_output(); // this is about half a minute #define trend_interval 3758 stats_t statistics[trend_interval]; @@ -1435,7 +1373,7 @@ static void *player_thread_func(void *arg) { int64_t current_delay; int play_number = 0; time_of_last_audio_packet = 0; - shutdown_requested = 0; + conn->shutdown_requested = 0; number_of_statistics = oldest_statistic = newest_statistic = 0; tsum_of_sync_errors = tsum_of_corrections = tsum_of_insertions_and_deletions = tsum_of_drifts = 0; @@ -1490,13 +1428,13 @@ static void *player_thread_func(void *arg) { // debug(1,"Define tbuf of length // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change)); tbuf = malloc(sizeof(int32_t) * 2 * - (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change)); if (tbuf == NULL) debug(1, "Failed to allocate memory for the transition buffer."); sbuf = 0; if (config.packet_stuffing == ST_soxr) { // needed for stuffing sbuf = malloc(sizeof(int32_t) * 2 * - (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change)); if (sbuf == NULL) debug(1, "Failed to allocate memory for the transition buffer."); } @@ -1504,15 +1442,14 @@ static void *player_thread_func(void *arg) { // We might need an output buffer and a buffer of silence. // The size of these dependents on the number of frames, the size of each frame and the maximum // size change - outbuf = malloc(output_bytes_per_frame * - (conn->max_frames_per_packet * output_sample_ratio + max_frame_size_change)); + outbuf = malloc(conn->output_bytes_per_frame * + (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change)); if (outbuf == NULL) debug(1, "Failed to allocate memory for an output buffer."); - silence = malloc(output_bytes_per_frame * conn->max_frames_per_packet * output_sample_ratio); + silence = malloc(conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio); if (silence == NULL) debug(1, "Failed to allocate memory for a silence buffer."); - memset(silence, 0, output_bytes_per_frame * conn->max_frames_per_packet * output_sample_ratio); - late_packet_message_sent = 0; + memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio); first_packet_timestamp = 0; missing_packets = late_packets = too_late_packets = resend_requests = 0; flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used @@ -1558,7 +1495,7 @@ static void *player_thread_func(void *arg) { } uint64_t tens_of_seconds = 0; - while (!please_stop) { + while (!conn->player_thread_please_stop) { abuf_t *inframe = buffer_get_frame(conn); if (inframe) { inbuf = inframe->data; @@ -1569,7 +1506,7 @@ static void *player_thread_func(void *arg) { // debug(1,"Player has a supplied silent frame."); last_seqno_read = (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder - config.output->play(silence, conn->max_frames_per_packet * output_sample_ratio); + config.output->play(silence, conn->max_frames_per_packet * conn->output_sample_ratio); } else { int enable_dither = 0; @@ -1620,7 +1557,7 @@ static void *player_thread_func(void *arg) { // here, replicate the samples if you're upsampling - for (j = 0; j < output_sample_ratio; j++) { + for (j = 0; j < conn->output_sample_ratio; j++) { // raise the 16-bit sample to 32 bits. int32_t t = ls << 16; *outpl++ = t; @@ -1656,7 +1593,7 @@ static void *player_thread_func(void *arg) { } // inbuf = tbuf; - inbuflength *= output_sample_ratio; + inbuflength *= conn->output_sample_ratio; } // We have a frame of data. We need to see if we want to add or remove a frame from it to @@ -1672,7 +1609,7 @@ static void *player_thread_func(void *arg) { uint64_t reference_timestamp_time, remote_reference_timestamp_time; get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); // types okay - reference_timestamp *= output_sample_ratio; + reference_timestamp *= conn->output_sample_ratio; int64_t rt, nt; rt = reference_timestamp; // uint32_t to int64_t nt = inframe->timestamp; // uint32_t to int64_t @@ -1766,7 +1703,7 @@ static void *player_thread_func(void *arg) { // This is the timing error for the next audio frame in the DAC. sync_error = delay - - config.latency * output_sample_ratio; // int64_t from int64_t - int32_t, so okay + config.latency * conn->output_sample_ratio; // int64_t from int64_t - int32_t, so okay // if (llabs(sync_error)>352*512) // debug(1,"Very large sync error: %lld",sync_error); @@ -1865,7 +1802,7 @@ static void *player_thread_func(void *arg) { if (abs_sync_error < 0) abs_sync_error = -abs_sync_error; - if ((config.no_sync == 0) && (inframe->timestamp != 0) && (!please_stop) && + if ((config.no_sync == 0) && (inframe->timestamp != 0) && (!conn->player_thread_please_stop) && (config.resyncthreshold > 0.0) && (abs_sync_error > config.resyncthreshold * config.output_rate)) { sync_error_out_of_bounds++; @@ -1992,9 +1929,9 @@ static void *player_thread_func(void *arg) { "%*d", /* max buffer occupancy */ 10, 1000 * moving_average_sync_error / config.output_rate, 10, - moving_average_correction * 1000000 / (352 * output_sample_ratio), 10, + moving_average_correction * 1000000 / (352 * conn->output_sample_ratio), 10, moving_average_insertions_plus_deletions * 1000000 / - (352 * output_sample_ratio), + (352 * conn->output_sample_ratio), 12, play_number, 7, missing_packets, 7, late_packets, 7, too_late_packets, 7, resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); @@ -2072,7 +2009,7 @@ static void *player_thread_func(void *arg) { pthread_join(rtp_control_thread, NULL); debug(1, "control thread joined"); free_buffer(conn); - terminate_decoders(); + terminate_decoders(conn); debug(1, "Player thread exit"); return 0; } @@ -2290,7 +2227,6 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { if (config.buffer_start_fill > BUFFER_FRAMES) die("specified buffer starting fill %d > buffer size %d", config.buffer_start_fill, BUFFER_FRAMES); - please_stop = 0; command_start(); #ifdef CONFIG_METADATA send_ssnc_metadata('pbeg', NULL, 0, 1); @@ -2324,7 +2260,7 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { // if (*thread==NULL) // debug(1,"Trying to stop a non-existent player thread"); // else { - please_stop = 1; + conn->player_thread_please_stop = 1; pthread_cond_signal(&flowcontrol); // tell it to give up pthread_join(*player_thread, NULL); #ifdef CONFIG_METADATA diff --git a/player.h b/player.h index b257ac30..fee8d5a0 100644 --- a/player.h +++ b/player.h @@ -18,6 +18,7 @@ #endif #include "audio.h" +#include "alac.h" typedef uint16_t seq_t; @@ -51,9 +52,16 @@ typedef struct { abuf_t audio_buffer[BUFFER_FRAMES]; int max_frames_per_packet,input_num_channels,input_bit_depth,input_rate; + int input_bytes_per_frame,output_bytes_per_frame,output_sample_ratio; + int max_frame_size_change; int64_t previous_random_number; + alac_file *decoder_info; uint32_t please_stop; uint64_t packet_count; + int shutdown_requested; + int connection_state_to_output; + int player_thread_please_stop; + #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; #endif diff --git a/rtp.c b/rtp.c index 4f17e6e0..04f72b2b 100644 --- a/rtp.c +++ b/rtp.c @@ -129,7 +129,7 @@ void *rtp_audio_receiver(void *arg) { stat_mean += stat_delta / stat_n; stat_M2 += stat_delta * (time_interval_us - stat_mean); if (stat_n % 2500 == 0) { - debug(2, "Packet reception interval stats: mean, standard deviation and max for the last " + debug(3, "Packet reception interval stats: mean, standard deviation and max for the last " "2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.", stat_mean, sqrtf(stat_M2 / (stat_n - 1)), longest_packet_time_interval_us); stat_n = 0; From c87414237ff02b917e703ca13028e1334643fef9 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 16:28:26 +0000 Subject: [PATCH 10/17] de-globalise missing_packets, late_packets, too_late_packets, resend_requests, decoder_in_use, last_seqno_read --- player.c | 43 ++++++++++++++++++++----------------------- player.h | 5 +++++ 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/player.c b/player.c index 6a92585d..1d33d6d9 100644 --- a/player.c +++ b/player.c @@ -88,7 +88,6 @@ static uint32_t timestamp_epoch, last_timestamp, // debug variables static int32_t last_seqno_read; -static int decoder_in_use = 0; // interthread variables static int fix_volume = 0x10000; @@ -120,11 +119,6 @@ static pthread_cond_t flowcontrol; static int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds -static audio_parameters audio_information; - -// stats -static uint64_t missing_packets, late_packets, too_late_packets, resend_requests; - // make timestamps and seqnos definitely monotonic // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 @@ -298,18 +292,18 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co memcpy(packet + aeslen, buf + aeslen, len - aeslen); #ifdef HAVE_APPLE_ALAC if (config.use_apple_decoder) { - if (decoder_in_use != 1 << decoder_apple_alac) { + if (conn->decoder_in_use != 1 << decoder_apple_alac) { debug(1, "Apple ALAC Decoder used on encrypted audio."); - decoder_in_use = 1 << decoder_apple_alac; + conn->decoder_in_use = 1 << decoder_apple_alac; } apple_alac_decode_frame(packet, len, (unsigned char *)dest, &outsize); outsize = outsize * 4; // bring the size to bytes } else #endif { - if (decoder_in_use != 1 << decoder_hammerton) { + if (conn->decoder_in_use != 1 << decoder_hammerton) { debug(1, "Hammerton Decoder used on encrypted audio."); - decoder_in_use = 1 << decoder_hammerton; + conn->decoder_in_use = 1 << decoder_hammerton; } alac_decode_frame(conn->decoder_info, packet, (unsigned char *)dest, &outsize); } @@ -317,18 +311,18 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co // not encrypted #ifdef HAVE_APPLE_ALAC if (config.use_apple_decoder) { - if (decoder_in_use != 1 << decoder_apple_alac) { + if (conn->decoder_in_use != 1 << decoder_apple_alac) { debug(1, "Apple ALAC Decoder used on unencrypted audio."); - decoder_in_use = 1 << decoder_apple_alac; + conn->decoder_in_use = 1 << decoder_apple_alac; } apple_alac_decode_frame(buf, len, (unsigned char *)dest, &outsize); outsize = outsize * 4; // bring the size to bytes } else #endif { - if (decoder_in_use != 1 << decoder_hammerton) { + if (conn->decoder_in_use != 1 << decoder_hammerton) { debug(1, "Hammerton Decoder used on unencrypted audio."); - decoder_in_use = 1 << decoder_hammerton; + conn->decoder_in_use = 1 << decoder_hammerton; } alac_decode_frame(conn->decoder_info, buf, dest, &outsize); } @@ -547,10 +541,10 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // resend_requests++; ab_write = SUCCESSOR(seqno); } else if (seq_order(ab_read, seqno)) { // late but not yet played - late_packets++; + conn->late_packets++; abuf = conn->audio_buffer + BUFIDX(seqno); } else { // too late. - too_late_packets++; + conn->too_late_packets++; } // pthread_mutex_unlock(&ab_mutex); @@ -1091,14 +1085,14 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (!abuf->ready) { rtp_request_resend(next, 1); // debug(1,"Resend %u.",next); - resend_requests++; + conn->resend_requests++; } } } if (!curframe->ready) { // debug(1, "Supplying a silent frame for frame %u", read); - missing_packets++; + conn->missing_packets++; curframe->timestamp = 0; // indicate a silent frame should be substituted } curframe->ready = 0; @@ -1287,6 +1281,8 @@ static void *player_thread_func(void *arg) { conn->previous_random_number = 0; conn->input_bytes_per_frame = 4; conn->player_thread_please_stop = 0; + conn->decoder_in_use = 0; + init_decoder((int32_t *)&conn->stream.fmtp,conn); // this sets up incoming rate, bit depth, channels // must be after decoder init @@ -1451,7 +1447,7 @@ static void *player_thread_func(void *arg) { debug(1, "Failed to allocate memory for a silence buffer."); memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio); first_packet_timestamp = 0; - missing_packets = late_packets = too_late_packets = resend_requests = 0; + conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0; flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used // as a null operand, so we'll use it like that too int sync_error_out_of_bounds = @@ -1932,8 +1928,8 @@ static void *player_thread_func(void *arg) { moving_average_correction * 1000000 / (352 * conn->output_sample_ratio), 10, moving_average_insertions_plus_deletions * 1000000 / (352 * conn->output_sample_ratio), - 12, play_number, 7, missing_packets, 7, late_packets, 7, too_late_packets, - 7, resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, + 12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, + 7, conn->resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); } else { inform("%*.1f," /* Sync error in milliseconds */ @@ -1947,7 +1943,7 @@ static void *player_thread_func(void *arg) { "%*d", /* max buffer occupancy */ 10, 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7, - missing_packets, 7, late_packets, 7, too_late_packets, 7, resend_requests, + conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); } @@ -1962,7 +1958,7 @@ static void *player_thread_func(void *arg) { "%*d", /* max buffer occupancy */ 10, 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7, - missing_packets, 7, late_packets, 7, too_late_packets, 7, resend_requests, 5, + conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7, conn->resend_requests, 5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy); } } else { @@ -2051,6 +2047,7 @@ void player_volume(double airplay_volume) { max_db; // hw_range_db is a flag; if 0 means no mixer if (config.output->parameters) { + audio_parameters audio_information; // have a hardware mixer config.output->parameters(&audio_information); hw_max_db = audio_information.maximum_volume_dB; diff --git a/player.h b/player.h index fee8d5a0..b310bc12 100644 --- a/player.h +++ b/player.h @@ -61,6 +61,11 @@ typedef struct { int shutdown_requested; int connection_state_to_output; int player_thread_please_stop; + // stats + uint64_t missing_packets, late_packets, too_late_packets, resend_requests; + int decoder_in_use; + // debug variables + int32_t last_seqno_read; #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; From f06e638d24343eaec6c7ee977647afe89508260b Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 17:22:48 +0000 Subject: [PATCH 11/17] de-globalise flowcontrol ab_mutex,flush_mutex, first_packet_time_to_play, time_since_play_started --- player.c | 143 +++++++++++++++++++++++++++---------------------------- player.h | 8 +++- rtsp.c | 6 +-- 3 files changed, 79 insertions(+), 78 deletions(-) diff --git a/player.c b/player.c index 1d33d6d9..4ddfe578 100644 --- a/player.c +++ b/player.c @@ -79,16 +79,7 @@ static uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 // or 1. - -// #define FRAME_BYTES(max_frames_per_packet) (4 * max_frames_per_packet) -// maximal resampling shift - conservative -//#define OUTFRAME_BYTES(max_frames_per_packet) (4 * (max_frames_per_packet + 3)) - -// static pthread_t player_thread = NULL; - -// debug variables -static int32_t last_seqno_read; - + // interthread variables static int fix_volume = 0x10000; static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -112,13 +103,6 @@ static int flush_requested = 0; static int64_t flush_rtp_timestamp; static uint64_t time_of_last_audio_packet; -// mutexes and condition variables -static pthread_mutex_t ab_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t flush_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t flowcontrol; - -static int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds - // make timestamps and seqnos definitely monotonic // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 @@ -181,7 +165,7 @@ static void ab_resync(rtsp_conn_info* conn) { conn->audio_buffer[i].sequence_number = 0; } ab_synced = 0; - last_seqno_read = -1; + conn->last_seqno_read = -1; ab_buffering = 1; } @@ -486,13 +470,13 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // ignore a request to flush that has been made before the first packet... if (conn->packet_count == 0) { - pthread_mutex_lock(&flush_mutex); + pthread_mutex_lock(&conn->flush_mutex); flush_requested = 0; flush_rtp_timestamp = 0; - pthread_mutex_unlock(&flush_mutex); + pthread_mutex_unlock(&conn->flush_mutex); } - pthread_mutex_lock(&ab_mutex); + pthread_mutex_lock(&conn->ab_mutex); conn->packet_count++; time_of_last_audio_packet = get_absolute_time_in_fp(); if (conn->connection_state_to_output) { // if we are supposed to be processing these packets @@ -565,11 +549,11 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // pthread_mutex_lock(&ab_mutex); } - int rc = pthread_cond_signal(&flowcontrol); + int rc = pthread_cond_signal(&conn->flowcontrol); if (rc) debug(1, "Error signalling flowcontrol."); } - pthread_mutex_unlock(&ab_mutex); + pthread_mutex_unlock(&conn->ab_mutex); } int32_t rand_in_range(int32_t exclusive_range_limit) { @@ -712,7 +696,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { abuf_t *curframe; int notified_buffer_empty = 0; // diagnostic only - pthread_mutex_lock(&ab_mutex); + pthread_mutex_lock(&conn->ab_mutex); int wait; long dac_delay = 0; // long because alsa returns a long do { @@ -740,23 +724,23 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { conn->connection_state_to_output = rco; // change happening if (conn->connection_state_to_output == 0) { // going off - pthread_mutex_lock(&flush_mutex); + pthread_mutex_lock(&conn->flush_mutex); flush_requested = 1; - pthread_mutex_unlock(&flush_mutex); + pthread_mutex_unlock(&conn->flush_mutex); } } - pthread_mutex_lock(&flush_mutex); + pthread_mutex_lock(&conn->flush_mutex); if (flush_requested == 1) { if (config.output->flush) config.output->flush(); ab_resync(conn); first_packet_timestamp = 0; - first_packet_time_to_play = 0; - time_since_play_started = 0; + conn->first_packet_time_to_play = 0; + conn->time_since_play_started = 0; flush_requested = 0; } - pthread_mutex_unlock(&flush_mutex); + pthread_mutex_unlock(&conn->flush_mutex); uint32_t flush_limit = 0; if (ab_synced) { @@ -849,25 +833,25 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (delta >= 0) { int64_t delta_fp_sec = (delta << 32) / config.output_rate; // int64_t which is positive - first_packet_time_to_play = reference_timestamp_time + delta_fp_sec; + conn->first_packet_time_to_play = reference_timestamp_time + delta_fp_sec; } else { int64_t abs_delta = -delta; int64_t delta_fp_sec = (abs_delta << 32) / config.output_rate; // int64_t which is positive - first_packet_time_to_play = reference_timestamp_time - delta_fp_sec; + conn->first_packet_time_to_play = reference_timestamp_time - delta_fp_sec; } - if (local_time_now >= first_packet_time_to_play) { + if (local_time_now >= conn->first_packet_time_to_play) { debug( 1, "First packet is late! It should have played before now. Flushing 0.1 seconds"); - player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio); + player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio,conn); } } } - if (first_packet_time_to_play != 0) { - // recalculate first_packet_time_to_play -- the latency might change + if (conn->first_packet_time_to_play != 0) { + // recalculate conn->first_packet_time_to_play -- the latency might change int64_t delta = (first_packet_timestamp - reference_timestamp) + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate; @@ -875,32 +859,32 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (delta >= 0) { int64_t delta_fp_sec = (delta << 32) / config.output_rate; // int64_t which is positive - first_packet_time_to_play = reference_timestamp_time + delta_fp_sec; + conn->first_packet_time_to_play = reference_timestamp_time + delta_fp_sec; } else { int64_t abs_delta = -delta; int64_t delta_fp_sec = (abs_delta << 32) / config.output_rate; // int64_t which is positive - first_packet_time_to_play = reference_timestamp_time - delta_fp_sec; + conn->first_packet_time_to_play = reference_timestamp_time - delta_fp_sec; } int64_t max_dac_delay = config.output_rate / 10; int64_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC - if (local_time_now >= first_packet_time_to_play) { + if (local_time_now >= conn->first_packet_time_to_play) { // we've gone past the time... // debug(1,"Run past the exact start time by %llu frames, with time now of %llx, fpttp // of %llx and dac_delay of %d and %d packets; - // flush.",(((tn-first_packet_time_to_play)*config.output_rate)>>32)+dac_delay,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, + // flush.",(((tn-conn->first_packet_time_to_play)*config.output_rate)>>32)+dac_delay,tn,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read, // ab_write)); if (config.output->flush) config.output->flush(); ab_resync(conn); first_packet_timestamp = 0; - first_packet_time_to_play = 0; - time_since_play_started = 0; + conn->first_packet_time_to_play = 0; + conn->time_since_play_started = 0; } else { - // first_packet_time_to_play is definitely later than local_time_now + // conn->first_packet_time_to_play is definitely later than local_time_now if ((config.output->delay) && (have_sent_prefiller_silence != 0)) { int resp = config.output->delay(&dac_delay); if (resp != 0) { @@ -910,19 +894,19 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } else dac_delay = 0; int64_t gross_frame_gap = - ((first_packet_time_to_play - local_time_now) * config.output_rate) >> 32; + ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) >> 32; int64_t exact_frame_gap = gross_frame_gap - dac_delay; if (exact_frame_gap < 0) { // we've gone past the time... // debug(1,"Run a bit past the exact start time by %lld frames, with time now of // %llx, fpttp of %llx and dac_delay of %d and %d packets; - // flush.",-exact_frame_gap,tn,first_packet_time_to_play,dac_delay,seq_diff(ab_read, + // flush.",-exact_frame_gap,tn,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read, // ab_write)); if (config.output->flush) config.output->flush(); ab_resync(conn); first_packet_timestamp = 0; - first_packet_time_to_play = 0; + conn->first_packet_time_to_play = 0; } else { int64_t fs = filler_size; if (fs > (max_dac_delay - dac_delay)) @@ -1052,7 +1036,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { time_of_wakeup.tv_sec = sec; time_of_wakeup.tv_nsec = nsec; - pthread_cond_timedwait(&flowcontrol, &ab_mutex, &time_of_wakeup); + pthread_cond_timedwait(&conn->flowcontrol, &conn->ab_mutex, &time_of_wakeup); // int rc = pthread_cond_timedwait(&flowcontrol,&ab_mutex,&time_of_wakeup); // if (rc!=0) // debug(1,"pthread_cond_timedwait returned error code %d.",rc); @@ -1063,13 +1047,13 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { struct timespec time_to_wait; time_to_wait.tv_sec = sec; time_to_wait.tv_nsec = nsec; - pthread_cond_timedwait_relative_np(&flowcontrol, &ab_mutex, &time_to_wait); + pthread_cond_timedwait_relative_np(&conn->flowcontrol, &conn->ab_mutex, &time_to_wait); #endif } } while (wait); if (conn->player_thread_please_stop) { - pthread_mutex_unlock(&ab_mutex); + pthread_mutex_unlock(&conn->ab_mutex); return 0; } @@ -1097,7 +1081,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } curframe->ready = 0; ab_read = SUCCESSOR(ab_read); - pthread_mutex_unlock(&ab_mutex); + pthread_mutex_unlock(&conn->ab_mutex); return curframe; } @@ -1500,8 +1484,8 @@ static void *player_thread_func(void *arg) { play_number++; if (inframe->timestamp == 0) { // debug(1,"Player has a supplied silent frame."); - last_seqno_read = - (SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder + conn->last_seqno_read = + (SUCCESSOR(conn->last_seqno_read) & 0xffff); // manage the packet out of sequence minder config.output->play(silence, conn->max_frames_per_packet * conn->output_sample_ratio); } else { @@ -1641,18 +1625,18 @@ static void *player_thread_func(void *arg) { int amount_to_stuff = 0; // check sequencing - if (last_seqno_read == -1) - last_seqno_read = + if (conn->last_seqno_read == -1) + conn->last_seqno_read = inframe->sequence_number; // int32_t from seq_t, i.e. uint16_t, so okay. else { - last_seqno_read = - SUCCESSOR(last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay. + conn->last_seqno_read = + SUCCESSOR(conn->last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay. if (inframe->sequence_number != - last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay + conn->last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay debug(1, "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u " "and ab_write: %u.", - last_seqno_read, inframe->sequence_number, ab_read, ab_write); - last_seqno_read = inframe->sequence_number; // reset warning... + conn->last_seqno_read, inframe->sequence_number, ab_read, ab_write); + conn->last_seqno_read = inframe->sequence_number; // reset warning... } } @@ -1725,10 +1709,10 @@ static void *player_thread_func(void *arg) { // calculate the time elapsed since the play session started. if (amount_to_stuff) { - if ((local_time_now) && (first_packet_time_to_play) && - (local_time_now >= first_packet_time_to_play)) { + if ((local_time_now) && (conn->first_packet_time_to_play) && + (local_time_now >= conn->first_packet_time_to_play)) { - int64_t tp = (local_time_now - first_packet_time_to_play) >> + int64_t tp = (local_time_now - conn->first_packet_time_to_play) >> 32; // seconds int64_t from uint64_t which is always positive, so ok if (tp < 5) @@ -1810,7 +1794,7 @@ static void *player_thread_func(void *arg) { "resyncing. Error: %lld.", sync_error_out_of_bounds, sync_error); sync_error_out_of_bounds = 0; - player_flush(nt); + player_flush(nt,conn); } } else { sync_error_out_of_bounds = 0; @@ -2011,7 +1995,7 @@ static void *player_thread_func(void *arg) { } // takes the volume as specified by the airplay protocol -void player_volume(double airplay_volume) { +void player_volume(double airplay_volume, rtsp_conn_info* conn) { // The volume ranges -144.0 (mute) or -30 -- 0. See // http://git.zx2c4.com/Airtunes2/about/#setting-volume @@ -2203,13 +2187,13 @@ void player_volume(double airplay_volume) { #endif } -void player_flush(int64_t timestamp) { +void player_flush(int64_t timestamp, rtsp_conn_info* conn) { debug(3, "Flush requested up to %u. It seems as if 0 is special.", timestamp); - pthread_mutex_lock(&flush_mutex); + pthread_mutex_lock(&conn->flush_mutex); flush_requested = 1; // if (timestamp!=0) flush_rtp_timestamp = timestamp; // flush all packets up to (and including?) this - pthread_mutex_unlock(&flush_mutex); + pthread_mutex_unlock(&conn->flush_mutex); play_segment_reference_frame = 0; #ifdef CONFIG_METADATA send_ssnc_metadata('pfls', NULL, 0, 1); @@ -2229,18 +2213,25 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { send_ssnc_metadata('pbeg', NULL, 0, 1); #endif + + int rc = pthread_mutex_init(&conn->ab_mutex, NULL); + if (rc) + debug(1, "Error initialising ab_mutex."); + rc = pthread_mutex_init(&conn->flush_mutex, NULL); + if (rc) + debug(1, "Error initialising flush_mutex."); // set the flowcontrol condition variable to wait on a monotonic clock #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN pthread_condattr_t attr; pthread_condattr_init(&attr); pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it. - int rc = pthread_cond_init(&flowcontrol, &attr); + rc = pthread_cond_init(&conn->flowcontrol, &attr); #endif #ifdef COMPILE_FOR_OSX - int rc = pthread_cond_init(&flowcontrol, NULL); + rc = pthread_cond_init(&conn->flowcontrol, NULL); #endif if (rc) - debug(1, "Error initialising condition variable."); + debug(1, "Error initialising flowcontrol condition variable."); config.output->start(config.output_rate, config.output_format); size_t size = (PTHREAD_STACK_MIN + 256 * 1024); pthread_attr_t tattr; @@ -2258,14 +2249,20 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { // debug(1,"Trying to stop a non-existent player thread"); // else { conn->player_thread_please_stop = 1; - pthread_cond_signal(&flowcontrol); // tell it to give up + pthread_cond_signal(&conn->flowcontrol); // tell it to give up pthread_join(*player_thread, NULL); #ifdef CONFIG_METADATA send_ssnc_metadata('pend', NULL, 0, 1); #endif command_stop(); - int rc = pthread_cond_destroy(&flowcontrol); + int rc = pthread_cond_destroy(&conn->flowcontrol); if (rc) - debug(1, "Error destroying condition variable."); + debug(1, "Error destroying flowcontrol condition variable."); + rc = pthread_mutex_destroy(&conn->flush_mutex); + if (rc) + debug(1, "Error destroying flush_mutex variable."); + rc = pthread_mutex_destroy(&conn->ab_mutex); + if (rc) + debug(1, "Error destroying ab_mutex variable."); // } } diff --git a/player.h b/player.h index b310bc12..f5dfb732 100644 --- a/player.h +++ b/player.h @@ -61,11 +61,15 @@ typedef struct { int shutdown_requested; int connection_state_to_output; int player_thread_please_stop; + int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds // stats uint64_t missing_packets, late_packets, too_late_packets, resend_requests; int decoder_in_use; // debug variables int32_t last_seqno_read; +// mutexes and condition variables + pthread_cond_t flowcontrol; + pthread_mutex_t ab_mutex,flush_mutex; #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; @@ -86,8 +90,8 @@ int32_t seq_diff(seq_t a, seq_t b); int player_play(pthread_t *thread, rtsp_conn_info* conn); void player_stop(pthread_t *thread, rtsp_conn_info* conn); -void player_volume(double f); -void player_flush(int64_t timestamp); +void player_volume(double f, rtsp_conn_info* conn); +void player_flush(int64_t timestamp, rtsp_conn_info* conn); void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info* conn); int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic diff --git a/rtsp.c b/rtsp.c index 164c8e8b..ac531800 100644 --- a/rtsp.c +++ b/rtsp.c @@ -643,7 +643,7 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1 rtptime--; // debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime); - player_flush(rtptime); + player_flush(rtptime,conn); } } } @@ -684,7 +684,7 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * } } // debug(1,"RTSP Flush Requested: %u.",rtptime); - player_flush(rtptime); + player_flush(rtptime,conn); resp->respcode = 200; } @@ -848,7 +848,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r float volume = atof(cp + 8); if (config.ignore_volume_control == 0) { debug(2, "volume: %f\n", volume); - player_volume(volume); + player_volume(volume,conn); } #ifdef CONFIG_METADATA else { // if ignore volume is on... From 3ada8c944c1ff359eeb00a2e2452dd2e6a0c8afa Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Thu, 9 Mar 2017 17:51:07 +0000 Subject: [PATCH 12/17] Make initialising and destroying mutexes and condition variables internal to the player thread. --- player.c | 70 ++++++++++++++++++++++++++------------------------------ 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/player.c b/player.c index 4ddfe578..65324406 100644 --- a/player.c +++ b/player.c @@ -155,9 +155,6 @@ int64_t monotonic_timestamp(uint32_t timestamp) { return return_value; } -// add an epoch to the seq_no. Uses the accompanying timestamp to determine the correct epoch -uint64_t monotonic_seqno(uint16_t seq_no) {} - static void ab_resync(rtsp_conn_info* conn) { int i; for (i = 0; i < BUFFER_FRAMES; i++) { @@ -1260,13 +1257,33 @@ static void *player_thread_func(void *arg) { rtsp_conn_info *conn = (rtsp_conn_info *)arg; + conn->please_stop = 0; conn->packet_count = 0; conn->previous_random_number = 0; conn->input_bytes_per_frame = 4; conn->player_thread_please_stop = 0; conn->decoder_in_use = 0; - + + int rc = pthread_mutex_init(&conn->ab_mutex, NULL); + if (rc) + debug(1, "Error initialising ab_mutex."); + rc = pthread_mutex_init(&conn->flush_mutex, NULL); + if (rc) + debug(1, "Error initialising flush_mutex."); +// set the flowcontrol condition variable to wait on a monotonic clock +#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it. + rc = pthread_cond_init(&conn->flowcontrol, &attr); +#endif +#ifdef COMPILE_FOR_OSX + rc = pthread_cond_init(&conn->flowcontrol, NULL); +#endif + if (rc) + debug(1, "Error initialising flowcontrol condition variable."); + config.output->start(config.output_rate, config.output_format); init_decoder((int32_t *)&conn->stream.fmtp,conn); // this sets up incoming rate, bit depth, channels // must be after decoder init @@ -1990,6 +2007,16 @@ static void *player_thread_func(void *arg) { debug(1, "control thread joined"); free_buffer(conn); terminate_decoders(conn); + // remove flow control and mutexes + rc = pthread_cond_destroy(&conn->flowcontrol); + if (rc) + debug(1, "Error destroying flowcontrol condition variable."); + rc = pthread_mutex_destroy(&conn->flush_mutex); + if (rc) + debug(1, "Error destroying flush_mutex variable."); + rc = pthread_mutex_destroy(&conn->ab_mutex); + if (rc) + debug(1, "Error destroying ab_mutex variable."); debug(1, "Player thread exit"); return 0; } @@ -2212,31 +2239,10 @@ int player_play(pthread_t *player_thread, rtsp_conn_info *conn) { #ifdef CONFIG_METADATA send_ssnc_metadata('pbeg', NULL, 0, 1); #endif - - - int rc = pthread_mutex_init(&conn->ab_mutex, NULL); - if (rc) - debug(1, "Error initialising ab_mutex."); - rc = pthread_mutex_init(&conn->flush_mutex, NULL); - if (rc) - debug(1, "Error initialising flush_mutex."); -// set the flowcontrol condition variable to wait on a monotonic clock -#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN - pthread_condattr_t attr; - pthread_condattr_init(&attr); - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it. - rc = pthread_cond_init(&conn->flowcontrol, &attr); -#endif -#ifdef COMPILE_FOR_OSX - rc = pthread_cond_init(&conn->flowcontrol, NULL); -#endif - if (rc) - debug(1, "Error initialising flowcontrol condition variable."); - config.output->start(config.output_rate, config.output_format); - size_t size = (PTHREAD_STACK_MIN + 256 * 1024); + size_t size = (PTHREAD_STACK_MIN + 256 * 1024); pthread_attr_t tattr; pthread_attr_init(&tattr); - rc = pthread_attr_setstacksize(&tattr, size); + int rc = pthread_attr_setstacksize(&tattr, size); if (rc) debug(1, "Error setting stack size for player_thread: %s", strerror(errno)); pthread_create(player_thread, &tattr, player_thread_func, (void*)conn); @@ -2255,14 +2261,4 @@ void player_stop(pthread_t *player_thread, rtsp_conn_info *conn) { send_ssnc_metadata('pend', NULL, 0, 1); #endif command_stop(); - int rc = pthread_cond_destroy(&conn->flowcontrol); - if (rc) - debug(1, "Error destroying flowcontrol condition variable."); - rc = pthread_mutex_destroy(&conn->flush_mutex); - if (rc) - debug(1, "Error destroying flush_mutex variable."); - rc = pthread_mutex_destroy(&conn->ab_mutex); - if (rc) - debug(1, "Error destroying ab_mutex variable."); - // } } From 755e95904ca118e2e86070a982b44a60a20b429f Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 10 Mar 2017 17:44:50 +0000 Subject: [PATCH 13/17] De globalise everything except ab_read and ab_write and the volume control stuff --- player.c | 139 +++++++++++++++++++++++++++---------------------------- player.h | 9 +++- rtp.c | 8 ++-- 3 files changed, 80 insertions(+), 76 deletions(-) diff --git a/player.c b/player.c index 65324406..24e394c2 100644 --- a/player.c +++ b/player.c @@ -76,10 +76,7 @@ #include "apple_alac.h" #endif -static uint32_t timestamp_epoch, last_timestamp, - maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 - // or 1. - + // interthread variables static int fix_volume = 0x10000; static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -97,11 +94,6 @@ static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; // mutex-protected variables static seq_t ab_read, ab_write; -static int ab_buffering = 1, ab_synced = 0; -static int64_t first_packet_timestamp = 0; -static int flush_requested = 0; -static int64_t flush_rtp_timestamp; -static uint64_t time_of_last_audio_packet; // make timestamps and seqnos definitely monotonic @@ -112,42 +104,42 @@ static uint64_t time_of_last_audio_packet; // over 50,000 years. // also, it won't reach zero until then, if ever, so we can safely say that a null monotonic // timestamp can mean something special -int64_t monotonic_timestamp(uint32_t timestamp) { +int64_t monotonic_timestamp(uint32_t timestamp,rtsp_conn_info* conn) { int64_t previous_value; int64_t return_value; - if (timestamp_epoch == 0) { - if (timestamp > maximum_timestamp_interval) - timestamp_epoch = 1; + if (conn->timestamp_epoch == 0) { + if (timestamp > conn->maximum_timestamp_interval) + conn->timestamp_epoch = 1; else - timestamp_epoch = 2; - previous_value = timestamp_epoch; + conn->timestamp_epoch = 2; + previous_value = conn->timestamp_epoch; previous_value <<= 32; previous_value += timestamp; } else { - previous_value = timestamp_epoch; + previous_value = conn->timestamp_epoch; previous_value <<= 32; - previous_value += last_timestamp; - if (timestamp < last_timestamp) { + previous_value += conn->last_timestamp; + if (timestamp < conn->last_timestamp) { // the incoming timestamp is less than the last one. // if the difference is more than a minute, assume it's really from the next epoch - if ((last_timestamp - timestamp) > maximum_timestamp_interval) - timestamp_epoch++; + if ((conn->last_timestamp - timestamp) > conn->maximum_timestamp_interval) + conn->timestamp_epoch++; } else { // the incoming timestamp is greater than the last one. // if the difference is more than a minute, assume it's really from the previous epoch - if ((timestamp - last_timestamp) > maximum_timestamp_interval) - timestamp_epoch--; + if ((timestamp - conn->last_timestamp) > conn->maximum_timestamp_interval) + conn->timestamp_epoch--; } } - last_timestamp = timestamp; - return_value = timestamp_epoch; + conn->last_timestamp = timestamp; + return_value = conn->timestamp_epoch; return_value <<= 32; return_value += timestamp; if (previous_value > return_value) { - if ((previous_value - return_value) > maximum_timestamp_interval) + if ((previous_value - return_value) > conn->maximum_timestamp_interval) debug(1, "interval between successive rtptimes greater than allowed!"); } else { - if ((return_value - previous_value) > maximum_timestamp_interval) + if ((return_value - previous_value) > conn->maximum_timestamp_interval) debug(1, "interval between successive rtptimes greater than allowed!"); } if (return_value < 0) @@ -161,9 +153,9 @@ static void ab_resync(rtsp_conn_info* conn) { conn->audio_buffer[i].ready = 0; conn->audio_buffer[i].sequence_number = 0; } - ab_synced = 0; + conn->ab_synced = 0; conn->last_seqno_read = -1; - ab_buffering = 1; + conn->ab_buffering = 1; } // the sequence number is a 16-bit unsigned number which wraps pretty often @@ -468,36 +460,36 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // ignore a request to flush that has been made before the first packet... if (conn->packet_count == 0) { pthread_mutex_lock(&conn->flush_mutex); - flush_requested = 0; - flush_rtp_timestamp = 0; + conn->flush_requested = 0; + conn->flush_rtp_timestamp = 0; pthread_mutex_unlock(&conn->flush_mutex); } pthread_mutex_lock(&conn->ab_mutex); conn->packet_count++; - time_of_last_audio_packet = get_absolute_time_in_fp(); + conn->time_of_last_audio_packet = get_absolute_time_in_fp(); if (conn->connection_state_to_output) { // if we are supposed to be processing these packets // if (flush_rtp_timestamp != 0) // debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp); - if ((flush_rtp_timestamp != 0) && (ltimestamp <= flush_rtp_timestamp)) { + if ((conn->flush_rtp_timestamp != 0) && (ltimestamp <= conn->flush_rtp_timestamp)) { debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %lld, flushing to " "timestamp: %lld.", - seqno, ltimestamp, flush_rtp_timestamp); + seqno, ltimestamp, conn->flush_rtp_timestamp); } else { - if ((flush_rtp_timestamp != 0x0) && - (ltimestamp > flush_rtp_timestamp)) // if we have gone past the flush boundary time - flush_rtp_timestamp = 0x0; + if ((conn->flush_rtp_timestamp != 0x0) && + (ltimestamp > conn->flush_rtp_timestamp)) // if we have gone past the flush boundary time + conn->flush_rtp_timestamp = 0x0; abuf_t *abuf = 0; - if (!ab_synced) { + if (!conn->ab_synced) { debug(2, "syncing to seqno %u.", seqno); ab_write = seqno; ab_read = seqno; - ab_synced = 1; + conn->ab_synced = 1; } if (ab_write == seqno) { // expected packet abuf = conn->audio_buffer + BUFIDX(seqno); @@ -705,11 +697,11 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // config.timeout of zero means don't check..., but iTunes may be confused by a long gap // followed by a resumption... - if ((time_of_last_audio_packet != 0) && (conn->shutdown_requested == 0) && + if ((conn->time_of_last_audio_packet != 0) && (conn->shutdown_requested == 0) && (config.dont_check_timeout == 0)) { uint64_t ct = config.timeout; // go from int to 64-bit int - if ((local_time_now > time_of_last_audio_packet) && - (local_time_now - time_of_last_audio_packet >= ct << 32)) { + if ((local_time_now > conn->time_of_last_audio_packet) && + (local_time_now - conn->time_of_last_audio_packet >= ct << 32)) { debug(1, "As Yeats almost said, \"Too long a silence / can make a stone of the heart\""); rtsp_request_shutdown_stream(); conn->shutdown_requested = 1; @@ -722,25 +714,25 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // change happening if (conn->connection_state_to_output == 0) { // going off pthread_mutex_lock(&conn->flush_mutex); - flush_requested = 1; + conn->flush_requested = 1; pthread_mutex_unlock(&conn->flush_mutex); } } pthread_mutex_lock(&conn->flush_mutex); - if (flush_requested == 1) { + if (conn->flush_requested == 1) { if (config.output->flush) config.output->flush(); ab_resync(conn); - first_packet_timestamp = 0; + conn->first_packet_timestamp = 0; conn->first_packet_time_to_play = 0; conn->time_since_play_started = 0; - flush_requested = 0; + conn->flush_requested = 0; } pthread_mutex_unlock(&conn->flush_mutex); uint32_t flush_limit = 0; - if (ab_synced) { + if (conn->ab_synced) { do { curframe = conn->audio_buffer + BUFIDX(ab_read); if ((ab_read != ab_write) && (curframe->ready)) { // it could be synced and empty, under @@ -760,17 +752,17 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } } - if ((flush_rtp_timestamp != 0) && (curframe->timestamp <= flush_rtp_timestamp)) { + if ((conn->flush_rtp_timestamp != 0) && (curframe->timestamp <= conn->flush_rtp_timestamp)) { debug(1, "Dropping flushed packet seqno %u, timestamp %lld", curframe->sequence_number, curframe->timestamp); curframe->ready = 0; flush_limit++; ab_read = SUCCESSOR(ab_read); } - if (curframe->timestamp > flush_rtp_timestamp) - flush_rtp_timestamp = 0; + if (curframe->timestamp > conn->flush_rtp_timestamp) + conn->flush_rtp_timestamp = 0; } - } while ((flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0)); + } while ((conn->flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0)); if (flush_limit == 8820) { debug(1, "Flush hit the 8820 frame limit!"); @@ -781,7 +773,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (curframe->ready) { notified_buffer_empty = 0; // at least one buffer now -- diagnostic only. - if (ab_buffering) { // if we are getting packets but not yet forwarding them to the player + if (conn->ab_buffering) { // if we are getting packets but not yet forwarding them to the player int have_sent_prefiller_silence; // set true when we have sent some silent frames to the // DAC int64_t reference_timestamp; @@ -789,12 +781,12 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); reference_timestamp *= conn->output_sample_ratio; - if (first_packet_timestamp == 0) { // if this is the very first packet + if (conn->first_packet_timestamp == 0) { // if this is the very first packet // debug(1,"First frame seen, time %u, with %d // frames...",curframe->timestamp,seq_diff(ab_read, ab_write)); if (reference_timestamp) { // if we have a reference time // debug(1,"First frame seen with timestamp..."); - first_packet_timestamp = curframe->timestamp; // we will keep buffering until we are + conn->first_packet_timestamp = curframe->timestamp; // we will keep buffering until we are // supposed to start playing this have_sent_prefiller_silence = 0; @@ -823,7 +815,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { debug(1, "Output sample ratio is %d", conn->output_sample_ratio); - int64_t delta = (first_packet_timestamp - reference_timestamp) + + int64_t delta = (conn->first_packet_timestamp - reference_timestamp) + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate; @@ -842,14 +834,14 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { debug( 1, "First packet is late! It should have played before now. Flushing 0.1 seconds"); - player_flush(first_packet_timestamp + 4410 * conn->output_sample_ratio,conn); + player_flush(conn->first_packet_timestamp + 4410 * conn->output_sample_ratio,conn); } } } if (conn->first_packet_time_to_play != 0) { // recalculate conn->first_packet_time_to_play -- the latency might change - int64_t delta = (first_packet_timestamp - reference_timestamp) + + int64_t delta = (conn->first_packet_timestamp - reference_timestamp) + config.latency * conn->output_sample_ratio + config.audio_backend_latency_offset * config.output_rate; @@ -877,7 +869,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (config.output->flush) config.output->flush(); ab_resync(conn); - first_packet_timestamp = 0; + conn->first_packet_timestamp = 0; conn->first_packet_time_to_play = 0; conn->time_since_play_started = 0; } else { @@ -902,7 +894,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { if (config.output->flush) config.output->flush(); ab_resync(conn); - first_packet_timestamp = 0; + conn->first_packet_timestamp = 0; conn->first_packet_time_to_play = 0; } else { int64_t fs = filler_size; @@ -919,7 +911,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // with %d packets, ab_read is %04x, ab_write is // %04x.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, // ab_write),ab_read,ab_write); - ab_buffering = 0; + conn->ab_buffering = 0; } signed short *silence; // if (fs==0) @@ -944,7 +936,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } } } - if (ab_buffering == 0) { + if (conn->ab_buffering == 0) { // not the time of the playing of the first frame uint64_t reference_timestamp_time; // don't need this... get_reference_timestamp_stuff(&play_segment_reference_frame, &reference_timestamp_time, @@ -972,7 +964,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // Note: the last three items are expressed in frames and must be converted to time. int do_wait = 0; // don't wait unless we can really prove we must - if ((ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) { + if ((conn->ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) { do_wait = 1; // if the current frame exists and is ready, then wait unless it's time to let it go... int64_t reference_timestamp; @@ -1009,14 +1001,14 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } } if (do_wait == 0) - if ((ab_synced != 0) && (ab_read == ab_write)) { // the buffer is empty! + if ((conn->ab_synced != 0) && (ab_read == ab_write)) { // the buffer is empty! if (notified_buffer_empty == 0) { debug(1, "Buffers exhausted."); notified_buffer_empty = 1; } do_wait = 1; } - wait = (ab_buffering || (do_wait != 0) || (!ab_synced)) && (!conn->player_thread_please_stop); + wait = (conn->ab_buffering || (do_wait != 0) || (!conn->ab_synced)) && (!conn->player_thread_please_stop); if (wait) { uint64_t time_to_wait_for_wakeup_fp = @@ -1059,7 +1051,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // check if t+8, t+16, t+32, t+64, t+128, ... (buffer_start_fill / 2) // packets have arrived... last-chance resend - if (!ab_buffering) { + if (!conn->ab_buffering) { for (i = 8; i < (seq_diff(ab_read, ab_write) / 2); i = (i * 2)) { seq_t next = seq_sum(ab_read, i); abuf = conn->audio_buffer + BUFIDX(next); @@ -1264,6 +1256,11 @@ static void *player_thread_func(void *arg) { conn->input_bytes_per_frame = 4; conn->player_thread_please_stop = 0; conn->decoder_in_use = 0; + conn->ab_buffering = 1; + conn->ab_synced = 0; + conn->first_packet_timestamp = 0; + conn->flush_requested = 0; + int rc = pthread_mutex_init(&conn->ab_mutex, NULL); if (rc) @@ -1307,8 +1304,8 @@ static void *player_thread_func(void *arg) { #endif } - timestamp_epoch = 0; // indicate that the next timestamp will be the first one. - maximum_timestamp_interval = conn->input_rate * 60; // actually there shouldn't be more than about 13v + conn->timestamp_epoch = 0; // indicate that the next timestamp will be the first one. + conn->maximum_timestamp_interval = conn->input_rate * 60; // actually there shouldn't be more than about 13v // seconds of a gap between successive rtptimes, at // worst @@ -1369,7 +1366,7 @@ static void *player_thread_func(void *arg) { int play_samples; int64_t current_delay; int play_number = 0; - time_of_last_audio_packet = 0; + conn->time_of_last_audio_packet = 0; conn->shutdown_requested = 0; number_of_statistics = oldest_statistic = newest_statistic = 0; tsum_of_sync_errors = tsum_of_corrections = tsum_of_insertions_and_deletions = tsum_of_drifts = 0; @@ -1447,9 +1444,9 @@ static void *player_thread_func(void *arg) { if (silence == NULL) debug(1, "Failed to allocate memory for a silence buffer."); memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio); - first_packet_timestamp = 0; + conn->first_packet_timestamp = 0; conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0; - flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used + conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used // as a null operand, so we'll use it like that too int sync_error_out_of_bounds = 0; // number of times in a row that there's been a serious sync error @@ -2217,9 +2214,9 @@ void player_volume(double airplay_volume, rtsp_conn_info* conn) { void player_flush(int64_t timestamp, rtsp_conn_info* conn) { debug(3, "Flush requested up to %u. It seems as if 0 is special.", timestamp); pthread_mutex_lock(&conn->flush_mutex); - flush_requested = 1; + conn->flush_requested = 1; // if (timestamp!=0) - flush_rtp_timestamp = timestamp; // flush all packets up to (and including?) this + conn->flush_rtp_timestamp = timestamp; // flush all packets up to (and including?) this pthread_mutex_unlock(&conn->flush_mutex); play_segment_reference_frame = 0; #ifdef CONFIG_METADATA diff --git a/player.h b/player.h index f5dfb732..0f760362 100644 --- a/player.h +++ b/player.h @@ -70,6 +70,13 @@ typedef struct { // mutexes and condition variables pthread_cond_t flowcontrol; pthread_mutex_t ab_mutex,flush_mutex; + uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 + // or 1. + int ab_buffering,ab_synced; + int64_t first_packet_timestamp; + int flush_requested; + int64_t flush_rtp_timestamp; + uint64_t time_of_last_audio_packet; #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; @@ -94,7 +101,7 @@ void player_volume(double f, rtsp_conn_info* conn); void player_flush(int64_t timestamp, rtsp_conn_info* conn); void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info* conn); -int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic +int64_t monotonic_timestamp(uint32_t timestamp,rtsp_conn_info* conn); // add an epoch to the timestamp. The monotonic // timestamp guaranteed to start between 2^32 2^33 // frames and continue up to 2^64 frames // which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds. diff --git a/rtp.c b/rtp.c index 04f72b2b..26ea8193 100644 --- a/rtp.c +++ b/rtp.c @@ -164,7 +164,7 @@ void *rtp_audio_receiver(void *arg) { // debug(3, "RTP: Packets out of sequence: expected: %d, got %d.", last_seqno, seqno); last_seqno = seqno; // reset warning... } - int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4))); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)),conn); // if (packet[1]&0x10) // debug(1,"Audio packet Extension bit set."); @@ -234,8 +234,8 @@ void *rtp_control_receiver(void *arg) { // debug(1,"Remote Sync Time: %0llx.",remote_time_of_sync); - rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4]))); - sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16]))); + rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])),conn); + sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])),conn); if (config.use_negotiated_latencies) { int64_t la = sync_rtp_timestamp - rtp_timestamp_less_latency + 11025; @@ -274,7 +274,7 @@ void *rtp_control_receiver(void *arg) { plen -= 4; seq_t seqno = ntohs(*(unsigned short *)(pktp + 2)); - int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4))); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)),conn); pktp += 12; plen -= 12; From b559139862db8f1042bc16d67bc0ddb047312e3d Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 10 Mar 2017 19:20:49 +0000 Subject: [PATCH 14/17] De-globalise fix_volume and the vol_mutex --- player.c | 48 +++++++++++++++++++++++++----------------------- player.h | 2 ++ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/player.c b/player.c index 24e394c2..da664d27 100644 --- a/player.c +++ b/player.c @@ -76,11 +76,6 @@ #include "apple_alac.h" #endif - -// interthread variables -static int fix_volume = 0x10000; -static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER; - // default buffer size // needs to be a power of 2 because of the way BUFIDX(seqno) works //#define BUFFER_FRAMES 512 @@ -1118,17 +1113,17 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l stuffsamp = (rand() % (length - 2)) + 1; // ensure there's always a sample before and after the item - pthread_mutex_lock(&vol_mutex); + pthread_mutex_lock(&conn->vol_mutex); for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); }; if (tstuff) { if (tstuff == 1) { // debug(3, "+++++++++"); // interpolate one sample - process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, fix_volume, dither,conn); - process_sample(mean_32(inptr[-1], inptr[1]), &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, conn->fix_volume, dither,conn); + process_sample(mean_32(inptr[-1], inptr[1]), &l_outptr, l_output_format, conn->fix_volume, dither,conn); } else if (stuff == -1) { // debug(3, "---------"); inptr++; @@ -1142,11 +1137,11 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l remainder = remainder + tstuff; // don't run over the correct end of the output buffer for (i = stuffsamp; i < remainder; i++) { - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); - process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); + process_sample(*inptr++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); } } - pthread_mutex_unlock(&vol_mutex); + pthread_mutex_unlock(&conn->vol_mutex); return length + tstuff; } @@ -1221,8 +1216,8 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng ip = scratchBuffer; char *l_outptr = outptr; for (i = 0; i < length + tstuff; i++) { - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); }; } else { // the whole frame, if no stuffing @@ -1233,8 +1228,8 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng int i; for (i = 0; i < length; i++) { - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); - process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); + process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither,conn); }; } return length + tstuff; @@ -1260,6 +1255,7 @@ static void *player_thread_func(void *arg) { conn->ab_synced = 0; conn->first_packet_timestamp = 0; conn->flush_requested = 0; + conn->fix_volume = 0x10000; int rc = pthread_mutex_init(&conn->ab_mutex, NULL); @@ -1268,6 +1264,9 @@ static void *player_thread_func(void *arg) { rc = pthread_mutex_init(&conn->flush_mutex, NULL); if (rc) debug(1, "Error initialising flush_mutex."); + rc = pthread_mutex_init(&conn->vol_mutex, NULL); + if (rc) + debug(1, "Error initialising vol_mutex."); // set the flowcontrol condition variable to wait on a monotonic clock #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN pthread_condattr_t attr; @@ -1412,7 +1411,7 @@ static void *player_thread_func(void *arg) { debug(1, "Dithering will be enabled because the input bit depth is greater than the output bit " "depth"); } - if (fix_volume != 0x10000) { + if (conn->fix_volume != 0x10000) { debug(1, "Dithering will be enabled the output volume is being altered in software"); } @@ -1504,7 +1503,7 @@ static void *player_thread_func(void *arg) { } else { int enable_dither = 0; - if ((fix_volume != 0x10000) || (conn->input_bit_depth > output_bit_depth)) + if ((conn->fix_volume != 0x10000) || (conn->input_bit_depth > output_bit_depth)) enable_dither = 1; // here, let's transform the frame of data, if necessary @@ -1817,7 +1816,7 @@ static void *player_thread_func(void *arg) { // if there is no delay procedure, or it's not working or not allowed, there can be no // synchronising - if (fix_volume == 0x10000) + if (conn->fix_volume == 0x10000) if (inbuf == NULL) debug(1, "NULL inbuf to play -- skipping it."); @@ -2014,6 +2013,9 @@ static void *player_thread_func(void *arg) { rc = pthread_mutex_destroy(&conn->ab_mutex); if (rc) debug(1, "Error destroying ab_mutex variable."); + rc = pthread_mutex_destroy(&conn->vol_mutex); + if (rc) + debug(1, "Error destroying vol_mutex variable."); debug(1, "Player thread exit"); return 0; } @@ -2196,9 +2198,9 @@ void player_volume(double airplay_volume, rtsp_conn_info* conn) { // debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of // %f",software_attenuation,temp_fix_volume,airplay_volume); - pthread_mutex_lock(&vol_mutex); - fix_volume = temp_fix_volume; - pthread_mutex_unlock(&vol_mutex); + pthread_mutex_lock(&conn->vol_mutex); + conn->fix_volume = temp_fix_volume; + pthread_mutex_unlock(&conn->vol_mutex); #ifdef CONFIG_METADATA char *dv = malloc(128); // will be freed in the metadata thread diff --git a/player.h b/player.h index 0f760362..c8b39877 100644 --- a/player.h +++ b/player.h @@ -70,6 +70,8 @@ typedef struct { // mutexes and condition variables pthread_cond_t flowcontrol; pthread_mutex_t ab_mutex,flush_mutex; + pthread_mutex_t vol_mutex; + int fix_volume; uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 // or 1. int ab_buffering,ab_synced; From 314b5291a6496e6deb7b1c8428c523dd81405b1a Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 10 Mar 2017 19:41:51 +0000 Subject: [PATCH 15/17] Make the seq_diff... etc calls explicitly depend on a base value --- player.c | 24 ++++++++++++------------ player.h | 3 --- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/player.c b/player.c index da664d27..1df3798d 100644 --- a/player.c +++ b/player.c @@ -173,9 +173,9 @@ static inline seq_t PREDECESSOR(seq_t x) { } // anything with ORDINATE in it must be proctected by the ab_mutex -static inline int32_t ORDINATE(seq_t x) { +static inline int32_t ORDINATE(seq_t x, seq_t base) { int32_t p = x; // int32_t from seq_t, i.e. uint16_t, so okay - int32_t q = ab_read; // int32_t from seq_t, i.e. uint16_t, so okay + int32_t q = base; // int32_t from seq_t, i.e. uint16_t, so okay int32_t t = (p + 0x10000 - q) & 0xffff; // we definitely will get a positive number in t at this point, but it might be a // positive alias of a negative number, i.e. x might actually be "before" ab_read @@ -189,15 +189,15 @@ static inline int32_t ORDINATE(seq_t x) { } // wrapped number between two seq_t. -int32_t seq_diff(seq_t a, seq_t b) { - int32_t diff = ORDINATE(b) - ORDINATE(a); +int32_t seq_diff(seq_t a, seq_t b,seq_t base) { + int32_t diff = ORDINATE(b,base) - ORDINATE(a,base); return diff; } // the sequence numbers will wrap pretty often. // this returns true if the second arg is after the first -static inline int seq_order(seq_t a, seq_t b) { - int32_t d = ORDINATE(b) - ORDINATE(a); +static inline int seq_order(seq_t a, seq_t b, seq_t base) { + int32_t d = ORDINATE(b,base) - ORDINATE(a,base); return d > 0; } @@ -489,11 +489,11 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r if (ab_write == seqno) { // expected packet abuf = conn->audio_buffer + BUFIDX(seqno); ab_write = SUCCESSOR(seqno); - } else if (seq_order(ab_write, seqno)) { // newer than expected + } else if (seq_order(ab_write, seqno, ab_read)) { // newer than expected // if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8) // debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno: // %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno); - int32_t gap = seq_diff(ab_write, seqno); + int32_t gap = seq_diff(ab_write, seqno, ab_read); if (gap <= 0) debug(1, "Unexpected gap size: %d.", gap); int i; @@ -508,7 +508,7 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r // rtp_request_resend(ab_write, gap); // resend_requests++; ab_write = SUCCESSOR(seqno); - } else if (seq_order(ab_read, seqno)) { // late but not yet played + } else if (seq_order(ab_read, seqno, ab_read)) { // late but not yet played conn->late_packets++; abuf = conn->audio_buffer + BUFIDX(seqno); } else { // too late. @@ -738,7 +738,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // some kind of sync problem has occurred. if (BUFIDX(curframe->sequence_number) == BUFIDX(ab_read)) { // it looks like some kind of aliasing has happened - if (seq_order(ab_read, curframe->sequence_number)) { + if (seq_order(ab_read, curframe->sequence_number,ab_read)) { ab_read = curframe->sequence_number; debug(1, "Aliasing of buffer index -- reset."); } @@ -1047,7 +1047,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { // packets have arrived... last-chance resend if (!conn->ab_buffering) { - for (i = 8; i < (seq_diff(ab_read, ab_write) / 2); i = (i * 2)) { + for (i = 8; i < (seq_diff(ab_read, ab_write, ab_read) / 2); i = (i * 2)) { seq_t next = seq_sum(ab_read, i); abuf = conn->audio_buffer + BUFIDX(next); if (!abuf->ready) { @@ -1653,7 +1653,7 @@ static void *player_thread_func(void *arg) { } } - buffer_occupancy = seq_diff(ab_read, ab_write); // int32_t from int32 + buffer_occupancy = seq_diff(ab_read, ab_write, ab_read); // int32_t from int32 if (buffer_occupancy < minimum_buffer_occupancy) minimum_buffer_occupancy = buffer_occupancy; diff --git a/player.h b/player.h index c8b39877..a40ef6bd 100644 --- a/player.h +++ b/player.h @@ -93,9 +93,6 @@ typedef struct { #endif } rtsp_conn_info; -// wrapped number between two seq_t. -int32_t seq_diff(seq_t a, seq_t b); - int player_play(pthread_t *thread, rtsp_conn_info* conn); void player_stop(pthread_t *thread, rtsp_conn_info* conn); From 5c48bfe0e9da89fc0dacf25c3cd7b7c328aaf49e Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 10 Mar 2017 19:57:02 +0000 Subject: [PATCH 16/17] De-globalise ab_read and ab_write. player thread now fully reentrant. --- player.c | 51 ++++++++++++++++++++++++--------------------------- player.h | 1 + 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/player.c b/player.c index 1df3798d..f6187c84 100644 --- a/player.c +++ b/player.c @@ -87,9 +87,6 @@ //static abuf_t audio_buffer[BUFFER_FRAMES]; #define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES) -// mutex-protected variables -static seq_t ab_read, ab_write; - // make timestamps and seqnos definitely monotonic // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 @@ -482,23 +479,23 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r if (!conn->ab_synced) { debug(2, "syncing to seqno %u.", seqno); - ab_write = seqno; - ab_read = seqno; + conn->ab_write = seqno; + conn->ab_read = seqno; conn->ab_synced = 1; } - if (ab_write == seqno) { // expected packet + if (conn->ab_write == seqno) { // expected packet abuf = conn->audio_buffer + BUFIDX(seqno); - ab_write = SUCCESSOR(seqno); - } else if (seq_order(ab_write, seqno, ab_read)) { // newer than expected + conn->ab_write = SUCCESSOR(seqno); + } else if (seq_order(conn->ab_write, seqno, conn->ab_read)) { // newer than expected // if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8) // debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno: // %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno); - int32_t gap = seq_diff(ab_write, seqno, ab_read); + int32_t gap = seq_diff(conn->ab_write, seqno, conn->ab_read); if (gap <= 0) debug(1, "Unexpected gap size: %d.", gap); int i; for (i = 0; i < gap; i++) { - abuf = conn->audio_buffer + BUFIDX(seq_sum(ab_write, i)); + abuf = conn->audio_buffer + BUFIDX(seq_sum(conn->ab_write, i)); abuf->ready = 0; // to be sure, to be sure abuf->timestamp = 0; abuf->sequence_number = 0; @@ -507,8 +504,8 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, r abuf = conn->audio_buffer + BUFIDX(seqno); // rtp_request_resend(ab_write, gap); // resend_requests++; - ab_write = SUCCESSOR(seqno); - } else if (seq_order(ab_read, seqno, ab_read)) { // late but not yet played + conn->ab_write = SUCCESSOR(seqno); + } else if (seq_order(conn->ab_read, seqno, conn->ab_read)) { // late but not yet played conn->late_packets++; abuf = conn->audio_buffer + BUFIDX(seqno); } else { // too late. @@ -729,17 +726,17 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { uint32_t flush_limit = 0; if (conn->ab_synced) { do { - curframe = conn->audio_buffer + BUFIDX(ab_read); - if ((ab_read != ab_write) && (curframe->ready)) { // it could be synced and empty, under + curframe = conn->audio_buffer + BUFIDX(conn->ab_read); + if ((conn->ab_read != conn->ab_write) && (curframe->ready)) { // it could be synced and empty, under // exceptional circumstances, with the // frame unused, thus apparently ready - if (curframe->sequence_number != ab_read) { + if (curframe->sequence_number != conn->ab_read) { // some kind of sync problem has occurred. - if (BUFIDX(curframe->sequence_number) == BUFIDX(ab_read)) { + if (BUFIDX(curframe->sequence_number) == BUFIDX(conn->ab_read)) { // it looks like some kind of aliasing has happened - if (seq_order(ab_read, curframe->sequence_number,ab_read)) { - ab_read = curframe->sequence_number; + if (seq_order(conn->ab_read, curframe->sequence_number,conn->ab_read)) { + conn->ab_read = curframe->sequence_number; debug(1, "Aliasing of buffer index -- reset."); } } else { @@ -752,7 +749,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { curframe->timestamp); curframe->ready = 0; flush_limit++; - ab_read = SUCCESSOR(ab_read); + conn->ab_read = SUCCESSOR(conn->ab_read); } if (curframe->timestamp > conn->flush_rtp_timestamp) conn->flush_rtp_timestamp = 0; @@ -764,7 +761,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { flush_limit = 0; } - curframe = conn->audio_buffer + BUFIDX(ab_read); + curframe = conn->audio_buffer + BUFIDX(conn->ab_read); if (curframe->ready) { notified_buffer_empty = 0; // at least one buffer now -- diagnostic only. @@ -996,7 +993,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { } } if (do_wait == 0) - if ((conn->ab_synced != 0) && (ab_read == ab_write)) { // the buffer is empty! + if ((conn->ab_synced != 0) && (conn->ab_read == conn->ab_write)) { // the buffer is empty! if (notified_buffer_empty == 0) { debug(1, "Buffers exhausted."); notified_buffer_empty = 1; @@ -1041,14 +1038,14 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { return 0; } - seq_t read = ab_read; + seq_t read = conn->ab_read; // check if t+8, t+16, t+32, t+64, t+128, ... (buffer_start_fill / 2) // packets have arrived... last-chance resend if (!conn->ab_buffering) { - for (i = 8; i < (seq_diff(ab_read, ab_write, ab_read) / 2); i = (i * 2)) { - seq_t next = seq_sum(ab_read, i); + for (i = 8; i < (seq_diff(conn->ab_read, conn->ab_write, conn->ab_read) / 2); i = (i * 2)) { + seq_t next = seq_sum(conn->ab_read, i); abuf = conn->audio_buffer + BUFIDX(next); if (!abuf->ready) { rtp_request_resend(next, 1); @@ -1064,7 +1061,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info* conn) { curframe->timestamp = 0; // indicate a silent frame should be substituted } curframe->ready = 0; - ab_read = SUCCESSOR(ab_read); + conn->ab_read = SUCCESSOR(conn->ab_read); pthread_mutex_unlock(&conn->ab_mutex); return curframe; } @@ -1648,12 +1645,12 @@ static void *player_thread_func(void *arg) { conn->last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay debug(1, "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u " "and ab_write: %u.", - conn->last_seqno_read, inframe->sequence_number, ab_read, ab_write); + conn->last_seqno_read, inframe->sequence_number, conn->ab_read, conn->ab_write); conn->last_seqno_read = inframe->sequence_number; // reset warning... } } - buffer_occupancy = seq_diff(ab_read, ab_write, ab_read); // int32_t from int32 + buffer_occupancy = seq_diff(conn->ab_read, conn->ab_write, conn->ab_read); // int32_t from int32 if (buffer_occupancy < minimum_buffer_occupancy) minimum_buffer_occupancy = buffer_occupancy; diff --git a/player.h b/player.h index a40ef6bd..41e8373a 100644 --- a/player.h +++ b/player.h @@ -79,6 +79,7 @@ typedef struct { int flush_requested; int64_t flush_rtp_timestamp; uint64_t time_of_last_audio_packet; + seq_t ab_read, ab_write; #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; From b4f772c3b1adcbd98cfb7e9d0bf421eda94362e4 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 10 Mar 2017 21:00:18 +0000 Subject: [PATCH 17/17] Change the identified basck to ShairportSync -- lost in the move from 2.8.6 to 3.0 --- mdns.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mdns.h b/mdns.h index c4fe4bc6..7aa9dbb2 100644 --- a/mdns.h +++ b/mdns.h @@ -24,7 +24,7 @@ typedef struct { // "sr=44100", "vn=3", "txtvers=1", config.password ? "pw=true" : "pw=false" #define MDNS_RECORD_WITH_METADATA \ - "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", \ + "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", \ METADATA_EXPRESSION, "ss=16", "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", \ "ch=2", "txtvers=1", config.password ? "pw=true" : "pw=false" @@ -35,7 +35,7 @@ typedef struct { // "txtvers=1", config.password ? "pw=true" : "pw=false" #define MDNS_RECORD_WITHOUT_METADATA \ - "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", "ss=16", \ + "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", "ss=16", \ "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", "ch=2", "txtvers=1", \ config.password ? "pw=true" : "pw=false"