From 5f564556c9500bfbf9f49f24c9c948853f4eda7b Mon Sep 17 00:00:00 2001
From: "F. Duncanh"
Date: Wed, 8 Feb 2023 01:31:44 -0500
Subject: [PATCH] add a -sync option to activate server-client sync in
audio-only mode
---
README.html | 18 ++++++++++++++++--
README.md | 14 +++++++++++++-
README.txt | 19 +++++++++++++++++--
renderers/audio_renderer.h | 2 +-
renderers/audio_renderer_gstreamer.c | 8 ++++++--
uxplay.1 | 3 ++-
uxplay.cpp | 7 +++++--
7 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/README.html b/README.html
index ca77351..d007c0a 100644
--- a/README.html
+++ b/README.html
@@ -394,6 +394,15 @@ client drops the connection; since UxPlay-1.58, the option
-nohold modifies this behavior so that when a new client
requests a connection, it removes the current client and takes
over.
+Since UxPlay-1.54, you can display the accompanying “Cover Art”
from sources like Apple Music in Audio-Only (ALAC) mode: run
“uxplay -ca <name> &” in the background, then run
@@ -680,6 +689,12 @@ the mirror display (X11) window.
-nh Do not append “@_hostname_” at the end of the AirPlay
server name.
+-sync (In Audio-Only (ALAC)) mode: this option
+synchronizes audio on the server with video on the client, but causes
+the client to add a delay to account for latency, so pausing the stream
+will not take effect immediately. This can be mitigated by using the
+-al audio latency setting to change the latency (default
+0.25 secs) that the server reports to the cient.
-s wxh (e.g. -s 1920x1080 , which is the default )
sets the display resolution (width and height, in pixels). (This may be
a request made to the AirPlay client, and perhaps will not be the final
@@ -780,8 +795,7 @@ in (decimal) seconds in Audio-only (ALAC), that is reported to the
client. Values in the range [0.0, 10.0] seconds are allowed, and will be
converted to a whole number of microseconds. Default is 0.25 sec (250000
usec). (This replaces the -ao option introduced in v1.62,
-as a workaround for a problem that is now fixed: it is not clear if
-changing the value of x produces any effects, however.)
+as a workaround for a problem that is now fixed).
-ca filename provides a file (where
filename can include a full path) used for output of “cover
art” (from Apple Music, etc.,) in audio-only ALAC mode. This
diff --git a/README.md b/README.md
index ff0b3a8..d4c388d 100644
--- a/README.md
+++ b/README.md
@@ -333,6 +333,12 @@ per second. (You can see what framerate is actually streaming by using -vs fpsdi
its current client until that client drops the connection; since UxPlay-1.58, the option `-nohold` modifies this
behavior so that when a new client requests a connection, it removes the current client and takes over.
+* In Audio-Only mode, use the `-sync` option to synchronize audio on the server with video
+on the client. This introduces a delay that the client adds to account for latency. There is an
+option `-al x` that sets the audio latency _x_ that the server reports to the client that in principle
+might modify the delay a little (this is not clear). Here (non-negative decimal) _x_ is given in seconds, default
+is 0.25. _Without the `-sync` option, there is no audio delay, but the client's video lags behind the server's audio._
+
* Since UxPlay-1.54, you can display the accompanying "Cover Art" from sources like Apple Music in Audio-Only (ALAC) mode:
run "`uxplay -ca &`" in the background, then run a image viewer with an autoreload feature: an example
is "feh": run "``feh -R 1 ``"
@@ -566,6 +572,12 @@ Options:
**-nh** Do not append "@_hostname_" at the end of the AirPlay server name.
+**-sync** (In Audio-Only (ALAC)) mode: this option synchronizes audio on the server with video on the client,
+ but causes the client to add a delay to account for latency, so pausing the stream will not take effect
+ immediately. This can be mitigated by using the `-al` audio latency setting to change the latency (default 0.25 secs)
+ that the server reports to the cient.
+
+
**-s wxh** (e.g. -s 1920x1080 , which is the default ) sets the display resolution (width and height,
in pixels). (This may be a
request made to the AirPlay client, and perhaps will not
@@ -660,7 +672,7 @@ which will not work if a firewall is running.
**-al _x_** specifies an audio latency _x_ in (decimal) seconds in Audio-only (ALAC), that is reported to the client. Values
in the range [0.0, 10.0] seconds are allowed, and will be converted to a whole number of microseconds. Default
is 0.25 sec (250000 usec). (This replaces the `-ao` option introduced in v1.62, as a workaround for a problem that
- is now fixed: it is not clear if changing the value of _x_ produces any effects, however.)
+ is now fixed).
**-ca _filename_** provides a file (where _filename_ can include a full path) used for output of "cover art"
(from Apple Music, _etc._,) in audio-only ALAC mode. This file is overwritten with the latest cover art as
diff --git a/README.txt b/README.txt
index 6bf3857..9399e60 100644
--- a/README.txt
+++ b/README.txt
@@ -397,6 +397,15 @@ for help with this or other problems.
modifies this behavior so that when a new client requests a
connection, it removes the current client and takes over.
+- In Audio-Only mode, use the `-sync` option to synchronize audio on
+ the server with video on the client. This introduces a delay that
+ the client adds to account for latency. There is an option `-al x`
+ that sets the audio latency *x* that the server reports to the
+ client that in principle might modify the delay a little (this is
+ not clear). Here (non-negative decimal) *x* is given in seconds,
+ default is 0.25. *Without the `-sync` option, there is no audio
+ delay, but the client's video lags behind the server's audio.*
+
- Since UxPlay-1.54, you can display the accompanying "Cover Art" from
sources like Apple Music in Audio-Only (ALAC) mode: run
"`uxplay -ca &`" in the background, then run a image viewer
@@ -691,6 +700,13 @@ will also now be the name shown above the mirror display (X11) window.
**-nh** Do not append "@_hostname_" at the end of the AirPlay server
name.
+**-sync** (In Audio-Only (ALAC)) mode: this option synchronizes audio on
+the server with video on the client, but causes the client to add a
+delay to account for latency, so pausing the stream will not take effect
+immediately. This can be mitigated by using the `-al` audio latency
+setting to change the latency (default 0.25 secs) that the server
+reports to the cient.
+
**-s wxh** (e.g. -s 1920x1080 , which is the default ) sets the display
resolution (width and height, in pixels). (This may be a request made to
the AirPlay client, and perhaps will not be the final resolution you
@@ -801,8 +817,7 @@ Audio-only (ALAC), that is reported to the client. Values in the range
\[0.0, 10.0\] seconds are allowed, and will be converted to a whole
number of microseconds. Default is 0.25 sec (250000 usec). (This
replaces the `-ao` option introduced in v1.62, as a workaround for a
-problem that is now fixed: it is not clear if changing the value of *x*
-produces any effects, however.)
+problem that is now fixed).
**-ca *filename*** provides a file (where *filename* can include a full
path) used for output of "cover art" (from Apple Music, *etc.*,) in
diff --git a/renderers/audio_renderer.h b/renderers/audio_renderer.h
index adeea75..6481eb1 100644
--- a/renderers/audio_renderer.h
+++ b/renderers/audio_renderer.h
@@ -30,7 +30,7 @@ extern "C" {
#include "../lib/logger.h"
bool gstreamer_init();
-void audio_renderer_init(logger_t *logger, const char* audiosink);
+void audio_renderer_init(logger_t *logger, const char* audiosink, const bool *audio_sync);
void audio_renderer_start(unsigned char* compression_type);
void audio_renderer_stop();
void audio_renderer_render_buffer(unsigned char* data, int *data_len, unsigned short *seqnum, uint64_t *ntp_time);
diff --git a/renderers/audio_renderer_gstreamer.c b/renderers/audio_renderer_gstreamer.c
index 239bc16..d1760dd 100644
--- a/renderers/audio_renderer_gstreamer.c
+++ b/renderers/audio_renderer_gstreamer.c
@@ -82,7 +82,7 @@ static GstClockTime gst_audio_pipeline_base_time = GST_CLOCK_TIME_NONE;
static logger_t *logger = NULL;
const char * format[NFORMATS];
-void audio_renderer_init(logger_t *render_logger, const char* audiosink) {
+void audio_renderer_init(logger_t *render_logger, const char* audiosink, const bool* audio_sync) {
GError *error = NULL;
GstCaps *caps = NULL;
GstClock *clock = gst_system_clock_obtain();
@@ -114,7 +114,11 @@ void audio_renderer_init(logger_t *render_logger, const char* audiosink) {
g_string_append (launch, audiosink);
switch(i) {
case 1: /*ALAC*/
- g_string_append (launch, " sync=true");
+ if (*audio_sync) {
+ g_string_append (launch, " sync=true");
+ } else {
+ g_string_append (launch, " sync=false");
+ }
break;
default:
g_string_append (launch, " sync=false");
diff --git a/uxplay.1 b/uxplay.1
index f91280f..60a8125 100644
--- a/uxplay.1
+++ b/uxplay.1
@@ -13,7 +13,8 @@ UxPlay 1.63: An open\-source AirPlay mirroring (+ audio streaming) server.
.TP
\fB\-nh\fR Do \fBNOT\fR append "@\fIhostname\fR" at end of the AirPlay server name
.TP
-.B
+\fB\-sync\fR (In Audio-Only mode) sync audio on server with video on client.
+.TP
\fB\-s\fR wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]
.TP
\fB\-o\fR Set display "overscanned" mode on (not usually needed)
diff --git a/uxplay.cpp b/uxplay.cpp
index e97a4fd..a63eb9f 100644
--- a/uxplay.cpp
+++ b/uxplay.cpp
@@ -65,7 +65,7 @@ static std::string server_name = DEFAULT_NAME;
static dnssd_t *dnssd = NULL;
static raop_t *raop = NULL;
static logger_t *render_logger = NULL;
-
+static bool audio_sync = false;
static bool relaunch_video = false;
static bool reset_loop = false;
static unsigned int open_connections= 0;
@@ -359,6 +359,7 @@ static void print_info (char *name) {
printf("Options:\n");
printf("-n name Specify the network name of the AirPlay server\n");
printf("-nh Do not add \"@hostname\" at the end of the AirPlay server name\n");
+ printf("-sync (In Audio-Only mode) sync audio on server with video on client\n");
printf("-s wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]\n");
printf("-o Set display \"overscanned\" mode on (not usually needed)\n");
printf("-fs Full-screen (only works with X11, Wayland and VAAPI)\n");
@@ -552,6 +553,8 @@ static void parse_arguments (int argc, char *argv[]) {
server_name = std::string(argv[++i]);
} else if (arg == "-nh") {
do_append_hostname = false;
+ } else if (arg == "-sync") {
+ audio_sync = true;
} else if (arg == "-s") {
if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1);
std::string value(argv[++i]);
@@ -1280,7 +1283,7 @@ int main (int argc, char *argv[]) {
logger_set_level(render_logger, debug_log ? LOGGER_DEBUG : LOGGER_INFO);
if (use_audio) {
- audio_renderer_init(render_logger, audiosink.c_str());
+ audio_renderer_init(render_logger, audiosink.c_str(), &audio_sync);
} else {
LOGI("audio_disabled");
}