mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
v1.63: fix audio sync with client video in Audio-only mode
This commit is contained in:
42
README.html
42
README.html
@@ -1,6 +1,6 @@
|
||||
<h1
|
||||
id="uxplay-1.62-airplay-mirror-and-airplay-audio-server-for-linux-macos-and-unix-now-also-runs-on-windows.">UxPlay
|
||||
1.62: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix
|
||||
id="uxplay-1.63-airplay-mirror-and-airplay-audio-server-for-linux-macos-and-unix-now-also-runs-on-windows.">UxPlay
|
||||
1.63: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix
|
||||
(now also runs on Windows).</h1>
|
||||
<h3
|
||||
id="now-developed-at-the-github-site-httpsgithub.comfdh2uxplay-where-all-user-issues-should-be-posted.">Now
|
||||
@@ -400,17 +400,11 @@ from sources like Apple Music in Audio-Only (ALAC) mode: run
|
||||
a image viewer with an autoreload feature: an example is “feh”: run
|
||||
“<code>feh -R 1 <name></code>” in the foreground; terminate feh
|
||||
and then Uxplay with “<code>ctrl-C fg ctrl-C</code>”.</p></li>
|
||||
<li><p>If you wish to listen in Audio-Only mode on the server while
|
||||
watching the client screen (for video or Apple Music song lyrics, etc.),
|
||||
the video on the client is delayed by about 5 seconds behind the the
|
||||
audio on the server (<em>this is a Legacy mode issue: the client does
|
||||
not receive latency information to sync its video with audio played on
|
||||
the server</em>). Since UxPlay-1.62, this can be corrected with the
|
||||
<strong>audio offset</strong> option <code>-ao x</code> with an
|
||||
<em>x</em> of about 5.0 (allowed values are decimal numbers between 0
|
||||
and 10.0 seconds); this workaround just delays playing of audio on the
|
||||
server by <em>x</em> seconds, so the effect of pausing or changing
|
||||
tracks on the client will also be delayed.</p></li>
|
||||
<li><p>In Audio-Only mode the server needs to specify a latency to the
|
||||
client so the client can show video in sync with audio played on the
|
||||
server. The default is 0.25 seconds: this can be changed with the
|
||||
<code>-ao x.y</code> option, where x.y is a decimal like 0.25 in the
|
||||
range [0.0, 10.0], with microsecond resolution.</p></li>
|
||||
</ul>
|
||||
<p><strong>One common problem involves GStreamer attempting to use
|
||||
incorrectly-configured or absent accelerated hardware h264 video
|
||||
@@ -786,17 +780,11 @@ parameters to be included with the audiosink name. (Some choices of
|
||||
audiosink might not work on your system.)</p>
|
||||
<p><strong>-as 0</strong> (or just <strong>-a</strong>) suppresses
|
||||
playing of streamed audio, but displays streamed video.</p>
|
||||
<p><strong>-ao x.y</strong> adds an audio offset time in (decimal)
|
||||
seconds to Audio-only (ALAC) streams to allow synchronization of sound
|
||||
playing on the UxPlay server with video on the client which delays
|
||||
playing the audio by <em>x.y</em> seconds (a decimal number). In the
|
||||
AirPlay Legacy mode used by UxPlay, the client cannot obtain audio
|
||||
latency information from the server, and appears to assume a latency of
|
||||
about 5 seconds. This can be compensated for with offset values such as
|
||||
<code>-ao 5</code> (but the effect of a pause in play etc., on the
|
||||
client will also be delayed). The -ao option accepts values in the range
|
||||
[0,10], which it converts to a whole number of milliseconds (-ao 1.2345
|
||||
gives 1234 msec audio delay).</p>
|
||||
<p><strong>-ao x.y</strong> specifies an audio latency) in (decimal)
|
||||
seconds in Audio-only (ALAC), that is reported to the client so it can
|
||||
synchronise its video with audio played on the server. 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).</p>
|
||||
<p><strong>-ca <em>filename</em></strong> provides a file (where
|
||||
<em>filename</em> can include a full path) used for output of “cover
|
||||
art” (from Apple Music, <em>etc.</em>,) in audio-only ALAC mode. This
|
||||
@@ -1140,6 +1128,12 @@ as “SupportsLegacyPairing”) of the “features” plist code (reported to
|
||||
the client by the AirPlay server) to be set. The “features” code and
|
||||
other settings are set in <code>UxPlay/lib/dnssdint.h</code>.</p>
|
||||
<h1 id="changelog">Changelog</h1>
|
||||
<p>1.63 2023-02-06 Corrected -ao option. Now allows audio latency
|
||||
reported to client to be changed from default of 0.25 sec (may not be
|
||||
necessary). Synchronisation of audio on server with video on client in
|
||||
audio-only ALAC mode now works, as sync=true is now used in the ALAC
|
||||
GStreamer pipeline. Internal change: all times are now given in
|
||||
nanoseconds.</p>
|
||||
<p>1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user
|
||||
synchronization of ALAC audio playing on the server with video, song
|
||||
lyrics, etc. playing on the client. x = 5.0 appears to be optimal in
|
||||
|
||||
25
README.md
25
README.md
@@ -1,4 +1,4 @@
|
||||
# UxPlay 1.62: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
|
||||
# UxPlay 1.63: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
|
||||
|
||||
### Now developed at the GitHub site [https://github.com/FDH2/UxPlay](https://github.com/FDH2/UxPlay) (where all user issues should be posted).
|
||||
|
||||
@@ -338,12 +338,9 @@ run "`uxplay -ca <name> &`" in the background, then run a image viewer with an a
|
||||
is "feh": run "``feh -R 1 <name>``"
|
||||
in the foreground; terminate feh and then Uxplay with "`ctrl-C fg ctrl-C`".
|
||||
|
||||
* If you wish to listen in Audio-Only mode on the server while watching the client screen (for video or Apple Music song lyrics, etc.),
|
||||
the video on the client is delayed by about 5 seconds behind the the audio on the server (_this is a Legacy mode issue: the client
|
||||
does not receive latency information to sync its video with audio played on the server_). Since UxPlay-1.62, this can be corrected with
|
||||
the **audio offset** option `-ao x` with an _x_ of about 5.0
|
||||
(allowed values are decimal numbers between 0 and 10.0 seconds); this workaround just delays playing of audio on the server by _x_ seconds, so the effect
|
||||
of pausing or changing tracks on the client will also be delayed.
|
||||
* In Audio-Only mode the server needs to specify a latency to the client so the client can show video in sync with audio played
|
||||
on the server. The default is 0.25 seconds: this can be changed with the `-ao x.y` option, where x.y is a decimal
|
||||
like 0.25 in the range [0.0, 10.0], with microsecond resolution.
|
||||
|
||||
**One common problem involves GStreamer
|
||||
attempting to use incorrectly-configured or absent accelerated hardware h264
|
||||
@@ -664,12 +661,9 @@ which will not work if a firewall is running.
|
||||
|
||||
**-as 0** (or just **-a**) suppresses playing of streamed audio, but displays streamed video.
|
||||
|
||||
**-ao x.y** adds an audio offset time in (decimal) seconds to Audio-only (ALAC) streams to allow synchronization of sound
|
||||
playing on the UxPlay server with video on the client which delays playing the audio by _x.y_ seconds (a
|
||||
decimal number). In the AirPlay Legacy mode used by UxPlay, the client cannot obtain audio latency information
|
||||
from the server, and appears to assume a latency of about 5 seconds. This can be compensated for with offset values such
|
||||
as `-ao 5` (but the effect of a pause in play etc., on the client will also be delayed). The -ao option accepts
|
||||
values in the range [0,10], which it converts to a whole number of milliseconds (-ao 1.2345 gives 1234 msec audio delay).
|
||||
**-ao x.y** specifies an audio latency) in (decimal) seconds in Audio-only (ALAC), that is reported to the client so it
|
||||
can synchronise its video with audio played on the server. 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).
|
||||
|
||||
**-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
|
||||
@@ -945,6 +939,11 @@ tvOS 12.2.1); it seems that the use of "legacy" protocol just requires bit 27 (l
|
||||
The "features" code and other settings are set in `UxPlay/lib/dnssdint.h`.
|
||||
|
||||
# Changelog
|
||||
1.63 2023-02-06 Corrected -ao option. Now allows audio latency reported to client to be changed
|
||||
from default of 0.25 sec (may not be necessary). Synchronisation of audio on server
|
||||
with video on client in audio-only ALAC mode now works, as sync=true is now used in
|
||||
the ALAC GStreamer pipeline. Internal change: all times are now given in nanoseconds.
|
||||
|
||||
1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user synchronization of ALAC
|
||||
audio playing on the server with video, song lyrics, etc. playing on the client.
|
||||
x = 5.0 appears to be optimal in many cases. Quality fixes: cleanup in volume
|
||||
|
||||
39
README.txt
39
README.txt
@@ -1,4 +1,4 @@
|
||||
# UxPlay 1.62: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
|
||||
# UxPlay 1.63: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).
|
||||
|
||||
### Now developed at the GitHub site <https://github.com/FDH2/UxPlay> (where all user issues should be posted).
|
||||
|
||||
@@ -404,17 +404,11 @@ for help with this or other problems.
|
||||
"`feh -R 1 <name>`" in the foreground; terminate feh and then Uxplay
|
||||
with "`ctrl-C fg ctrl-C`".
|
||||
|
||||
- If you wish to listen in Audio-Only mode on the server while
|
||||
watching the client screen (for video or Apple Music song lyrics,
|
||||
etc.), the video on the client is delayed by about 5 seconds behind
|
||||
the the audio on the server (*this is a Legacy mode issue: the
|
||||
client does not receive latency information to sync its video with
|
||||
audio played on the server*). Since UxPlay-1.62, this can be
|
||||
corrected with the **audio offset** option `-ao x` with an *x* of
|
||||
about 5.0 (allowed values are decimal numbers between 0 and 10.0
|
||||
seconds); this workaround just delays playing of audio on the server
|
||||
by *x* seconds, so the effect of pausing or changing tracks on the
|
||||
client will also be delayed.
|
||||
- In Audio-Only mode the server needs to specify a latency to the
|
||||
client so the client can show video in sync with audio played on the
|
||||
server. The default is 0.25 seconds: this can be changed with the
|
||||
`-ao x.y` option, where x.y is a decimal like 0.25 in the range
|
||||
\[0.0, 10.0\], with microsecond resolution.
|
||||
|
||||
**One common problem involves GStreamer attempting to use
|
||||
incorrectly-configured or absent accelerated hardware h264 video
|
||||
@@ -808,16 +802,11 @@ name. (Some choices of audiosink might not work on your system.)
|
||||
**-as 0** (or just **-a**) suppresses playing of streamed audio, but
|
||||
displays streamed video.
|
||||
|
||||
**-ao x.y** adds an audio offset time in (decimal) seconds to Audio-only
|
||||
(ALAC) streams to allow synchronization of sound playing on the UxPlay
|
||||
server with video on the client which delays playing the audio by *x.y*
|
||||
seconds (a decimal number). In the AirPlay Legacy mode used by UxPlay,
|
||||
the client cannot obtain audio latency information from the server, and
|
||||
appears to assume a latency of about 5 seconds. This can be compensated
|
||||
for with offset values such as `-ao 5` (but the effect of a pause in
|
||||
play etc., on the client will also be delayed). The -ao option accepts
|
||||
values in the range \[0,10\], which it converts to a whole number of
|
||||
milliseconds (-ao 1.2345 gives 1234 msec audio delay).
|
||||
**-ao x.y** specifies an audio latency) in (decimal) seconds in
|
||||
Audio-only (ALAC), that is reported to the client so it can synchronise
|
||||
its video with audio played on the server. 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).
|
||||
|
||||
**-ca *filename*** provides a file (where *filename* can include a full
|
||||
path) used for output of "cover art" (from Apple Music, *etc.*,) in
|
||||
@@ -1183,6 +1172,12 @@ other settings are set in `UxPlay/lib/dnssdint.h`.
|
||||
|
||||
# Changelog
|
||||
|
||||
1.63 2023-02-06 Corrected -ao option. Now allows audio latency reported
|
||||
to client to be changed from default of 0.25 sec (may not be necessary).
|
||||
Synchronisation of audio on server with video on client in audio-only
|
||||
ALAC mode now works, as sync=true is now used in the ALAC GStreamer
|
||||
pipeline. Internal change: all times are now given in nanoseconds.
|
||||
|
||||
1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user
|
||||
synchronization of ALAC audio playing on the server with video, song
|
||||
lyrics, etc. playing on the client. x = 5.0 appears to be optimal in
|
||||
|
||||
@@ -60,6 +60,7 @@ struct raop_s {
|
||||
uint8_t overscanned;
|
||||
uint8_t clientFPSdata;
|
||||
|
||||
int audio_delay_micros;
|
||||
int max_ntp_timeouts;
|
||||
};
|
||||
|
||||
@@ -461,6 +462,7 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) {
|
||||
raop->clientFPSdata = 0;
|
||||
|
||||
raop->max_ntp_timeouts = 0;
|
||||
raop->audio_delay_micros = 250000;
|
||||
|
||||
return raop;
|
||||
}
|
||||
@@ -519,6 +521,11 @@ int raop_set_plist(raop_t *raop, const char *plist_item, const int value) {
|
||||
} else if (strcmp(plist_item, "max_ntp_timeouts") == 0) {
|
||||
raop->max_ntp_timeouts = (value > 0 ? value : 0);
|
||||
if (raop->max_ntp_timeouts != value) retval = 1;
|
||||
} else if (strcmp(plist_item, "audio_delay_micros") == 0) {
|
||||
if (value >= 0 && value <= 10 * SECOND_IN_USECS) {
|
||||
raop->audio_delay_micros = value;
|
||||
}
|
||||
if (raop->audio_delay_micros != value) retval = 1;
|
||||
} else {
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <plist/plist.h>
|
||||
#define AUDIO_SAMPLE_RATE 44100 /* all supported AirPlay audio format use this sample rate */
|
||||
#define SECOND_IN_USECS 1000000
|
||||
|
||||
typedef void (*raop_handler_t)(raop_conn_t *, http_request_t *,
|
||||
http_response_t *, char **, int *);
|
||||
@@ -500,7 +502,9 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
unsigned short cport = conn->raop->control_lport, dport = conn->raop->data_lport;
|
||||
unsigned short remote_cport = 0;
|
||||
unsigned char ct;
|
||||
unsigned int sr = 44100; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */
|
||||
unsigned int sr = AUDIO_SAMPLE_RATE; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */
|
||||
unsigned int ad = (unsigned int) (((uint64_t) conn->raop->audio_delay_micros) * AUDIO_SAMPLE_RATE / SECOND_IN_USECS);
|
||||
|
||||
uint64_t uint_val = 0;
|
||||
plist_t req_stream_control_port_node = plist_dict_get_item(req_stream_node, "controlPort");
|
||||
plist_get_uint_val(req_stream_control_port_node, &uint_val);
|
||||
@@ -545,7 +549,7 @@ raop_handler_setup(raop_conn_t *conn,
|
||||
}
|
||||
|
||||
if (conn->raop_rtp) {
|
||||
raop_rtp_start_audio(conn->raop_rtp, use_udp, &remote_cport, &cport, &dport, &ct, &sr);
|
||||
raop_rtp_start_audio(conn->raop_rtp, use_udp, &remote_cport, &cport, &dport, &ct, &sr, &ad);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "RAOP initialized success");
|
||||
} else {
|
||||
logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!");
|
||||
@@ -686,7 +690,10 @@ raop_handler_record(raop_conn_t *conn,
|
||||
http_request_t *request, http_response_t *response,
|
||||
char **response_data, int *response_datalen)
|
||||
{
|
||||
char audio_latency[12];
|
||||
unsigned int ad = (unsigned int) (((uint64_t) conn->raop->audio_delay_micros) * AUDIO_SAMPLE_RATE / SECOND_IN_USECS);
|
||||
sprintf(audio_latency, "%u", ad);
|
||||
logger_log(conn->raop->logger, LOGGER_DEBUG, "raop_handler_record");
|
||||
http_response_add_header(response, "Audio-Latency", "11025");
|
||||
http_response_add_header(response, "Audio-Latency", audio_latency);
|
||||
http_response_add_header(response, "Audio-Jack-Status", "connected; type=analog");
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ struct raop_rtp_s {
|
||||
// Time and sync
|
||||
raop_ntp_t *ntp;
|
||||
double rtp_clock_rate;
|
||||
unsigned int audio_delay_rtp;
|
||||
int64_t rtp_sync_offset;
|
||||
raop_rtp_sync_data_t sync_data[RAOP_RTP_SYNC_DATA_COUNT];
|
||||
int sync_data_index;
|
||||
@@ -551,14 +552,12 @@ raop_rtp_thread_udp(void *arg)
|
||||
uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8);
|
||||
uint64_t sync_ntp_remote = raop_ntp_timestamp_to_nano_seconds(sync_ntp_raw, true);
|
||||
uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote);
|
||||
int64_t shift;
|
||||
int64_t shift = 0;
|
||||
switch (raop_rtp->ct) {
|
||||
case 0x08: /*AAC-ELD */
|
||||
shift = -11025; /* 44100/4 */
|
||||
case 0x02: /* ALAC audio-only mode */
|
||||
break;
|
||||
case 0x02:
|
||||
default:
|
||||
shift = 0; /* not needed for ALAC (audio only) */
|
||||
shift -= (int64_t) raop_rtp->audio_delay_rtp; /* remove delay in Mirror mode */
|
||||
break;
|
||||
}
|
||||
char *str = utils_data_to_string(packet, packetlen, 20);
|
||||
@@ -710,8 +709,8 @@ raop_rtp_thread_udp(void *arg)
|
||||
|
||||
// Start rtp service, three udp ports
|
||||
void
|
||||
raop_rtp_start_audio(raop_rtp_t *raop_rtp, int use_udp, unsigned short *control_rport,
|
||||
unsigned short *control_lport, unsigned short *data_lport, unsigned char *ct, unsigned int *sr)
|
||||
raop_rtp_start_audio(raop_rtp_t *raop_rtp, int use_udp, unsigned short *control_rport, unsigned short *control_lport,
|
||||
unsigned short *data_lport, unsigned char *ct, unsigned int *sr, unsigned int *ad)
|
||||
{
|
||||
logger_log(raop_rtp->logger, LOGGER_INFO, "raop_rtp starting audio");
|
||||
int use_ipv6 = 0;
|
||||
@@ -726,6 +725,7 @@ raop_rtp_start_audio(raop_rtp_t *raop_rtp, int use_udp, unsigned short *control_
|
||||
|
||||
raop_rtp->ct = *ct;
|
||||
raop_rtp->rtp_clock_rate = SECOND_IN_NSECS / *sr;
|
||||
raop_rtp->audio_delay_rtp = *ad;
|
||||
|
||||
/* Initialize ports and sockets */
|
||||
raop_rtp->control_lport = *control_lport;
|
||||
|
||||
@@ -29,8 +29,8 @@ typedef struct raop_rtp_s raop_rtp_t;
|
||||
raop_rtp_t *raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, const unsigned char *remote,
|
||||
int remotelen, const unsigned char *aeskey, const unsigned char *aesiv);
|
||||
|
||||
void raop_rtp_start_audio(raop_rtp_t *raop_rtp, int use_udp, unsigned short *control_rport,
|
||||
unsigned short *control_lport, unsigned short *data_lport, unsigned char *ct, unsigned int *sr);
|
||||
void raop_rtp_start_audio(raop_rtp_t *raop_rtp, int use_udp, unsigned short *control_rport, unsigned short *control_lport,
|
||||
unsigned short *data_lport, unsigned char *ct, unsigned int *sr, unsigned int *ad);
|
||||
|
||||
void raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume);
|
||||
void raop_rtp_set_metadata(raop_rtp_t *raop_rtp, const char *data, int datalen);
|
||||
|
||||
@@ -30,7 +30,7 @@ extern "C" {
|
||||
#include "../lib/logger.h"
|
||||
|
||||
bool gstreamer_init();
|
||||
void audio_renderer_init(logger_t *logger, const char* audiosink, const char* audiodelay);
|
||||
void audio_renderer_init(logger_t *logger, const char* audiosink);
|
||||
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);
|
||||
|
||||
@@ -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, const char* audio_delay) {
|
||||
void audio_renderer_init(logger_t *render_logger, const char* audiosink) {
|
||||
GError *error = NULL;
|
||||
GstCaps *caps = NULL;
|
||||
GstClock *clock = gst_system_clock_obtain();
|
||||
@@ -101,11 +101,6 @@ void audio_renderer_init(logger_t *render_logger, const char* audiosink, const c
|
||||
g_string_append(launch, "! avdec_aac ! ");
|
||||
break;
|
||||
case 1: /* ALAC */
|
||||
if (audio_delay[0]) {
|
||||
g_string_append(launch, "min-threshold-time=");
|
||||
g_string_append(launch, audio_delay);
|
||||
g_string_append(launch, "000000 ");
|
||||
}
|
||||
g_string_append(launch, "! avdec_alac ! ");
|
||||
break;
|
||||
case 3: /*PCM*/
|
||||
@@ -117,7 +112,14 @@ void audio_renderer_init(logger_t *render_logger, const char* audiosink, const c
|
||||
g_string_append (launch, "audioresample ! "); /* wasapisink must resample from 44.1 kHz to 48 kHz */
|
||||
g_string_append (launch, "volume name=volume ! level ! ");
|
||||
g_string_append (launch, audiosink);
|
||||
g_string_append (launch, " sync=false");
|
||||
switch(i) {
|
||||
case 1: /*ALAC*/
|
||||
g_string_append (launch, " sync=true");
|
||||
break;
|
||||
default:
|
||||
g_string_append (launch, " sync=false");
|
||||
break;
|
||||
}
|
||||
renderer_type[i]->pipeline = gst_parse_launch(launch->str, &error);
|
||||
if (error) {
|
||||
g_error ("gst_parse_launch error (audio %d):\n %s\n", i+1, error->message);
|
||||
|
||||
6
uxplay.1
6
uxplay.1
@@ -1,11 +1,11 @@
|
||||
.TH UXPLAY "1" "January 2023" "1.62" "User Commands"
|
||||
.TH UXPLAY "1" "February 2023" "1.63" "User Commands"
|
||||
.SH NAME
|
||||
uxplay \- start AirPlay server
|
||||
.SH SYNOPSIS
|
||||
.B uxplay
|
||||
[\fI\,-n name\/\fR] [\fI\,-s wxh\/\fR] [\fI\,-p \/\fR[\fI\,n\/\fR]] [more \fI OPTIONS \/\fR ...]
|
||||
.SH DESCRIPTION
|
||||
UxPlay 1.62: An open\-source AirPlay mirroring (+ audio streaming) server.
|
||||
UxPlay 1.63: An open\-source AirPlay mirroring (+ audio streaming) server.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B
|
||||
@@ -73,7 +73,7 @@ UxPlay 1.62: An open\-source AirPlay mirroring (+ audio streaming) server.
|
||||
.TP
|
||||
\fB\-as\fR 0 (or \fB\-a\fR) Turn audio off, streamed video only.
|
||||
.TP
|
||||
\fB\-ao\fR x.y Audio offset time in seconds (default 0.0) in Audio-only mode.
|
||||
\fB\-ao\fR x.y Audio-only mode latency in seconds (default 0.25) used by client.
|
||||
.TP
|
||||
\fB\-ca\fI fn \fR In Airplay Audio (ALAC) mode, write cover-art to file fn.
|
||||
.TP
|
||||
|
||||
28
uxplay.cpp
28
uxplay.cpp
@@ -51,8 +51,9 @@
|
||||
#include "renderers/video_renderer.h"
|
||||
#include "renderers/audio_renderer.h"
|
||||
|
||||
#define VERSION "1.62"
|
||||
#define VERSION "1.63"
|
||||
|
||||
#define SECOND_IN_USECS 1000000
|
||||
#define DEFAULT_NAME "UxPlay"
|
||||
#define DEFAULT_DEBUG_LOG false
|
||||
#define LOWEST_ALLOWED_PORT 1024
|
||||
@@ -73,7 +74,7 @@ static videoflip_t videoflip[2] = { NONE , NONE };
|
||||
static bool use_video = true;
|
||||
static unsigned char compression_type = 0;
|
||||
static std::string audiosink = "autoaudiosink";
|
||||
static std::string audiodelay = "";
|
||||
static int audiodelay = -1;
|
||||
static bool use_audio = true;
|
||||
static bool new_window_closing_behavior = true;
|
||||
static bool close_window;
|
||||
@@ -387,7 +388,7 @@ static void print_info (char *name) {
|
||||
printf(" some choices:pulsesink,alsasink,pipewiresink,jackaudiosink,\n");
|
||||
printf(" osssink,oss4sink,osxaudiosink,wasapisink,directsoundsink.\n");
|
||||
printf("-as 0 (or -a) Turn audio off, streamed video only\n");
|
||||
printf("-ao x.y Audio offset time in seconds (default 0.0) in Audio-only mode.\n");
|
||||
printf("-ao x.y Audio-only mode latency in seconds (default 0.25) used by client.\n");
|
||||
printf("-ca <fn> In Airplay Audio (ALAC) mode, write cover-art to file <fn>\n");
|
||||
printf("-reset n Reset after 3n seconds client silence (default %d, 0=never)\n", NTP_TIMEOUT_LIMIT);
|
||||
printf("-nc do Not Close video window when client stops mirroring\n");
|
||||
@@ -741,20 +742,14 @@ static void parse_arguments (int argc, char *argv[]) {
|
||||
int n;
|
||||
char *end;
|
||||
if (i < argc - 1 && *argv[i+1] != '-') {
|
||||
n = (int) (1000 * strtof(argv[++i], &end));
|
||||
if (*end == '\0' && n >=0 && n <= 10000) {
|
||||
audiodelay.erase();
|
||||
if (n > 0) {
|
||||
char* delay = new char[6];
|
||||
snprintf(delay, 6, "%d", n);
|
||||
audiodelay = delay;
|
||||
delete[] delay;
|
||||
}
|
||||
n = (int) (strtof(argv[++i], &end) * SECOND_IN_USECS);
|
||||
if (*end == '\0' && n >=0 && n <= 10 * SECOND_IN_USECS) {
|
||||
audiodelay = n;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "invalid argument -ao %s: must be a decimal time offset in seconds, range [0,10]\n"
|
||||
"(like 5 or 4.8, which will be converted to a whole number of milliseconds)\n", argv[i]);
|
||||
"(like 5 or 4.8, which will be converted to a whole number of microseconds)\n", argv[i]);
|
||||
exit(1);
|
||||
} else {
|
||||
fprintf(stderr, "unknown option %s, stopping\n",argv[i]);
|
||||
@@ -1162,6 +1157,7 @@ int start_raop_server (unsigned short display[5], unsigned short tcp[3], unsigne
|
||||
|
||||
if (show_client_FPS_data) raop_set_plist(raop, "clientFPSdata", 1);
|
||||
raop_set_plist(raop, "max_ntp_timeouts", max_ntp_timeouts);
|
||||
if (audiodelay >= 0) raop_set_plist(raop, "audio_delay_micros", audiodelay);
|
||||
|
||||
/* network port selection (ports listed as "0" will be dynamically assigned) */
|
||||
raop_set_tcp_ports(raop, tcp);
|
||||
@@ -1284,10 +1280,10 @@ int main (int argc, char *argv[]) {
|
||||
logger_set_level(render_logger, debug_log ? LOGGER_DEBUG : LOGGER_INFO);
|
||||
|
||||
if (use_audio) {
|
||||
if (audiodelay.c_str()[0]) {
|
||||
LOGI("Audio-only ALAC streams will be delayed by %s milliseconds", audiodelay.c_str());
|
||||
if (audiodelay >= 0) {
|
||||
LOGI("Audio-only ALAC streams will be delayed by %d microseconds", audiodelay);
|
||||
}
|
||||
audio_renderer_init(render_logger, audiosink.c_str(), audiodelay.c_str());
|
||||
audio_renderer_init(render_logger, audiosink.c_str());
|
||||
} else {
|
||||
LOGI("audio_disabled");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user