]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
works in AP1-compatible AP2 mode, but resend isn't working.
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 2 May 2021 11:49:41 +0000 (12:49 +0100)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Sun, 2 May 2021 11:49:41 +0000 (12:49 +0100)
player.c
player.h
rtp.c
rtsp.c

index 6b67ee1331e11b01613361875e24f9e2ae7062d7..7d6d026e5ea38dbf3cd429e88f15b0722570174e 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1922,11 +1922,17 @@ void *player_thread_func(void *arg) {
     }
   }
 
-#ifndef CONFIG_AIRPLAY_2
+#ifdef CONFIG_AIRPLAY_2
+  if (conn->timing_type == ts_ntp) {
+#endif
+
   // create and start the timing, control and audio receiver threads
   pthread_create(&conn->rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)conn);
   pthread_create(&conn->rtp_control_thread, NULL, &rtp_control_receiver, (void *)conn);
   pthread_create(&conn->rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)conn);
+
+#ifdef CONFIG_AIRPLAY_2
+  }
 #endif
 
   pthread_cleanup_push(player_thread_cleanup_handler, arg); // undo what's been done so far
index 9a92c0c4ff6f2e703d592315f7ab7815192e7ec2..5766f6fc5a0469e7eaff470fc43cbf72a029f30c 100644 (file)
--- a/player.h
+++ b/player.h
@@ -81,7 +81,6 @@ typedef enum {
   ast_apple_lossless,
 } audio_stream_type;
 
