mirror of
https://github.com/morgan9e/UxPlay
synced 2026-04-14 00:04:13 +09:00
UxPlay 1.38 added option -as to choose GStreamer audiosink
This commit is contained in:
23
README.md
23
README.md
@@ -1,4 +1,4 @@
|
||||
# UxPlay 1.37
|
||||
# UxPlay 1.38
|
||||
|
||||
This project is a GPLv3 unix AirPlay server which now also works on macOS.
|
||||
Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/macOS clients
|
||||
@@ -21,7 +21,7 @@ If the client streams audio using AirPlay as opposed to AirPlay screen-mirrorin
|
||||
input into the GStreamer audio-rendering pipeline, but does not get rendered into audio output. If someone can adapt the GStreamer audio
|
||||
pipeline to also render these Airplay audio streams, such an enhancement of UxPlay would be welcome as a Pull Request!_
|
||||
|
||||
UxPlay 1.37 is based on https://github.com/FD-/RPiPlay, with GStreamer integration from
|
||||
UxPlay 1.38 is based on https://github.com/FD-/RPiPlay, with GStreamer integration from
|
||||
https://github.com/antimof/UxPlay.
|
||||
(UxPlay only uses GStreamer, and does not contain the alternative Raspberry-Pi-specific
|
||||
audio and video renderers also found in RPiPlay.)
|
||||
@@ -198,6 +198,11 @@ plugin for Intel graphics is *NOT* installed (**uninstall it** if it is installe
|
||||
"-vs ximagesink" or "-vs xvimagesink", to see if this fixes the problem, or "-vs vaapisink" to see if this
|
||||
reproduces the problem.)
|
||||
|
||||
You can try to fix audio problems by using the "-as _audiosink_" option to choose the GStreamer audiosink , rather than
|
||||
have autoaudiosink pick one for you. The command "gst_inspect-1.0 | grep Sink | grep Audio" " will show you which audiosinks and videosinks are
|
||||
available on your system. (Replace "Audio" by "Video" to see videosinks). Common audiosinks are pulsesink, alsasink, osssink, oss4sink,
|
||||
and osxaudiosink (macOS).
|
||||
|
||||
If you ran cmake with "-DZOOMFIX=ON", check if the problem is still there without ZOOMFIX.
|
||||
ZOOMFIX is only applied to the default videosink choice ("autovideosink") and the two X11 videosinks
|
||||
"ximagesink" and "xvimagesink". ZOOMFIX is only designed for these last two; if
|
||||
@@ -269,7 +274,7 @@ which will not work if a firewall is running.
|
||||
attempt to run two instances of uxplay on the same computer.)
|
||||
On macOS, random MAC addresses are always used.
|
||||
|
||||
**-a** disable audio, leaving only the video playing.
|
||||
|
||||
|
||||
Also: image transforms that had been added to RPiPlay have been ported to UxPlay:
|
||||
|
||||
@@ -290,6 +295,14 @@ Also: image transforms that had been added to RPiPlay have been ported to UxPlay
|
||||
**-vs 0** suppresses display of streamed video, but plays streamed audio. (The client's screen
|
||||
is still mirrored at a reduced rate of 1 frame per second, but is not rendered or displayed.)
|
||||
|
||||
**-as _audiosink_** chooses the GStreamer audiosink, instead of letting
|
||||
autoaudiosink pick it for you. Some audiosink choices are: pulsesink, alsasink,
|
||||
osssink, oss4sink, and osxaudiosink (for macOS). Using quotes
|
||||
"..." might allow some parameters to be included with the audiosink name.
|
||||
(Some choices of audiosink might not work on your system.)
|
||||
|
||||
**-as 0** or **-a** suppresses playing of streamed audio, but displays streamed video.
|
||||
|
||||
**-t _timeout_** will cause the server to relaunch (without stopping uxplay) if no connections
|
||||
have been present during the previous _timeout_ seconds. (You may wish to use this because the Server may not be
|
||||
visible to new Clients that were inactive when the Server was launched, and an idle Bonjour
|
||||
@@ -302,6 +315,8 @@ Also: image transforms that had been added to RPiPlay have been ported to UxPlay
|
||||
|
||||
|
||||
# ChangeLog
|
||||
1.38 2021-10-8 Add -as _audiosink_ option to allow user to choose the GStreamer audiosink.
|
||||
|
||||
1.37 2021-09-29 Append "@hostname" to AirPlay Server name, where "hostname" is the name of the
|
||||
server running uxplay (reworked change in 1.36).
|
||||
|
||||
@@ -330,7 +345,7 @@ This involved crypto updates, replacement
|
||||
of the included plist library by the system-installed version, and a change
|
||||
over to a library llhttp for http parsing.
|
||||
|
||||
2. Added the -s, -o -p, -m, -r, -f, -fps -vs and -t options.
|
||||
2. Added the -s, -o -p, -m, -r, -f, -fps -vs -va and -t options.
|
||||
|
||||
3. If "`cmake -DZOOMFIX=ON .`" is run before compiling,
|
||||
the mirrored window is now visible to screen-sharing applications such as
|
||||
|
||||
@@ -23,7 +23,7 @@ add_library( airplay
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
find_library( LIBPLIST NAMES plist plist-2.0 )
|
||||
find_library( LIBPLIST NAMES plist3 plist plist-2.0 )
|
||||
elseif( APPLE )
|
||||
pkg_check_modules( PLIST REQUIRED libplist-2.0 )
|
||||
find_library( LIBPLIST libplist-2.0.a REQUIRED )
|
||||
|
||||
@@ -32,7 +32,7 @@ extern "C" {
|
||||
|
||||
typedef struct audio_renderer_s audio_renderer_t;
|
||||
|
||||
audio_renderer_t *audio_renderer_init(logger_t *logger, video_renderer_t *video_renderer);
|
||||
audio_renderer_t *audio_renderer_init(logger_t *logger, video_renderer_t *video_renderer, const char* audiosink);
|
||||
void audio_renderer_start(audio_renderer_t *renderer);
|
||||
void audio_renderer_render_buffer(audio_renderer_t *renderer, raop_ntp_t *ntp, unsigned char* data, int data_len, uint64_t pts);
|
||||
void audio_renderer_set_volume(audio_renderer_t *renderer, float volume);
|
||||
|
||||
@@ -51,7 +51,7 @@ static gboolean check_plugins (void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
audio_renderer_t *audio_renderer_init(logger_t *logger, video_renderer_t *video_renderer) {
|
||||
audio_renderer_t *audio_renderer_init(logger_t *logger, video_renderer_t *video_renderer, const char* audiosink) {
|
||||
audio_renderer_t *renderer;
|
||||
GError *error = NULL;
|
||||
|
||||
@@ -63,8 +63,11 @@ audio_renderer_t *audio_renderer_init(logger_t *logger, video_renderer_t *video_
|
||||
|
||||
assert(check_plugins ());
|
||||
|
||||
renderer->pipeline = gst_parse_launch("appsrc name=audio_source stream-type=0 format=GST_FORMAT_TIME is-live=true ! queue ! decodebin !"
|
||||
"audioconvert ! volume name=volume ! level ! autoaudiosink sync=false", &error);
|
||||
GString *launch = g_string_new("appsrc name=audio_source stream-type=0 format=GST_FORMAT_TIME is-live=true ! queue ! decodebin !"
|
||||
"audioconvert ! volume name=volume ! level ! ");
|
||||
g_string_append(launch, audiosink);
|
||||
g_string_append(launch, " sync=false");
|
||||
renderer->pipeline = gst_parse_launch(launch->str, &error);
|
||||
g_assert (renderer->pipeline);
|
||||
|
||||
renderer->appsrc = gst_bin_get_by_name (GST_BIN (renderer->pipeline), "audio_source");
|
||||
|
||||
31
uxplay.cpp
31
uxplay.cpp
@@ -35,7 +35,7 @@
|
||||
#include "renderers/video_renderer.h"
|
||||
#include "renderers/audio_renderer.h"
|
||||
|
||||
#define VERSION "1.37"
|
||||
#define VERSION "1.38"
|
||||
|
||||
#define DEFAULT_NAME "UxPlay"
|
||||
#define DEFAULT_DEBUG_LOG false
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
static int start_server (std::vector<char> hw_addr, std::string name, unsigned short display[5],
|
||||
unsigned short tcp[3], unsigned short udp[3], videoflip_t videoflip[2],
|
||||
bool use_audio, bool debug_log, std::string videosink);
|
||||
bool use_audio, bool debug_log, std::string videosink, std::string audiosink);
|
||||
|
||||
static int stop_server ();
|
||||
|
||||
@@ -159,13 +159,15 @@ static void print_info (char *name) {
|
||||
printf(" use \"-p n1,n2,n3\" to set each port, \"n1,n2\" for n3 = n2+1\n");
|
||||
printf(" \"-p tcp n\" or \"-p udp n\" sets TCP or UDP ports only\n");
|
||||
printf("-m Use random MAC address (use for concurrent UxPlay's)\n");
|
||||
printf("-a Turn audio off. video output only\n");
|
||||
printf("-t n Relaunch server if no connection existed in last n seconds\n");
|
||||
printf("-vs Choose the GStreamer videosink; default \"autovideosink\"\n");
|
||||
printf(" choices: ximagesink,xvimagesink,vaapisink,fpsdisplaysink, etc.\n");
|
||||
printf("-vs Choose the GStreamer videosink; default \"autovideosink\"\n");
|
||||
printf(" choices: ximagesink,xvimagesink,vaapisink,glimagesink, etc.\n");
|
||||
printf("-vs 0 Streamed audio only, with no video display window\n");
|
||||
printf("-as Choose the GStreamer audiosink; default \"autoaudiosink\"\n");
|
||||
printf(" choices: pulsesink,alsasink,osssink,oss4sink,osxaudiosink,etc.\n");
|
||||
printf("-as 0 (or -a) Turn audio off, video output only\n");
|
||||
printf("-d Enable debug logging\n");
|
||||
printf("-v/-h Displays this help and version information\n");
|
||||
printf("-v or -h Displays this help and version information\n");
|
||||
}
|
||||
|
||||
bool option_has_value(const int i, const int argc, std::string option, const char *next_arg) {
|
||||
@@ -296,7 +298,8 @@ int main (int argc, char *argv[]) {
|
||||
unsigned short display[5] = {0}, tcp[3] = {0}, udp[3] = {0};
|
||||
videoflip_t videoflip[2] = { NONE , NONE };
|
||||
std::string videosink = "autovideosink";
|
||||
|
||||
std::string audiosink = "autoaudiosink";
|
||||
|
||||
#ifdef SUPPRESS_AVAHI_COMPAT_WARNING
|
||||
// suppress avahi_compat nag message. avahi emits a "nag" warning (once)
|
||||
// if getenv("AVAHI_COMPAT_NOWARN") returns null.
|
||||
@@ -373,6 +376,10 @@ int main (int argc, char *argv[]) {
|
||||
if (!option_has_value(i, argc, arg, argv[i+1])) exit(1);
|
||||
videosink.erase();
|
||||
videosink.append(argv[++i]);
|
||||
} else if (arg == "-as") {
|
||||
if (!option_has_value(i, argc, arg, argv[i+1])) exit(1);
|
||||
audiosink.erase();
|
||||
audiosink.append(argv[++i]);
|
||||
} else if (arg == "-t") {
|
||||
if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1);
|
||||
server_timeout = 0;
|
||||
@@ -401,7 +408,7 @@ int main (int argc, char *argv[]) {
|
||||
relaunch:
|
||||
connections_stopped = false;
|
||||
if (start_server(server_hw_addr, server_name, display, tcp, udp,
|
||||
videoflip,use_audio, debug_log, videosink)) {
|
||||
videoflip,use_audio, debug_log, videosink, audiosink)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -483,7 +490,7 @@ extern "C" void log_callback (void *cls, int level, const char *msg) {
|
||||
|
||||
int start_server (std::vector<char> hw_addr, std::string name, unsigned short display[5],
|
||||
unsigned short tcp[3], unsigned short udp[3], videoflip_t videoflip[2],
|
||||
bool use_audio, bool debug_log, std::string videosink) {
|
||||
bool use_audio, bool debug_log, std::string videosink, std::string audiosink) {
|
||||
raop_callbacks_t raop_cbs;
|
||||
memset(&raop_cbs, 0, sizeof(raop_cbs));
|
||||
raop_cbs.conn_init = conn_init;
|
||||
@@ -507,6 +514,10 @@ int start_server (std::vector<char> hw_addr, std::string name, unsigned short di
|
||||
use_video = false;
|
||||
display[3] = 1; /* set fps to 1 frame per sec when no video will be shown */
|
||||
}
|
||||
if(audiosink == "0") {
|
||||
use_audio = false;
|
||||
}
|
||||
|
||||
raop_set_display(raop, display[0], display[1], display[2], display[3], display[4]);
|
||||
|
||||
/* network port selection (ports listed as "0" will be dynamically assigned) */
|
||||
@@ -533,7 +544,7 @@ int start_server (std::vector<char> hw_addr, std::string name, unsigned short di
|
||||
|
||||
if (! use_audio) {
|
||||
LOGI("Audio disabled");
|
||||
} else if ((audio_renderer = audio_renderer_init(render_logger, video_renderer)) ==
|
||||
} else if ((audio_renderer = audio_renderer_init(render_logger, video_renderer, audiosink.c_str())) ==
|
||||
NULL) {
|
||||
LOGE("Could not init audio renderer");
|
||||
stop_server();
|
||||
|
||||
Reference in New Issue
Block a user