From e3faba141c24bdbec191c46010c7d394453a9969 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Sun, 28 Nov 2021 21:51:26 +0000
Subject: [PATCH 01/13] log statsistics headers whenever verbosity goes on or
off or whenever statistics are requested
---
dbus-service.c | 4 ++++
player.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/dbus-service.c b/dbus-service.c
index bbd5dcd4..05dd9726 100644
--- a/dbus-service.c
+++ b/dbus-service.c
@@ -423,6 +423,8 @@ gboolean notify_statistics_callback(ShairportSyncDiagnostics *skeleton,
// debug(1, "\"notify_statistics_callback\" called.");
if (shairport_sync_diagnostics_get_statistics(skeleton)) {
debug(1, ">> start logging statistics");
+ if (config.statistics_requested == 0)
+ statistics_row = 0; // redraw the header line
config.statistics_requested = 1;
} else {
debug(1, ">> stop logging statistics");
@@ -437,6 +439,8 @@ gboolean notify_verbosity_callback(ShairportSyncDiagnostics *skeleton,
if ((th >= 0) && (th <= 3)) {
if (th == 0)
debug(1, ">> log verbosity set to %d.", th);
+ if (((debuglev == 0) && (th != 0)) || ((debuglev != 0) && (th == 0)))
+ statistics_row = 0; // if the debug level changes, redraw the header line
debuglev = th;
debug(1, ">> log verbosity set to %d.", th);
} else {
diff --git a/player.h b/player.h
index d37f00c7..edf80837 100644
--- a/player.h
+++ b/player.h
@@ -410,6 +410,7 @@ typedef struct {
} rtsp_conn_info;
extern pthread_mutex_t playing_conn_lock;
+extern int statistics_row; // will be reset to zero when debug level changes or statistics enabled
void reset_buffer(rtsp_conn_info *conn);
From 7b8e293f8b4c8ea3a7d7aeb148ffed6b10d44288 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Wed, 1 Dec 2021 09:01:31 +0000
Subject: [PATCH 02/13] Change behaviour after an unrecoverable error -- if not
handled, exit Shairport Sync.
---
player.c | 2 +-
rtsp.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/player.c b/player.c
index 9b0b86ca..e9fa556a 100644
--- a/player.c
+++ b/player.c
@@ -1168,7 +1168,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
if (config.cmd_unfixable) {
command_execute(config.cmd_unfixable, "output_device_stalled", 1);
} else {
- warn("an unrecoverable error, \"output_device_stalled\", has been "
+ die("an unrecoverable error, \"output_device_stalled\", has been "
"detected.",
conn->connection_number);
}
diff --git a/rtsp.c b/rtsp.c
index 079ad14d..ae650a6a 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -611,7 +611,7 @@ void *player_watchdog_thread_code(void *arg) {
conn->unfixable_error_reported = 1;
command_execute(config.cmd_unfixable, "unable_to_cancel_play_session", 1);
} else {
- warn("an unrecoverable error, \"unable_to_cancel_play_session\", has been detected.",
+ die("an unrecoverable error, \"unable_to_cancel_play_session\", has been detected.",
conn->connection_number);
}
}
From b3526c54726c627b9e083ed0eed9b770bca3f829 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Wed, 1 Dec 2021 17:58:22 +0000
Subject: [PATCH 03/13] Use PKG_CHECK_MODULES to find libavcodec, to make it
work with Fedora 35 (?)
---
configure.ac | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index e0dcb10f..7f31e167 100644
--- a/configure.ac
+++ b/configure.ac
@@ -413,7 +413,9 @@ if test "x$with_airplay_2" = "xyes" ; then
# PKG_CHECK_MODULES([libgcrypt], [libgcrypt],[CFLAGS="${libgcrypt_CFLAGS} ${CFLAGS}" LIBS="${libgcrypt_LIBS} ${LIBS}"],[AC_MSG_ERROR(AirPlay 2 support requires libgcrypt -- libgcrypt-dev suggested)])
# AC_CHECK_LIB([sodium], [sodium_init], ,[AC_MSG_ERROR([AirPlay 2 support requires libsodium -- libsodium-dev suggested])])
AC_CHECK_LIB([avutil],[av_malloc], [], [AC_MSG_ERROR([Airplay 2 support requires libavutil -- libavutil-dev suggested])])
- AC_CHECK_LIB([avcodec],[avcodec_find_encoder], [], [AC_MSG_ERROR([AirPlay 2 support requires libavcodec -- libavcodec-dev suggested])])
+ PKG_CHECK_MODULES([libavcodec], [libavcodec],[CFLAGS="${libavcodec_CFLAGS} ${CFLAGS}" LIBS="${libavcodec_LIBS} ${LIBS}"],[
+ AC_MSG_ERROR(AirPlay 2 support requires libavcodec -- libavcodec-dev suggested)])
+# AC_CHECK_LIB([avcodec],[avcodec_find_encoder], [], [AC_MSG_ERROR([AirPlay 2 support requires libavcodec -- libavcodec-dev suggested])])
AC_CHECK_LIB([avformat],[avformat_new_stream], [], [AC_MSG_ERROR([AirPlay 2 support requires libavformat -- libavformat-dev suggested])])
AC_CHECK_LIB([swresample],[swr_convert], [], [AC_MSG_ERROR([AirPlay 2 support requires libswresample -- libswresample-dev suggested])])
AC_CHECK_LIB([uuid],[uuid_generate], [], [AC_MSG_ERROR([AirPlay 2 support requires the uuid library -- uuid-dev suggested])])
From 60f830bc7541e374dc87d72cc956452c924a7a75 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Thu, 2 Dec 2021 11:16:00 +0000
Subject: [PATCH 04/13] Tidy up the statistics printout table and stop
outputting (non existent) nominal fps for AP2 Realtime Streams.
---
player.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/player.c b/player.c
index e9fa556a..257d2ee8 100644
--- a/player.c
+++ b/player.c
@@ -1554,25 +1554,19 @@ int *statistics_print_profile;
// these arrays specify which of the statistics specified by the statistics_item calls will actually
// be printed -- 2 means print, 1 means print only in a debug mode, 0 means skip
-// don't display output fps -- not sure how accurate it is (change item 14 and 17 to 1 to restore)
-int ap1_synced_statistics_print_profile[] = {2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1};
-int ap1_nosync_statistics_print_profile[] = {2, 0, 0, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 1, 0};
-int ap1_nodelay_statistics_print_profile[] = {0, 0, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 1, 0, 0, 1, 0};
+// clang-format off
+int ap1_synced_statistics_print_profile[] = {2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1};
+int ap1_nosync_statistics_print_profile[] = {2, 0, 0, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 0, 0, 1, 0};
+int ap1_nodelay_statistics_print_profile[] = {0, 0, 0, 1, 2, 1, 1, 2, 0, 1, 1, 1, 1, 0, 0, 1, 0};
-int ap2_realtime_synced_stream_statistics_print_profile[] = {2, 2, 2, 1, 2, 1, 1, 2, 1,
- 1, 1, 1, 1, 2, 2, 0, 0};
-int ap2_realtime_nosync_stream_statistics_print_profile[] = {2, 0, 0, 1, 2, 1, 1, 2, 1,
- 1, 1, 1, 1, 0, 0, 0, 0};
-int ap2_realtime_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 1, 2, 1, 1, 2, 0,
- 1, 1, 1, 1, 0, 0, 0, 0};
+int ap2_realtime_synced_stream_statistics_print_profile[] = {2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 1, 0, 1, 2, 2, 0, 0};
+int ap2_realtime_nosync_stream_statistics_print_profile[] = {2, 0, 0, 1, 2, 1, 1, 2, 1, 1, 1, 0, 1, 0, 0, 0, 0};
+int ap2_realtime_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 1, 2, 1, 1, 2, 0, 1, 1, 0, 1, 0, 0, 0, 0};
-// don't display output fps -- not sure how accurate it is (change item 14 1 to restore)
-int ap2_buffered_synced_stream_statistics_print_profile[] = {2, 2, 2, 1, 0, 0, 0, 0, 1,
- 1, 1, 0, 0, 2, 2, 0, 0};
-int ap2_buffered_nosync_stream_statistics_print_profile[] = {2, 0, 0, 1, 0, 0, 0, 0, 1,
- 1, 1, 0, 0, 0, 0, 0, 0};
-int ap2_buffered_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 1, 0, 0, 0, 0, 0,
- 1, 1, 0, 0, 0, 0, 0, 0};
+int ap2_buffered_synced_stream_statistics_print_profile[] = {2, 2, 2, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 2, 2, 0, 0};
+int ap2_buffered_nosync_stream_statistics_print_profile[] = {2, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0};
+int ap2_buffered_nodelay_stream_statistics_print_profile[] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0};
+// clang-format on
void statistics_item(const char *heading, const char *format, ...) {
if (((statistics_print_profile[statistics_column] == 1) && (debuglev != 0)) ||
From d32544d9047e3c3286819c93a56acd9a387c67bd Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Thu, 2 Dec 2021 11:17:59 +0000
Subject: [PATCH 05/13] Set the timing peer list as soon as a SETPEERS message
is received -- don't wait until play is about to begin. Not sure if it works
universally yet.
---
rtsp.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index ae650a6a..ba03359f 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -1756,7 +1756,7 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
if ((rate & 1) != 0) {
// keep this outside the flush_mutex lock
if (conn->ap2_timing_peer_list_message) {
- ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
+ // ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
} else {
debug(1, "Connection %d: No timing peer list!", conn->connection_number);
}
@@ -2290,10 +2290,10 @@ void handle_setpeers(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp
free(conn->ap2_timing_peer_list_message);
conn->ap2_timing_peer_list_message = strdup(timing_list_message);
// if this rtsp thread is playing...
- if (try_to_hold_play_lock(conn) == 0) {
+ // if (try_to_hold_play_lock(conn) == 0) {
ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
- release_hold_on_play_lock(conn);
- }
+ // release_hold_on_play_lock(conn);
+ // }
}
plist_free(addresses_array);
resp->respcode = 200;
@@ -2876,10 +2876,11 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
conn->input_bit_depth = conn->stream.fmtp[3];
conn->input_bytes_per_frame = conn->input_num_channels * ((conn->input_bit_depth + 7) / 8);
debug(2, "Realtime Stream Play");
- if (conn->ap2_timing_peer_list_message)
- ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
- else
+ if (conn->ap2_timing_peer_list_message) {
+ // ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
+ } else {
debug(1, "No timing peer list!");
+ }
activity_monitor_signify_activity(1);
player_prepare_to_play(conn);
player_play(conn);
From 231d5242d782483a44176b8e1efddb9ca4b2be0c Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Thu, 2 Dec 2021 11:19:52 +0000
Subject: [PATCH 06/13] clang format only
---
player.c | 4 ++--
rtsp.c | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/player.c b/player.c
index 257d2ee8..36c7aabf 100644
--- a/player.c
+++ b/player.c
@@ -1169,8 +1169,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
command_execute(config.cmd_unfixable, "output_device_stalled", 1);
} else {
die("an unrecoverable error, \"output_device_stalled\", has been "
- "detected.",
- conn->connection_number);
+ "detected.",
+ conn->connection_number);
}
}
} else {
diff --git a/rtsp.c b/rtsp.c
index ba03359f..45efd8cf 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -612,7 +612,7 @@ void *player_watchdog_thread_code(void *arg) {
command_execute(config.cmd_unfixable, "unable_to_cancel_play_session", 1);
} else {
die("an unrecoverable error, \"unable_to_cancel_play_session\", has been detected.",
- conn->connection_number);
+ conn->connection_number);
}
}
}
@@ -2291,8 +2291,8 @@ void handle_setpeers(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp
conn->ap2_timing_peer_list_message = strdup(timing_list_message);
// if this rtsp thread is playing...
// if (try_to_hold_play_lock(conn) == 0) {
- ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
- // release_hold_on_play_lock(conn);
+ ptp_send_control_message_string(conn->ap2_timing_peer_list_message);
+ // release_hold_on_play_lock(conn);
// }
}
plist_free(addresses_array);
From 41f55ac1cb4b371ac8dec4155ffabcccc6facd51 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:03:42 +0000
Subject: [PATCH 07/13] Stop clearing the timing peer list and stop removing
the anchor clock info.
---
player.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/player.c b/player.c
index 36c7aabf..da98c55b 100644
--- a/player.c
+++ b/player.c
@@ -383,6 +383,10 @@ void reset_buffer(rtsp_conn_info *conn) {
debug_mutex_lock(&conn->ab_mutex, 30000, 0);
ab_resync(conn);
debug_mutex_unlock(&conn->ab_mutex, 0);
+ if (config.output->flush) {
+ config.output->flush(); // no cancellation points
+// debug(1, "reset_buffer: flush output device.");
+ }
}
void get_audio_buffer_size_and_occupancy(unsigned int *size, unsigned int *occupancy,
@@ -1687,7 +1691,7 @@ void player_thread_cleanup_handler(void *arg) {
debug(3, "Audio thread terminated.");
#ifdef CONFIG_AIRPLAY_2
}
- ptp_send_control_message_string("T"); // remove all timing peers to force the master to 0
+ // ptp_send_control_message_string("T"); // remove all timing peers to force the master to 0
#endif
if (conn->outbuf) {
@@ -1711,7 +1715,7 @@ void player_thread_cleanup_handler(void *arg) {
if (conn->stream.type == ast_apple_lossless)
terminate_decoders(conn);
- reset_anchor_info(conn);
+ // reset_anchor_info(conn);
release_play_lock(conn);
conn->rtp_running = 0;
pthread_setcancelstate(oldState, NULL);
@@ -1747,7 +1751,7 @@ void *player_thread_func(void *arg) {
conn->ap2_play_enabled = 0;
#endif
- reset_anchor_info(conn);
+ // reset_anchor_info(conn);
if (conn->stream.type == ast_apple_lossless)
init_alac_decoder((int32_t *)&conn->stream.fmtp,
From fa20d88c1c2b46391a6de88f187fd8c816bd7806 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:08:35 +0000
Subject: [PATCH 08/13] Remember to add some exta fields later...
---
plists/get_info_response.xml | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/plists/get_info_response.xml b/plists/get_info_response.xml
index 7a3b7a05..b45e3bad 100644
--- a/plists/get_info_response.xml
+++ b/plists/get_info_response.xml
@@ -60,7 +60,8 @@
366.0
statusFlags
4
- txtAirPlay
-
+
+
From be4807fff205b7022d7fed2bc27b29ce1f1d38fa Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:09:29 +0000
Subject: [PATCH 09/13] Wait for that mutex for longer. (Don't know why yet...)
---
ptp-utilities.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ptp-utilities.c b/ptp-utilities.c
index 7019187e..fa1c6407 100644
--- a/ptp-utilities.c
+++ b/ptp-utilities.c
@@ -68,7 +68,7 @@ int get_nqptp_data(struct shm_structure *nqptp_data) {
int ptp_get_clock_info(uint64_t *actual_clock_id, uint64_t *time_of_sample, uint64_t *raw_offset,
uint64_t *mastership_start_time) {
int response = clock_ok;
- pthread_cleanup_debug_mutex_lock(&ptp_access_mutex, 20000, 1);
+ pthread_cleanup_debug_mutex_lock(&ptp_access_mutex, 50000, 1);
if (actual_clock_id != NULL)
*actual_clock_id = 0;
if (raw_offset != NULL)
From 0b21373c0e5ba8e565bf420ed2ad8eb79f23d491 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:13:20 +0000
Subject: [PATCH 10/13] Skip some invalid AAC packets, don't decode outdated
frames, wait for timing information to be valid.
---
rtp.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 48 insertions(+), 13 deletions(-)
diff --git a/rtp.c b/rtp.c
index 5b79ff4b..d3bf06c4 100644
--- a/rtp.c
+++ b/rtp.c
@@ -1310,7 +1310,7 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP,
// if the master clock and the anchor clock are the same
// wait at least this time before using the new master clock
// note that mastershipo may be backdated
- if (duration_of_mastership < 1500000000) {
+ if (duration_of_mastership < 100000000) {
debug(3, "master not old enough yet: %f ms", 0.000001 * duration_of_mastership);
response = clock_not_ready;
} else if ((duration_of_mastership > 5000000000) ||
@@ -1400,6 +1400,7 @@ int get_ptp_anchor_local_time_info(rtsp_conn_info *conn, uint32_t *anchorRTP,
}
}
} else {
+ // debug(1, "anchor_remote_info_is_valid not valid");
response = clock_no_anchor_info; // no anchor information
}
}
@@ -2253,7 +2254,14 @@ void *rtp_buffered_audio_processor(void *arg) {
int streaming_has_started = 0;
int play_enabled = 0;
uint32_t flush_from_timestamp;
- double requested_lead_time = 0.3; // normal lead time minimum
+ double requested_lead_time = 0.0; // normal lead time minimum -- maybe it should be about 0.1
+
+ // wait until our timing information is valid
+
+ // debug(1,"rtp_buffered_audio_processor ready.");
+ while (have_ptp_timing_information(conn) == 0)
+ usleep(1000);
+
reset_buffer(conn); // in case there is any garbage in the player
// int not_first_time_out = 0;
@@ -2519,28 +2527,42 @@ void *rtp_buffered_audio_processor(void *arg) {
// to decipher it first
// debug(1,"seq_no %u, timestamp %u", seq_no, timestamp);
+ uint64_t local_should_be_time = 0;
+ int have_time_information = frame_to_local_time(timestamp, &local_should_be_time, conn);
+ int64_t local_lead_time = 0;
+ int64_t requested_lead_time_ns = (int64_t)(requested_lead_time * 1000000000);
+ requested_lead_time_ns = (int64_t)(-300000000);
+ int outdated = 0;
+ if (have_time_information == 0) {
+ local_lead_time = local_should_be_time - get_absolute_time_in_ns();
+ outdated = (local_lead_time < requested_lead_time_ns);
+ // if (outdated != 0)
+ // debug(1,"Frame is outdated %d if lead_time %" PRId64 " is less than requested lead time %" PRId64 " ns.", outdated, local_lead_time, requested_lead_time_ns);
+ } else {
+ debug(1,"Timing information not valid");
+ // outdated = 1;
+ }
+
+
if ((flush_requested) && (seq_no >= flushUntilSeq)) {
- uint64_t should_be_time;
- if ((frame_to_local_time(timestamp, &should_be_time, conn) == 0) && (play_enabled)) {
+ if ((have_time_information == 0) && (play_enabled)) {
// play enabled will be off when this is a full flush and the anchor information is not
// valid
- int64_t lead_time = should_be_time - get_absolute_time_in_ns();
- debug(1,
+ debug(2,
"flush completed to seq: %u, flushUntilTS; %u with rtptime: %u, lead time: "
"0x%" PRIx64 " nanoseconds, i.e. %f sec.",
- seq_no, flushUntilTS, timestamp, lead_time, lead_time * 0.000000001);
+ seq_no, flushUntilTS, timestamp, local_lead_time, local_lead_time * 0.000000001);
} else {
debug(2, "flush completed to seq: %u with rtptime: %u.", seq_no, timestamp);
}
}
-
- if (((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
- ((flush_requested == 0) && (new_buffer_needed))) {
-
+
// if we are here because of a flush request, it must be the case that
// flushing the pcm buffer wasn't enough, as the request would have been turned off by now
// so we better indicate that the pcm buffer is empty and its contents invalid
- if (flush_requested) {
+
+ // also, if the incomgin frame is outdated, set pcm_buffer_occupancy to 0;
+ if ((flush_requested) || (outdated)){
pcm_buffer_occupancy = 0;
}
@@ -2556,6 +2578,11 @@ void *rtp_buffered_audio_processor(void *arg) {
//}
}
+
+ if (((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
+ ((flush_requested == 0) && (new_buffer_needed))) {
+
+
unsigned char nonce[12];
memset(nonce, 0, sizeof(nonce));
memcpy(nonce + 4, packet + nread - 8,
@@ -2596,6 +2623,7 @@ void *rtp_buffered_audio_processor(void *arg) {
data_remaining = aac_packet_length;
int ret = 0;
// there can be more than one av packet (? terminology) in a block
+ int frame_within_block = 0;
while (data_remaining > 0) {
if (decoded_frame == NULL) {
decoded_frame = av_frame_alloc();
@@ -2608,14 +2636,20 @@ void *rtp_buffered_audio_processor(void *arg) {
if (ret < 0) {
debug(1, "error while parsing deciphered audio packet.");
} else {
+ frame_within_block++;
data_to_process += ret;
data_remaining -= ret;
// debug(1, "frame found");
// now pass each packet to be decoded
if (pkt->size) {
+ //if (0) {
+ if (pkt->size <= 7) { // no idea about this...
+ debug(1,"malformed AAC packet skipped.");
+ } else {
ret = avcodec_send_packet(codec_context, pkt);
+
if (ret < 0) {
- debug(1, "error sending packet to decoder");
+ debug(1, "error sending frame %d of size %d to decoder, blocks_read: %u, blocks_read_since_flush: %u.", frame_within_block, pkt->size, blocks_read, blocks_read_since_flush);
} else {
while (ret >= 0) {
ret = avcodec_receive_frame(codec_context, decoded_frame);
@@ -2672,6 +2706,7 @@ void *rtp_buffered_audio_processor(void *arg) {
}
}
}
+ }
}
if (decoded_frame == NULL)
debug(1, "decoded_frame is NULL");
From 3b9f2e1c53ede54dcbfba551bc534d2efd43c557 Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:14:23 +0000
Subject: [PATCH 11/13] Don't ask for cover art if not asking for metadata too.
Duh.
---
shairport.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/shairport.c b/shairport.c
index 9b7648e3..b1faf5c9 100644
--- a/shairport.c
+++ b/shairport.c
@@ -1807,11 +1807,12 @@ int main(int argc, char **argv) {
#ifdef CONFIG_METADATA
// If we are asking for metadata, turn on the relevant bits
- if (config.metadata_enabled != 0)
+ if (config.metadata_enabled != 0) {
config.airplay_features |= (1 << 17) | (1 << 16); // 16 is progress, 17 is text
- // If we are asking for artwork, turn on the relevant bit
- if (config.get_coverart)
- config.airplay_features |= (1 << 15); // 15 is artwork
+ // If we are asking for artwork, turn on the relevant bit
+ if (config.get_coverart)
+ config.airplay_features |= (1 << 15); // 15 is artwork
+ }
#endif
debug(1, "Features: 0x%" PRIx64 ".", config.airplay_features);
From 1e2136821337dd73f4ac563e0ff6f3ff5790a92c Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:16:57 +0000
Subject: [PATCH 12/13] Add txtAirPlay data to info response. Don't pause long
RTSP message reception.
---
rtsp.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 110 insertions(+), 17 deletions(-)
diff --git a/rtsp.c b/rtsp.c
index 45efd8cf..6c0da18f 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -185,6 +185,39 @@ typedef struct {
#ifdef CONFIG_AIRPLAY_2
+int add_pstring_to_malloc(const char *s, void **allocation, size_t *size) {
+ int response = 0;
+ void *p = *allocation;
+ if (p == NULL) {
+ p = malloc(strlen(s) + 1);
+ if (p == NULL) {
+ debug(1, "error allocating memory");
+ } else {
+ *allocation = p;
+ *size = *size + strlen(s) + 1;
+ uint8_t *b = (uint8_t *)p;
+ *b = strlen(s);
+ p = p+1;
+ memcpy(p,s,strlen(s));
+ response = 1;
+ }
+ } else {
+ p = realloc(p, *size + strlen(s) + 1);
+ if (p == NULL) { // assuming we never allocate a zero byte space
+ debug(1, "error reallocating memory");
+ } else {
+ *allocation = p;
+ uint8_t *b = (uint8_t *)p + *size;
+ *b = strlen(s);
+ p = p + *size + 1;
+ memcpy(p,s,strlen(s));
+ *size = *size + strlen(s) + 1;
+ response = 1;
+ }
+ }
+ return response;
+}
+
static void pkString_make(char *str, size_t str_size, const char *device_id) {
uint8_t public_key[32];
if (str_size < 2 * sizeof(public_key) + 1) {
@@ -1139,6 +1172,8 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
enum rtsp_read_request_response reply = rtsp_read_request_response_ok;
ssize_t buflen = 4096;
+ if ((config.metadata_enabled != 0) && (config.get_coverart != 0))
+ buflen = 1024 * 256; // big enough for typical picture data, which will be base64 encoded
int release_buffer = 0; // on exit, don't deallocate the buffer if everything was okay
char *buf = malloc(buflen + 1); // add a NUL at the end
if (!buf) {
@@ -1228,7 +1263,7 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
get_absolute_time_in_ns() + ((uint64_t)15000000000); // i.e. fifteen seconds from now
int warning_message_sent = 0;
- const size_t max_read_chunk = 1024 * 1024 / 16;
+ // const size_t max_read_chunk = 1024 * 1024 / 16;
while (inbuf < msg_size) {
// we are going to read the stream in chunks and time how long it takes to
@@ -1255,9 +1290,9 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
goto shutdown;
}
size_t read_chunk = msg_size - inbuf;
- if (read_chunk > max_read_chunk)
- read_chunk = max_read_chunk;
- usleep(80000); // wait about 80 milliseconds between reads of up to max_read_chunk
+ //if (read_chunk > max_read_chunk)
+ // read_chunk = max_read_chunk;
+ // usleep(80000); // wait about 80 milliseconds between reads of up to max_read_chunk
nread = read_from_rtsp_connection(conn, buf + inbuf, read_chunk);
if (!nread) {
reply = rtsp_read_request_response_error;
@@ -1476,7 +1511,7 @@ void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp)
void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *req,
rtsp_message *resp) {
-
+ debug_log_rtsp_message(2, "GET /info:", req);
if (rtsp_message_contains_plist(req)) { // it's stage one
// get version of AirPlay -- it might be too old. Not using it yet.
char *hdr = msg_get_header(req, "User-Agent");
@@ -1519,6 +1554,43 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
if (response_plist == NULL) {
debug(1, "GET /info Stage 1: response plist not created from XML!");
} else {
+ void *qualifier_response_data = NULL;
+ size_t qualifier_response_data_length = 0;
+ if (add_pstring_to_malloc("acl=0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc(deviceIdString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc(featuresString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("rsf=0x0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("flags=0x4", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("model=Shairport Sync", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("manufacturer=", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("serialNumber=", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("protovers=1.1", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("srcvers=366.0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc(piString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc(gidString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ if (add_pstring_to_malloc("gcgl=0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ snprintf(pkString, sizeof(pkString), "pk=");
+ pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="),
+ config.airplay_device_id);
+ if (add_pstring_to_malloc(pkString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ debug(1, "Problem");
+ // debug(1,"qualifier_response_data_length: %u.", qualifier_response_data_length);
+
+ plist_dict_set_item(response_plist, "txtAirPlay", plist_new_data(qualifier_response_data, qualifier_response_data_length));
+
plist_dict_set_item(response_plist, "features", plist_new_uint(config.airplay_features));
plist_dict_set_item(response_plist, "statusFlags",
plist_new_uint(config.airplay_statusflags));
@@ -1526,15 +1598,16 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
char *vs = get_version_string();
- plist_dict_set_item(response_plist, "model", plist_new_string(vs));
+// plist_dict_set_item(response_plist, "model", plist_new_string(vs));
+ plist_dict_set_item(response_plist, "model", plist_new_string("Shairport Sync"));
free(vs);
- char pkString[128];
- pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
- plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
+ //pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
+ //plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
plist_to_bin(response_plist, &resp->content, &resp->contentlength);
if (resp->contentlength == 0)
debug(1, "GET /info Stage 1: response bplist not created!");
plist_free(response_plist);
+ free(qualifier_response_data);
}
msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist");
debug_log_rtsp_message(2, "GET /info Stage 1 Response:", resp);
@@ -1554,11 +1627,11 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
char *vs = get_version_string();
- plist_dict_set_item(response_plist, "model", plist_new_string(vs));
+ // plist_dict_set_item(response_plist, "model", plist_new_string(vs));
+ plist_dict_set_item(response_plist, "model", plist_new_string("Shairport Sync"));
free(vs);
- char pkString[128];
- pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
- plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
+ // pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
+ // plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
plist_to_bin(response_plist, &resp->content, &resp->contentlength);
plist_free(response_plist);
msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist");
@@ -1702,12 +1775,12 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
}
uint64_t networkTimeSecs;
plist_get_uint_val(item, &networkTimeSecs);
- debug(2, "anchor networkTimeSecs is 0x%" PRIx64 ".", networkTimeSecs);
+ debug(2, "anchor networkTimeSecs is %" PRIu64 ".", networkTimeSecs);
item = plist_dict_get_item(messagePlist, "networkTimeFrac");
uint64_t networkTimeFrac;
plist_get_uint_val(item, &networkTimeFrac);
- debug(2, "anchor networkTimeFrac is 0x%" PRIx64 ".", networkTimeFrac);
+ debug(2, "anchor networkTimeFrac is 0%" PRIu64 ".", networkTimeFrac);
// it looks like the networkTimeFrac is a fraction where the msb is work 1/2, the
// next 1/4 and so on
// now, convert the network time and fraction into nanoseconds
@@ -1718,7 +1791,7 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message
networkTimeSecs = networkTimeSecs * 1000000000; // turn the whole seconds into ns
uint64_t anchorTimeNanoseconds = networkTimeSecs + networkTimeFrac;
- debug(2, "anchorTimeNanoseconds looks like 0x%" PRIx64 ".", anchorTimeNanoseconds);
+ debug(2, "anchorTimeNanoseconds looks like %" PRIu64 ".", anchorTimeNanoseconds);
item = plist_dict_get_item(messagePlist, "rtpTime");
uint64_t rtpTime;
@@ -2158,7 +2231,27 @@ void handle_configure(rtsp_conn_info *conn __attribute__((unused)),
void handle_feedback(__attribute__((unused)) rtsp_conn_info *conn,
__attribute__((unused)) rtsp_message *req,
- __attribute__((unused)) rtsp_message *resp) {}
+ __attribute__((unused)) rtsp_message *resp) {
+ /* not finished yet
+ plist_t payload_plist = plist_new_dict();
+ plist_dict_set_item(payload_plist, "type", plist_new_uint(103));
+ plist_dict_set_item(payload_plist, "sr", plist_new_real(44100.0));
+
+ plist_t array_plist = plist_new_array();
+ plist_array_append_item(array_plist, payload_plist);
+
+ plist_t response_plist = plist_new_dict();
+ plist_dict_set_item(response_plist, "streams",array_plist);
+
+ plist_to_bin(response_plist, &resp->content, &resp->contentlength);
+ plist_free(response_plist);
+ // plist_free(array_plist);
+ // plist_free(payload_plist);
+
+ msg_add_header(resp, "Content-Type", "application/x-apple-binary-plist");
+ debug_log_rtsp_message(2, "FEEDBACK response:", resp);
+ */
+}
void handle_command(__attribute__((unused)) rtsp_conn_info *conn, rtsp_message *req,
__attribute__((unused)) rtsp_message *resp) {
From 70821f81278abbf204ec9353b2808f8cad8bffec Mon Sep 17 00:00:00 2001
From: Mike Brady <4265913+mikebrady@users.noreply.github.com>
Date: Mon, 6 Dec 2021 18:45:25 +0000
Subject: [PATCH 13/13] Clang Format
---
player.c | 4 +-
rtp.c | 170 ++++++++++++++++++++++++++++---------------------------
rtsp.c | 75 ++++++++++++++----------
3 files changed, 133 insertions(+), 116 deletions(-)
diff --git a/player.c b/player.c
index da98c55b..6e1ee80d 100644
--- a/player.c
+++ b/player.c
@@ -384,8 +384,8 @@ void reset_buffer(rtsp_conn_info *conn) {
ab_resync(conn);
debug_mutex_unlock(&conn->ab_mutex, 0);
if (config.output->flush) {
- config.output->flush(); // no cancellation points
-// debug(1, "reset_buffer: flush output device.");
+ config.output->flush(); // no cancellation points
+ // debug(1, "reset_buffer: flush output device.");
}
}
diff --git a/rtp.c b/rtp.c
index d3bf06c4..f80e32ae 100644
--- a/rtp.c
+++ b/rtp.c
@@ -2255,14 +2255,14 @@ void *rtp_buffered_audio_processor(void *arg) {
int play_enabled = 0;
uint32_t flush_from_timestamp;
double requested_lead_time = 0.0; // normal lead time minimum -- maybe it should be about 0.1
-
+
// wait until our timing information is valid
-
+
// debug(1,"rtp_buffered_audio_processor ready.");
while (have_ptp_timing_information(conn) == 0)
usleep(1000);
-
- reset_buffer(conn); // in case there is any garbage in the player
+
+ reset_buffer(conn); // in case there is any garbage in the player
// int not_first_time_out = 0;
// quick check of parameters
@@ -2532,17 +2532,17 @@ void *rtp_buffered_audio_processor(void *arg) {
int64_t local_lead_time = 0;
int64_t requested_lead_time_ns = (int64_t)(requested_lead_time * 1000000000);
requested_lead_time_ns = (int64_t)(-300000000);
- int outdated = 0;
+ int outdated = 0;
if (have_time_information == 0) {
local_lead_time = local_should_be_time - get_absolute_time_in_ns();
outdated = (local_lead_time < requested_lead_time_ns);
// if (outdated != 0)
- // debug(1,"Frame is outdated %d if lead_time %" PRId64 " is less than requested lead time %" PRId64 " ns.", outdated, local_lead_time, requested_lead_time_ns);
+ // debug(1,"Frame is outdated %d if lead_time %" PRId64 " is less than requested lead time
+ // %" PRId64 " ns.", outdated, local_lead_time, requested_lead_time_ns);
} else {
- debug(1,"Timing information not valid");
+ debug(1, "Timing information not valid");
// outdated = 1;
}
-
if ((flush_requested) && (seq_no >= flushUntilSeq)) {
if ((have_time_information == 0) && (play_enabled)) {
@@ -2556,33 +2556,31 @@ void *rtp_buffered_audio_processor(void *arg) {
debug(2, "flush completed to seq: %u with rtptime: %u.", seq_no, timestamp);
}
}
-
- // if we are here because of a flush request, it must be the case that
- // flushing the pcm buffer wasn't enough, as the request would have been turned off by now
- // so we better indicate that the pcm buffer is empty and its contents invalid
-
- // also, if the incomgin frame is outdated, set pcm_buffer_occupancy to 0;
- if ((flush_requested) || (outdated)){
- pcm_buffer_occupancy = 0;
- }
- // decode the block and add it to or put it in the pcm buffer
+ // if we are here because of a flush request, it must be the case that
+ // flushing the pcm buffer wasn't enough, as the request would have been turned off by now
+ // so we better indicate that the pcm buffer is empty and its contents invalid
- if (pcm_buffer_occupancy == 0) {
- // they should match and the read point should be zero
- // if ((blocks_read != 0) && (pcm_buffer_read_point_rtptime != timestamp)) {
- // debug(2, "set pcm_buffer_read_point_rtptime from %u to %u.",
- // pcm_buffer_read_point_rtptime, timestamp);
- pcm_buffer_read_point_rtptime = timestamp;
- pcm_buffer_read_point = 0;
- //}
- }
+ // also, if the incomgin frame is outdated, set pcm_buffer_occupancy to 0;
+ if ((flush_requested) || (outdated)) {
+ pcm_buffer_occupancy = 0;
+ }
+ // decode the block and add it to or put it in the pcm buffer
+
+ if (pcm_buffer_occupancy == 0) {
+ // they should match and the read point should be zero
+ // if ((blocks_read != 0) && (pcm_buffer_read_point_rtptime != timestamp)) {
+ // debug(2, "set pcm_buffer_read_point_rtptime from %u to %u.",
+ // pcm_buffer_read_point_rtptime, timestamp);
+ pcm_buffer_read_point_rtptime = timestamp;
+ pcm_buffer_read_point = 0;
+ //}
+ }
if (((flush_requested != 0) && (seq_no == flushUntilSeq)) ||
((flush_requested == 0) && (new_buffer_needed))) {
-
unsigned char nonce[12];
memset(nonce, 0, sizeof(nonce));
memcpy(nonce + 4, packet + nread - 8,
@@ -2642,71 +2640,75 @@ void *rtp_buffered_audio_processor(void *arg) {
// debug(1, "frame found");
// now pass each packet to be decoded
if (pkt->size) {
- //if (0) {
+ // if (0) {
if (pkt->size <= 7) { // no idea about this...
- debug(1,"malformed AAC packet skipped.");
+ debug(1, "malformed AAC packet skipped.");
} else {
- ret = avcodec_send_packet(codec_context, pkt);
-
- if (ret < 0) {
- debug(1, "error sending frame %d of size %d to decoder, blocks_read: %u, blocks_read_since_flush: %u.", frame_within_block, pkt->size, blocks_read, blocks_read_since_flush);
- } else {
- while (ret >= 0) {
- ret = avcodec_receive_frame(codec_context, decoded_frame);
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
- break;
- else if (ret < 0) {
- debug(1, "error %d during decoding", ret);
- } else {
- av_samples_alloc(&pcm_audio, &dst_linesize, codec_context->channels,
- decoded_frame->nb_samples, av_format, 1);
- // remember to free pcm_audio
- ret = swr_convert(swr, &pcm_audio, decoded_frame->nb_samples,
- (const uint8_t **)decoded_frame->extended_data,
- decoded_frame->nb_samples);
- dst_bufsize = av_samples_get_buffer_size(
- &dst_linesize, codec_context->channels, ret, av_format, 1);
- // debug(1,"generated %d bytes of PCM", dst_bufsize);
- // copy the PCM audio into the PCM buffer.
- // make sure it's big enough first
+ ret = avcodec_send_packet(codec_context, pkt);
- // also, check it if needs to be truncated but to an impending delayed
- // flush_is_delayed
- if (flush_is_delayed) {
- // see if the flush_from_timestamp is in the buffer
- int32_t samples_remaining =
- (flush_from_timestamp - pcm_buffer_read_point_rtptime);
- if ((samples_remaining > 0) &&
- ((samples_remaining * conn->input_bytes_per_frame) < dst_bufsize)) {
- debug(2,
- "samples remaining before flush: %d, number of samples %d. "
- "flushFromTS: %u, pcm_buffer_read_point_rtptime: %u.",
- samples_remaining, dst_bufsize / conn->input_bytes_per_frame,
- flush_from_timestamp, pcm_buffer_read_point_rtptime);
- dst_bufsize = samples_remaining * conn->input_bytes_per_frame;
- }
- }
- if ((pcm_buffer_size - pcm_buffer_occupancy) < dst_bufsize) {
- debug(1,
- "pcm_buffer_read_point (frames): %u, pcm_buffer_occupancy "
- "(frames): %u",
- pcm_buffer_read_point / conn->input_bytes_per_frame,
- pcm_buffer_occupancy / conn->input_bytes_per_frame);
- pcm_buffer_size = dst_bufsize + pcm_buffer_occupancy;
- debug(1, "fatal error! pcm buffer too small at %d bytes.",
- pcm_buffer_size);
+ if (ret < 0) {
+ debug(1,
+ "error sending frame %d of size %d to decoder, blocks_read: %u, "
+ "blocks_read_since_flush: %u.",
+ frame_within_block, pkt->size, blocks_read, blocks_read_since_flush);
+ } else {
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(codec_context, decoded_frame);
+ if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
+ break;
+ else if (ret < 0) {
+ debug(1, "error %d during decoding", ret);
} else {
- memcpy(pcm_buffer + pcm_buffer_occupancy, pcm_audio, dst_bufsize);
- pcm_buffer_occupancy += dst_bufsize;
+ av_samples_alloc(&pcm_audio, &dst_linesize, codec_context->channels,
+ decoded_frame->nb_samples, av_format, 1);
+ // remember to free pcm_audio
+ ret = swr_convert(swr, &pcm_audio, decoded_frame->nb_samples,
+ (const uint8_t **)decoded_frame->extended_data,
+ decoded_frame->nb_samples);
+ dst_bufsize = av_samples_get_buffer_size(
+ &dst_linesize, codec_context->channels, ret, av_format, 1);
+ // debug(1,"generated %d bytes of PCM", dst_bufsize);
+ // copy the PCM audio into the PCM buffer.
+ // make sure it's big enough first
+
+ // also, check it if needs to be truncated but to an impending delayed
+ // flush_is_delayed
+ if (flush_is_delayed) {
+ // see if the flush_from_timestamp is in the buffer
+ int32_t samples_remaining =
+ (flush_from_timestamp - pcm_buffer_read_point_rtptime);
+ if ((samples_remaining > 0) &&
+ ((samples_remaining * conn->input_bytes_per_frame) <
+ dst_bufsize)) {
+ debug(2,
+ "samples remaining before flush: %d, number of samples %d. "
+ "flushFromTS: %u, pcm_buffer_read_point_rtptime: %u.",
+ samples_remaining, dst_bufsize / conn->input_bytes_per_frame,
+ flush_from_timestamp, pcm_buffer_read_point_rtptime);
+ dst_bufsize = samples_remaining * conn->input_bytes_per_frame;
+ }
+ }
+ if ((pcm_buffer_size - pcm_buffer_occupancy) < dst_bufsize) {
+ debug(1,
+ "pcm_buffer_read_point (frames): %u, pcm_buffer_occupancy "
+ "(frames): %u",
+ pcm_buffer_read_point / conn->input_bytes_per_frame,
+ pcm_buffer_occupancy / conn->input_bytes_per_frame);
+ pcm_buffer_size = dst_bufsize + pcm_buffer_occupancy;
+ debug(1, "fatal error! pcm buffer too small at %d bytes.",
+ pcm_buffer_size);
+ } else {
+ memcpy(pcm_buffer + pcm_buffer_occupancy, pcm_audio, dst_bufsize);
+ pcm_buffer_occupancy += dst_bufsize;
+ }
+ // debug(1,"decoded %d samples", decoded_frame->nb_samples);
+ // memcpy(sampleBuffer,outputBuffer16,dst_bufsize);
+ av_freep(&pcm_audio);
}
- // debug(1,"decoded %d samples", decoded_frame->nb_samples);
- // memcpy(sampleBuffer,outputBuffer16,dst_bufsize);
- av_freep(&pcm_audio);
}
}
}
}
- }
}
if (decoded_frame == NULL)
debug(1, "decoded_frame is NULL");
diff --git a/rtsp.c b/rtsp.c
index 6c0da18f..177a4b81 100644
--- a/rtsp.c
+++ b/rtsp.c
@@ -197,8 +197,8 @@ int add_pstring_to_malloc(const char *s, void **allocation, size_t *size) {
*size = *size + strlen(s) + 1;
uint8_t *b = (uint8_t *)p;
*b = strlen(s);
- p = p+1;
- memcpy(p,s,strlen(s));
+ p = p + 1;
+ memcpy(p, s, strlen(s));
response = 1;
}
} else {
@@ -210,7 +210,7 @@ int add_pstring_to_malloc(const char *s, void **allocation, size_t *size) {
uint8_t *b = (uint8_t *)p + *size;
*b = strlen(s);
p = p + *size + 1;
- memcpy(p,s,strlen(s));
+ memcpy(p, s, strlen(s));
*size = *size + strlen(s) + 1;
response = 1;
}
@@ -1173,8 +1173,8 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
enum rtsp_read_request_response reply = rtsp_read_request_response_ok;
ssize_t buflen = 4096;
if ((config.metadata_enabled != 0) && (config.get_coverart != 0))
- buflen = 1024 * 256; // big enough for typical picture data, which will be base64 encoded
- int release_buffer = 0; // on exit, don't deallocate the buffer if everything was okay
+ buflen = 1024 * 256; // big enough for typical picture data, which will be base64 encoded
+ int release_buffer = 0; // on exit, don't deallocate the buffer if everything was okay
char *buf = malloc(buflen + 1); // add a NUL at the end
if (!buf) {
warn("Connection %d: rtsp_read_request: can't get a buffer.", conn->connection_number);
@@ -1290,7 +1290,7 @@ enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn, rtsp_mes
goto shutdown;
}
size_t read_chunk = msg_size - inbuf;
- //if (read_chunk > max_read_chunk)
+ // if (read_chunk > max_read_chunk)
// read_chunk = max_read_chunk;
// usleep(80000); // wait about 80 milliseconds between reads of up to max_read_chunk
nread = read_from_rtsp_connection(conn, buf + inbuf, read_chunk);
@@ -1556,41 +1556,56 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
} else {
void *qualifier_response_data = NULL;
size_t qualifier_response_data_length = 0;
- if (add_pstring_to_malloc("acl=0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("acl=0", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc(deviceIdString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc(deviceIdString, &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc(featuresString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc(featuresString, &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("rsf=0x0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("rsf=0x0", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("flags=0x4", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("flags=0x4", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("model=Shairport Sync", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("model=Shairport Sync", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("manufacturer=", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("manufacturer=", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("serialNumber=", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("serialNumber=", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("protovers=1.1", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("protovers=1.1", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("srcvers=366.0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("srcvers=366.0", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc(piString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc(piString, &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc(gidString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc(gidString, &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
- if (add_pstring_to_malloc("gcgl=0", &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc("gcgl=0", &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
snprintf(pkString, sizeof(pkString), "pk=");
pkString_make(pkString + strlen("pk="), sizeof(pkString) - strlen("pk="),
config.airplay_device_id);
- if (add_pstring_to_malloc(pkString, &qualifier_response_data, &qualifier_response_data_length) == 0)
+ if (add_pstring_to_malloc(pkString, &qualifier_response_data,
+ &qualifier_response_data_length) == 0)
debug(1, "Problem");
// debug(1,"qualifier_response_data_length: %u.", qualifier_response_data_length);
-
- plist_dict_set_item(response_plist, "txtAirPlay", plist_new_data(qualifier_response_data, qualifier_response_data_length));
-
+
+ plist_dict_set_item(response_plist, "txtAirPlay",
+ plist_new_data(qualifier_response_data, qualifier_response_data_length));
+
plist_dict_set_item(response_plist, "features", plist_new_uint(config.airplay_features));
plist_dict_set_item(response_plist, "statusFlags",
plist_new_uint(config.airplay_statusflags));
@@ -1598,11 +1613,11 @@ void handle_get_info(__attribute((unused)) rtsp_conn_info *conn, rtsp_message *r
plist_dict_set_item(response_plist, "pi", plist_new_string(config.airplay_pi));
plist_dict_set_item(response_plist, "name", plist_new_string(config.service_name));
char *vs = get_version_string();
-// plist_dict_set_item(response_plist, "model", plist_new_string(vs));
+ // plist_dict_set_item(response_plist, "model", plist_new_string(vs));
plist_dict_set_item(response_plist, "model", plist_new_string("Shairport Sync"));
free(vs);
- //pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
- //plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
+ // pkString_make(pkString, sizeof(pkString), config.airplay_device_id);
+ // plist_dict_set_item(response_plist, "pk", plist_new_string(pkString));
plist_to_bin(response_plist, &resp->content, &resp->contentlength);
if (resp->contentlength == 0)
debug(1, "GET /info Stage 1: response bplist not created!");
@@ -2236,14 +2251,14 @@ void handle_feedback(__attribute__((unused)) rtsp_conn_info *conn,
plist_t payload_plist = plist_new_dict();
plist_dict_set_item(payload_plist, "type", plist_new_uint(103));
plist_dict_set_item(payload_plist, "sr", plist_new_real(44100.0));
-
+
plist_t array_plist = plist_new_array();
plist_array_append_item(array_plist, payload_plist);
-
+
plist_t response_plist = plist_new_dict();
plist_dict_set_item(response_plist, "streams",array_plist);
-
- plist_to_bin(response_plist, &resp->content, &resp->contentlength);
+
+ plist_to_bin(response_plist, &resp->content, &resp->contentlength);
plist_free(response_plist);
// plist_free(array_plist);
// plist_free(payload_plist);