From: Mike Brady <4265913+mikebrady@users.noreply.github.com> Date: Thu, 19 Jan 2023 14:32:32 +0000 (+0000) Subject: Add modifications for V9 of the nqptp interface. X-Git-Tag: 4.2.1d0~39 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6eb70eee70097482e03c38cf8b8cb1c4c75f696f;p=thirdparty%2Fshairport-sync.git Add modifications for V9 of the nqptp interface. --- diff --git a/nqptp-shm-structures.h b/nqptp-shm-structures.h index 3dbe0c90..251d06c1 100644 --- a/nqptp-shm-structures.h +++ b/nqptp-shm-structures.h @@ -22,26 +22,36 @@ #define NQPTP_INTERFACE_NAME "/nqptp" -#define NQPTP_SHM_STRUCTURES_VERSION 8 +#define NQPTP_SHM_STRUCTURES_VERSION 9 #define NQPTP_CONTROL_PORT 9000 -// The control port expects a UDP packet with the first space-delimited string -// being the name of the shared memory interface (SMI) to be used. -// This allows client applications to have a dedicated named SMI interface with -// a timing peer list independent of other clients. -// The name given must be a valid SMI name and must contain no spaces. -// If the named SMI interface doesn't exist it will be created by NQPTP. -// The SMI name should be delimited by a space and followed by a command letter. -// At present, the only command is "T", which must followed by nothing or by -// a space and a space-delimited list of IPv4 or IPv6 numbers, -// the whole not to exceed 4096 characters in total. +// The control port expects a UDP packet with the first character being a command letter +// and the rest being any arguments, the whole not to exceed 4096 characters. +// The "T" command, must followed by nothing or by +// a space and a space-delimited list of IPv4 or IPv6 numbers. // The IPs, if provided, will become the new list of timing peers, replacing any -// previous list. If the master clock of the new list is the same as that of the old list, -// the master clock is retained without resynchronisation; this means that non-master -// devices can be added and removed without disturbing the SMI's existing master clock. +// previous list. The first IP number is the clock that NQPTP will listen to. +// The remaining IP address are the addresses of all the timing peers. The timing peers +// are not used in this version of NQPTP. // If no timing list is provided, the existing timing list is deleted. -// (In future version of NQPTP the SMI interface may also be deleted at this point.) -// SMI interfaces are not currently deleted or garbage collected. +// The "B" command is a message that the client -- which generates the clock -- +// is about to start playing. +// NQPTP uses it to determine that the clock is active and will not sleep. +// The "E" command signifies that the client has stopped playing and that +// the clock may shortly sleep. +// The "P" command signifies that SPS has paused play (buffered audio only). +// The clock seems to stay running in this state. + +// When the clock is active, it is assumed that any decreases in the offset +// between the local and remote clocks are due to delays in the network. +// NQPTP smooths the offset by clamping any decreases to a small value. +// In this way, it can follow clock drift but ignore network delays. + +// When the clock is inactive, it can stop running. This causes the offset to decrease. +// NQPTP clock smoothing would treat this as a network delay, causing true sync to be lost. +// To avoid this, when the clock goes from inactive to active, +// NQPTP resets clock smoothing to the new offset. + #include #include diff --git a/player.c b/player.c index 84f0a9e4..9d52c6ec 100644 --- a/player.c +++ b/player.c @@ -3606,6 +3606,9 @@ int player_stop(rtsp_conn_info *conn) { // debuglev = 3; debug(3, "player_stop"); if (conn->player_thread) { +#ifdef CONFIG_AIRPLAY_2 + ptp_send_control_message_string("E"); // signify play is "E"nding +#endif debug(3, "player_thread cancel..."); pthread_cancel(*conn->player_thread); debug(3, "player_thread join..."); diff --git a/rtsp.c b/rtsp.c index 83ee0261..55220b75 100644 --- a/rtsp.c +++ b/rtsp.c @@ -2022,6 +2022,7 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message pthread_cleanup_push(mutex_unlock, &conn->flush_mutex); conn->ap2_rate = rate; if ((rate & 1) != 0) { + ptp_send_control_message_string("B"); // signify play is "B"eginning or resuming debug(2, "Connection %d: Start playing, with anchor clock %" PRIx64 ".", conn->connection_number, conn->networkTimeTimelineID); activity_monitor_signify_activity(1); @@ -2031,7 +2032,8 @@ void handle_setrateanchori(rtsp_conn_info *conn, rtsp_message *req, rtsp_message #endif conn->ap2_play_enabled = 1; } else { - debug(2, "Connection %d: Stop playing.", conn->connection_number); + ptp_send_control_message_string("P"); // signify play is "P"ausing + debug(2, "Connection %d: Pause playing.", conn->connection_number); conn->ap2_play_enabled = 0; activity_monitor_signify_activity(0); reset_anchor_info(conn); @@ -2955,6 +2957,7 @@ void handle_setup_2(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) // if it's a full service PTP stream, we get groupUUID, groupContainsGroupLeader and // timingPeerList if (conn->airplay_stream_category == ptp_stream) { + ptp_send_control_message_string("B"); // signify play is "B"eginning if (ptp_shm_interface_open() != 0) // it should be open already, but just in case it isn't... die("Can not access the NQPTP service. Has it stopped running?");