-typedef enum { ts_ntp, ts_ptp } timing_source_type;
 
 typedef struct {
   int encrypted;
@@ -91,6 +90,9 @@ typedef struct {
 } stream_cfg;
 
 #ifdef CONFIG_AIRPLAY_2
+typedef enum { ts_ntp, ts_ptp } timing_t;
+typedef enum { ap_1, ap_2 } airplay_t;
+
 typedef struct file_cipher_context {
   struct pair_cipher_context *cipher_context;
   int active; // can be created during a pair setup but not activated until next read
@@ -103,7 +105,6 @@ typedef struct file_cipher_context {
 
 typedef struct {
   int connection_number;             // for debug ID purposes, nothing else...
-  timing_source_type type_of_timing; // are we using NTP or PTP?
   int resend_interval;               // this is really just for debugging
   char *UserAgent;                   // free this on teardown
   int AirPlayVersion;        // zero if not an AirPlay session. Used to help calculate latency
@@ -240,6 +241,9 @@ typedef struct {
   uint32_t anchor_rtptime;
 
 #ifdef CONFIG_AIRPLAY_2
+  airplay_t airplay_type; // are we using AirPlay 1 or AirPlay 2 protocol on this connection?
+  timing_t timing_type; // are we using NTP or PTP on this connection?
+
   pthread_t rtp_event_thread;
   pthread_t rtp_ap2_control_thread;
   pthread_t rtp_realtime_audio_thread;
diff --git a/rtp.c b/rtp.c
index 35e415a9498a4aaf9450630d9a01d92925e0ac00..5016654367da27318e96fd636a40a0aadc46bd8c 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -120,6 +120,7 @@ void rtp_audio_receiver_cleanup_handler(__attribute__((unused)) void *arg) {
 }
 
 void *rtp_audio_receiver(void *arg) {
+  debug(1,"rtp_audio_receiver start");
   pthread_cleanup_push(rtp_audio_receiver_cleanup_handler, arg);
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
 
@@ -258,6 +259,7 @@ void rtp_control_handler_cleanup_handler(__attribute__((unused)) void *arg) {
 }
 
 void *rtp_control_receiver(void *arg) {
+  debug(1,"rtp_control_receiver start");
   pthread_cleanup_push(rtp_control_handler_cleanup_handler, arg);
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
 
@@ -288,8 +290,8 @@ void *rtp_control_receiver(void *arg) {
                                                                 obfp += 2;
                                                               };
                                                               *obfp = 0;
-                                             
-                                             
+
+
                                                               // get raw timestamp information
                                                               // I think that a good way to understand these timestamps is that
                                                               // (1) the rtlt below is the timestamp of the frame that should be playing at the
@@ -300,19 +302,19 @@ void *rtp_control_receiver(void *arg) {
                                                               // Thus, (3) the latency can be calculated by subtracting the second from the
                                                               // first.
                                                               // There must be more to it -- there something missing.
-                                             
+
                                                               // In addition, it seems that if the value of the short represented by the second
                                                               // pair of bytes in the packet is 7
                                                               // then an extra time lag is expected to be added, presumably by
                                                               // the AirPort Express.
-                                             
+
                                                               // Best guess is that this delay is 11,025 frames.
-                                             
+
                                                               uint32_t rtlt = nctohl(&packet[4]); // raw timestamp less latency
                                                               uint32_t rt = nctohl(&packet[16]);  // raw timestamp
-                                             
+
                                                               uint32_t fl = nctohs(&packet[2]); //
-                                             
+
                                                               debug(1,"Sync Packet of %d bytes received: \"%s\", flags: %d, timestamps %u and %u,
                                                           giving a latency of %d frames.",plen,obf,fl,rt,rtlt,rt-rtlt);
                                                               //debug(1,"Monotonic timestamps are: %" PRId64 " and %" PRId64 "
@@ -506,6 +508,7 @@ void rtp_timing_sender_cleanup_handler(void *arg) {
 }
 
 void *rtp_timing_sender(void *arg) {
+  debug(1,"rtp_timing_sender start");
   pthread_cleanup_push(rtp_timing_sender_cleanup_handler, arg);
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
   struct timing_request {
@@ -607,6 +610,7 @@ void rtp_timing_receiver_cleanup_handler(void *arg) {
 }
 
 void *rtp_timing_receiver(void *arg) {
+  debug(1,"rtp_timing_receiver start");
   pthread_cleanup_push(rtp_timing_receiver_cleanup_handler, arg);
   rtsp_conn_info *conn = (rtsp_conn_info *)arg;
 
@@ -672,7 +676,7 @@ void *rtp_timing_receiver(void *arg) {
         if (packet[1] == 0xd3) { // timing reply
 
           return_time = arrival_time - conn->departure_time;
-          debug(3, "clock synchronisation request: return time is %8.3f milliseconds.",
+          debug(1, "clock synchronisation request: return time is %8.3f milliseconds.",
                 0.000001 * return_time);
 
           if (return_time < 200000000) { // must be less than 0.2 seconds
@@ -2358,20 +2362,35 @@ void *rtp_buffered_audio_processor(void *arg) {
   pthread_exit(NULL);
 }
 int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn) {
-  return frame_to_ptp_local_time(timestamp, time, conn);
+  if (conn->timing_type == ts_ptp)
+    return frame_to_ptp_local_time(timestamp, time, conn);
+  else
+    return frame_to_ntp_local_time(timestamp, time, conn);
 }
 
 int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn) {
-  return local_ptp_time_to_frame(time, frame, conn);
+  if (conn->timing_type == ts_ptp)
+    return local_ptp_time_to_frame(time, frame, conn);
+  else
+    return local_ntp_time_to_frame(time, frame, conn);
 }
 
-void reset_anchor_info(rtsp_conn_info *conn) { reset_ptp_anchor_info(conn); }
+void reset_anchor_info(rtsp_conn_info *conn) {
+  if (conn->timing_type == ts_ptp)
+    reset_ptp_anchor_info(conn);
+  else
+    reset_ntp_anchor_info(conn);
+}
 
 int have_timestamp_timing_information(rtsp_conn_info *conn) {
-  return have_ptp_timing_information(conn);
+  if (conn->timing_type == ts_ptp)
+    return have_ptp_timing_information(conn);
+  else
+    return have_ntp_timestamp_timing_information(conn);
 }
 
 #else
+
 int frame_to_local_time(uint32_t timestamp, uint64_t *time, rtsp_conn_info *conn) {
   return frame_to_ntp_local_time(timestamp, time, conn);
 }
diff --git a/rtsp.c b/rtsp.c
index 41ddff2265ecbef4a2b668f18a37a1eded1d79ed..962a76266c3d9e6b65cebe394f1c04cf39fd7f3f 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -2090,7 +2090,7 @@ void handle_options(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *
                  "OPTIONS, GET_PARAMETER, SET_PARAMETER, GET");
 }
 
-void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
+void handle_teardown_2(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
                      rtsp_message *resp) {
   debug(2, "Connection %d: TEARDOWN", conn->connection_number);
 
@@ -2198,8 +2198,8 @@ void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message
     resp->respcode = 451; // don't know what to do here
   }
 }
+#endif
 
-#else
 void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message *req,
                      rtsp_message *resp) {
   debug_log_rtsp_message(2, "TEARDOWN request", req);
@@ -2220,7 +2220,7 @@ void handle_teardown(rtsp_conn_info *conn, __attribute__((unused)) rtsp_message
     resp->respcode = 451;
   }
 }
-#endif
+
 
 void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
   // TODO -- don't know what this is for in AP2
@@ -3571,6 +3571,11 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag
       }
     }
     */
+    // In AirPlay 2, an ANNOUNCE signifies the start of an AirPlay 1 session.
+#ifdef CONFIG_AIRPLAY_2
+    conn->airplay_type = ap_1;
+    conn->timing_type = ts_ntp;
+#endif
 
     conn->stream.type = ast_unknown;
     resp->respcode = 456; // 456 - Header Field Not Valid for Resource
@@ -3788,34 +3793,39 @@ out:
   }
 }
 
+#ifdef CONFIG_AIRPLAY_2
+static struct method_handler {
+  char *method;
+  void (*ap1_handler)(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp); // for AirPlay 1
+  void (*ap2_handler)(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp); // for AirPlay 2
+} method_handlers[] = {{"OPTIONS", handle_options, handle_options},
+                       {"ANNOUNCE", handle_announce, handle_announce},
+                       {"FLUSH", handle_flush, handle_flush},
+                       {"TEARDOWN", handle_teardown, handle_teardown_2},
+                       {"SETUP", handle_setup, handle_setup_2},
+                       {"GET_PARAMETER", handle_get_parameter, handle_get_parameter},
+                       {"SET_PARAMETER", handle_set_parameter, handle_set_parameter},
+                       {"RECORD", handle_record, handle_record_2},
+                       {"GET", handle_get, handle_get},
+                       {"POST", handle_post, handle_post},
+                       {"SETPEERS", handle_setpeers, handle_setpeers},
+                       {"SETRATEANCHORTI", handle_setrateanchori, handle_setrateanchori},
+                       {"FLUSHBUFFERED", handle_flushbuffered, handle_flushbuffered},
+                       {NULL, NULL, NULL}};
+#else
 static struct method_handler {
   char *method;
-  void (*handler)(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp);
+  void (*handler)(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp); // for AirPlay 1 only
 } method_handlers[] = {{"OPTIONS", handle_options},
                        {"ANNOUNCE", handle_announce},
                        {"FLUSH", handle_flush},
                        {"TEARDOWN", handle_teardown},
-#ifdef CONFIG_AIRPLAY_2
-                       {"SETUP", handle_setup_2},
-#else
                        {"SETUP", handle_setup},
-#endif
                        {"GET_PARAMETER", handle_get_parameter},
                        {"SET_PARAMETER", handle_set_parameter},
-#ifdef CONFIG_AIRPLAY_2
-                       {"RECORD", handle_record_2},
-#else
                        {"RECORD", handle_record},
-#endif
-#ifdef CONFIG_AIRPLAY_2
-
-                       {"GET", handle_get},
-                       {"POST", handle_post},
-                       {"SETPEERS", handle_setpeers},
-                       {"SETRATEANCHORTI", handle_setrateanchori},
-                       {"FLUSHBUFFERED", handle_flushbuffered},
-#endif
                        {NULL, NULL}};
+#endif
 
 static void apple_challenge(int fd, rtsp_message *req, rtsp_message *resp) {
   char *hdr = msg_get_header(req, "Apple-Challenge");
@@ -4247,7 +4257,14 @@ static void *rtsp_conversation_thread_func(void *pconn) {
         for (mh = method_handlers; mh->method; mh++) {
           if (!strcmp(mh->method, req->method)) {
             method_selected = 1;
+#ifdef CONFIG_AIRPLAY_2
+            if (conn->airplay_type == ap_1)
+              mh->ap1_handler(conn, req, resp);
+            else
+              mh->ap2_handler(conn, req, resp);
+#else
             mh->handler(conn, req, resp);
+#endif
             break;
           }
         }
@@ -4613,6 +4630,11 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
         die("Couldn't allocate memory for an rtsp_conn_info record.");
       memset(conn, 0, sizeof(rtsp_conn_info));
       conn->connection_number = RTSP_connection_index++;
+#ifdef CONFIG_AIRPLAY_2
+      conn->airplay_type = ap_2; // changed if an ANNOUNCE is received
+      conn->timing_type = ts_ptp; // changed if an ANNOUNCE is received
+#endif
+
 
       socklen_t size_of_reply = sizeof(SOCKADDR);
       conn->fd = accept(acceptfd, (struct sockaddr *)&conn->remote, &size_of_reply);