From 30f32bd793337f62481ce8ea9db8f4947e702bc9 Mon Sep 17 00:00:00 2001 From: fduncanh Date: Sat, 21 Aug 2021 16:33:31 -0400 Subject: [PATCH] improved the port selection option, added ability to choose videosink --- README.md | 42 ++++++++++--- lib/raop.c | 22 +++---- lib/raop.h | 2 +- lib/raop_handlers.h | 2 +- lib/raop_ntp.c | 5 +- lib/raop_rtp.c | 6 +- lib/raop_rtp_mirror.c | 6 +- uxplay.cpp | 140 ++++++++++++++++++++++++++++-------------- 8 files changed, 147 insertions(+), 78 deletions(-) diff --git a/README.md b/README.md index c7b9396..43beecd 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,9 @@ If uxplay starts, but stalls after "Initialized server socket(s)" appears, it is probably because a firewall is blocking access to the server on which it is running. If possible, either turn off the firewall to see if that is the problem, or get three consecutive network ports, -starting at port n, opened for both tcp and udp, and use "uxplay -p n" +starting at port n, all three in the range 1024-65535, opened for both tcp and udp, and use "uxplay -p n" (or open UDP 6000, 6001, 6011 TCP 7000,7001,7100 and use "uxplay -p"). - Try "uxplay -d " (debug log option) to see what is happening. If you use an nVidia graphics card, make sure that the gstreamer1.0-vaapi plugin for Intel graphics is *NOT* installed (de-install it!). @@ -78,7 +77,10 @@ AirPlay services to your iPad, iPhone etc. in pixels). (This may be a request made to the AirPlay client, and perhaps will not be the final resolution you get.) w and h are whole numbers with four - digits or less. + digits or less. Note that the **height** pixel size is the controlling + one used by the client for determining the streaming format; the width is + dynamically adjusted to the shape of the image (portait or landscape + format, depending on how an iPad is held, for example). **-s wxh@r** As above, but also informs the AirPlay client about the screen refresh rate of the display. Default is r=60 (60 Hz); r is a whole number @@ -92,11 +94,19 @@ AirPlay services to your iPad, iPhone etc. below 30 fps might be useful to reduce latency if you are running more than one instance of uxplay at the same time. +**-o** turns on an "overscanned" option for the display window. This + reduces the image resolution by using some of the pixels requested + by option -s wxh (or their default values 1920x1080) by adding an empty + boundary frame of unused pixels (which would be lost in a full-screen + dispaly that overscans, and is not displayed by gstreamer). + Recomnendation: **don't use this option**. -**-p** allows you to select the network ports used by UxPlay (these need +**-p** allows you to select the network ports used by UxPlay (these need to be opened if the server is behind a firewall). By itself, -p sets "legacy" ports TCP 7100, 7000, 7001, UDP 6000, 6001, 7011. -p n (e.g. -p - 35000) sets TCP and UDP ports n, n+1, n+2. Ports must be in the range + 35000) sets TCP and UDP ports n, n+1, n+2. -p n1,n2,n3 (comman separated + values) sets each port separatey; -p n1,n2 sets ports n1,n2,n2+1. -p tcp n + or -p udp n sets just the TCP or UDP ports. Ports must be in the range [1024-65535]. If the -p option is not used, the ports are chosen dynamically (randomly), @@ -118,7 +128,13 @@ Also: image transforms that had been added to RPiPlay have been ported to UxPlay **-r {R|L}** 90 degree Right (clockwise) or Left (counter-clockwise) rotations; these are carried out after any **-f** transforms. -# New features available: (v 1.31 2021-08-09) +**-vs videosink** chooses the GStreamer videosink, instead of letting + autovideosink pick it for you. For example, xvimagesink, vaapisink, or + fpsdisplaysink (which shows the streaming framerate in fps). Using quotes + "..." might allow some parameters to be included with the videosink name. + + +# New features available: (v 1.32 2021-08-21) 1. Updates of the RAOP (AirPlay protocol) collection of codes maintained at https://github.com/FD-/RPiPlay.git so it is current as of 2021-08-01, @@ -127,7 +143,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, -p, -m, -r, -f, and -fps options. +2. Added the -s, -o -p, -m, -r, -f, -fps, and -vs options. 3. If "cmake -DZOOMFIX=ON .." is run before compiling, the mirrored window is now visible to screen-sharing applications such as @@ -138,6 +154,16 @@ visible for screen-sharing.) Thanks to David Ventura https://github.com/DavidVentura/UxPlay for the fix and also for getting it into gstreamer-1.20. +If uxplay was compiled after +cmake was run without -DZOOMFIX=ON, and your gstreamer version is older that +1.20, you can still manually make the window visible with the X11 utility +xdotool, if it is installed on your system: +``` +xdotool selectwindow set_window --name "name" +``` +where "name" is your choice of name, and then select the uxplay window with +the mouse. + 4. The AirPlay server now terminates correctly when the gstreamer display window is closed, and is relaunched with the same settings to wait for a new connection. The program uxplay terminates when Ctrl-C is typed in the terminal window. @@ -174,6 +200,8 @@ memory leaks, at least in modern Linux; if for any reason you don't want this fix, comment out the line in CMakeLists.txt that activates it when uxplay is compiled.) +10. Allow choice (with -vs option) of the videosink that ends the GStreamer pipline. + # Disclaimer All the resources in this repository are written using only freely available information from the internet. The code and related resources are meant for educational purposes only. It is the responsibility of the user to make sure all local laws are adhered to. diff --git a/lib/raop.c b/lib/raop.c index ebe401b..d783786 100755 --- a/lib/raop.c +++ b/lib/raop.c @@ -44,16 +44,19 @@ struct raop_s { dnssd_t *dnssd; + /* local network ports */ unsigned short port; unsigned short timing_lport; unsigned short control_lport; unsigned short data_lport; unsigned short mirror_data_lport; + /* plist display items: width, height, refreshRate, maxFPS, overscanned */ uint16_t display_width; uint16_t display_height; uint8_t display_refresh_rate; uint8_t display_max_fps; + uint8_t display_overscanned; }; struct raop_conn_s { @@ -320,12 +323,13 @@ raop_init(int max_clients, raop_callbacks_t *callbacks) { raop->data_lport = 0; raop->mirror_data_lport = 0; - /* initialize display width, height, refresh_rate, max_fps */ + /* initialize display plist parameters */ raop->display_width = 1920; raop->display_height = 1080; raop->display_refresh_rate = 60; raop->display_max_fps = 30; - + raop->display_overscanned = 0; + return raop; } @@ -358,20 +362,14 @@ raop_set_log_level(raop_t *raop, int level) { } void raop_set_display(raop_t *raop, unsigned short width, unsigned short height, - unsigned short refresh_rate, unsigned short max_fps){ + unsigned short refresh_rate, unsigned short max_fps, unsigned short overscanned){ assert(raop); - // these must fit into two 8-bit bytes if (width) raop->display_width = (uint16_t) width; if (height) raop->display_height = (uint16_t) height; - - // these must fit into a single 8-bit byte - if (refresh_rate > 255) refresh_rate = 255; - if (refresh_rate) raop->display_refresh_rate = (uint8_t) refresh_rate; - - if (max_fps > 255) max_fps = 255; - if (max_fps) raop->display_max_fps = (uint8_t) max_fps; - + if (refresh_rate && refresh_rate < 256) raop->display_refresh_rate = (uint8_t) refresh_rate; + if (max_fps && max_fps < 256) raop->display_max_fps = (uint8_t) max_fps; + if (overscanned) raop->display_overscanned = 1; } void diff --git a/lib/raop.h b/lib/raop.h index bd02d17..09e1dda 100755 --- a/lib/raop.h +++ b/lib/raop.h @@ -55,7 +55,7 @@ RAOP_API raop_t *raop_init(int max_clients, raop_callbacks_t *callbacks); RAOP_API void raop_set_log_level(raop_t *raop, int level); RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls); RAOP_API void raop_set_display(raop_t *raop, unsigned short width, unsigned short height, - unsigned short refresh_rate, unsigned short max_fps); + unsigned short refresh_rate, unsigned short max_fps, unsigned short overscanned); RAOP_API void raop_set_port(raop_t *raop, unsigned short port); RAOP_API void raop_set_udp_ports(raop_t *raop, unsigned short port[3]); RAOP_API void raop_set_tcp_ports(raop_t *raop, unsigned short port[2]); diff --git a/lib/raop_handlers.h b/lib/raop_handlers.h index a2a056d..2cadb56 100755 --- a/lib/raop_handlers.h +++ b/lib/raop_handlers.h @@ -141,7 +141,7 @@ raop_handler_info(raop_conn_t *conn, plist_t displays_0_rotation_node = plist_new_bool(0); plist_t displays_0_refresh_rate_node = plist_new_uint(conn->raop->display_refresh_rate); plist_t displays_0_max_fps_node = plist_new_uint(conn->raop->display_max_fps); - plist_t displays_0_overscanned_node = plist_new_bool(0); + plist_t displays_0_overscanned_node = plist_new_bool(conn->raop->display_overscanned); plist_t displays_0_features = plist_new_uint(14); plist_dict_set_item(displays_0_node, "uuid", displays_0_uuid_node); diff --git a/lib/raop_ntp.c b/lib/raop_ntp.c index 530f947..f43bde7 100644 --- a/lib/raop_ntp.c +++ b/lib/raop_ntp.c @@ -213,9 +213,7 @@ raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6) /* Set port values */ raop_ntp->timing_lport = tport; - - logger_log(raop_ntp->logger, LOGGER_INFO, "raop_ntp timing_lport socket %d UDP port %d", - tsock, tport); + logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp local timing port socket %d port UDP %d", tsock, tport); return 0; sockets_cleanup: @@ -371,6 +369,7 @@ raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport) return; } if (timing_lport) *timing_lport = raop_ntp->timing_lport; + /* Create the thread and initialize running values */ raop_ntp->running = 1; raop_ntp->joined = 0; diff --git a/lib/raop_rtp.c b/lib/raop_rtp.c index 4e014b7..3728e5d 100755 --- a/lib/raop_rtp.c +++ b/lib/raop_rtp.c @@ -251,10 +251,8 @@ raop_rtp_init_sockets(raop_rtp_t *raop_rtp, int use_ipv6, int use_udp) /* Set port values */ raop_rtp->control_lport = cport; raop_rtp->data_lport = dport; - logger_log(raop_rtp->logger, LOGGER_INFO, "raop_rtp: control_lport socket %d at port UDP %d", - csock, cport); - logger_log(raop_rtp->logger, LOGGER_INFO, "raop_rtp: data_lport socket %d at port UDP %d", - dsock, dport); + logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp local control port socket %d port UDP %d", csock, cport); + logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp local data port socket %d port UDP %d", dsock, dport); return 0; sockets_cleanup: diff --git a/lib/raop_rtp_mirror.c b/lib/raop_rtp_mirror.c index 0916bb3..01ebf48 100755 --- a/lib/raop_rtp_mirror.c +++ b/lib/raop_rtp_mirror.c @@ -30,7 +30,6 @@ #include "mirror_buffer.h" #include "stream.h" -static int raop_rtp_init_mirror_sockets(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6); struct h264codec_s { unsigned char compatibility; @@ -433,6 +432,8 @@ raop_rtp_mirror_thread(void *arg) return 0; } +static int raop_rtp_init_mirror_sockets(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6); + void raop_rtp_start_mirror(raop_rtp_mirror_t *raop_rtp_mirror, int use_udp, unsigned short *mirror_data_lport) { @@ -526,8 +527,7 @@ raop_rtp_init_mirror_sockets(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6) /* Set port values */ raop_rtp_mirror->mirror_data_lport = dport; - logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp: mirror_data_lport socket %d at port TCP %d", - dsock, dport); + logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror local data port socket %d port TCP %d", dsock, dport); return 0; sockets_cleanup: diff --git a/uxplay.cpp b/uxplay.cpp index 61b5f22..8cceb1e 100755 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -33,7 +33,7 @@ #include "renderers/video_renderer.h" #include "renderers/audio_renderer.h" -#define VERSION "1.31" +#define VERSION "1.32" #define DEFAULT_NAME "UxPlay" #define DEFAULT_DEBUG_LOG false @@ -41,9 +41,9 @@ #define HIGHEST_PORT 65535 -static int start_server (std::vector hw_addr, std::string name, unsigned short display[4], +static int start_server (std::vector hw_addr, std::string name, unsigned short display[5], unsigned short tcp[2], unsigned short udp[3], videoflip_t videoflip[2], - bool use_audio, bool debug_log); + bool use_audio, bool debug_log, std::string videosink); static int stop_server (); @@ -117,20 +117,25 @@ static void print_info (char *name) { printf("Options:\n"); printf("-n name Specify the network name of the AirPlay server\n"); printf("-s wxh[@r]Set display resolution [refresh_rate] default 1920x1080[@60]\n"); + printf("-o Set mirror \"overscanned\" mode on (not usually needed)\n"); printf("-fps n Set maximum allowed streaming framerate, default 30\n"); printf("-f {H|V|I}Horizontal|Vertical flip, or both=Inversion=rotate 180 deg\n"); printf("-r {R|L} rotate 90 degrees Right (cw) or Left (ccw)\n"); - printf("-p n Use fixed UDP+TCP network ports n:n+1:n+2. (n>1023)\n"); printf("-p Use legacy UDP 6000:6001:7011 TCP 7000:7001:7100\n"); + printf("-p n Use TCP and UDP ports n,n+1,n+2. range 1024-56535\n"); + 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("-vs choose the GStreamer videosink; default \"autovideosink\"\n"); + printf(" choices: ximagesink,xvimagesink,vaapisink,fpsdisplaysink, etc.\n"); printf("-d Enable debug logging\n"); printf("-v/-h Displays this help and version information\n"); } -bool option_has_value(const int i, const int argc, const char *arg, const char *next_arg) { +bool option_has_value(const int i, const int argc, std::string option, const char *next_arg) { if (i >= argc - 1 || next_arg[0] == '-') { - fprintf(stderr,"invalid \"%s\" had no argument\n", arg); + LOGE("invalid: \"%s\" had no argument", option.c_str()); return false; } return true; @@ -141,14 +146,14 @@ static bool get_display_settings (std::string value, unsigned short *w, unsigned // with no more than 4 digits, r < 256 (stored in one byte). char *end; std::size_t pos = value.find_first_of("x"); - if (!pos) return false; + if (pos == std::string::npos) return false; std::string str1 = value.substr(pos+1); value.erase(pos); if (value.length() == 0 || value.length() > 4 || value[0] == '-') return false; *w = (unsigned short) strtoul(value.c_str(), &end, 10); if (*end || *w == 0) return false; pos = str1.find_first_of("@"); - if(pos) { + if(pos != std::string::npos) { std::string str2 = str1.substr(pos+1); if (str2.length() == 0 || str2.length() > 3 || str2[0] == '-') return false; *r = (unsigned short) strtoul(str2.c_str(), &end, 10); @@ -170,15 +175,37 @@ static bool get_fps (const char *str, unsigned short *n) { return true; } -static bool get_lowest_port (const char *str, unsigned short *n) { - //str must be a positive decimal integer in allowed range, 5 digits max. +static bool get_ports (int nports, std::string option, const char * value, unsigned short * const port) { + /*valid entries are comma-separated values port_1,port_2,...,port_r, 0 < r <= nports */ + /*where ports are distinct, and are in the allowed range. */ + /*missing values are consecutive to last given value (at least one value needed). */ char *end; unsigned long l; - if (strlen(str) == 0 || strlen(str) > 5 || str[0] == '-') return false; - *n = (unsigned short) (l = strtoul(str, &end, 10)); - if (*end) return false; - if (l < LOWEST_ALLOWED_PORT || l > HIGHEST_PORT - 2 ) return false; - return true; + std::size_t pos; + std::string val(value), str; + for (int i = 0; i <= nports ; i++) { + if(i == nports) break; + pos = val.find_first_of(','); + str = val.substr(0,pos); + if(str.length() == 0 || str.length() > 5 || str[0] == '-') break; + l = strtoul(str.c_str(), &end, 10); + if (*end || l < LOWEST_ALLOWED_PORT || l > HIGHEST_PORT) break; + *(port + i) = (unsigned short) l; + for (int j = 0; j < i ; j++) { + if( *(port + j) == *(port + i)) break; + } + if(pos == std::string::npos) { + if (nports + *(port + i) > i + 1 + HIGHEST_PORT) break; + for (int j = i + 1; j < nports; j++) { + *(port + j) = *(port + j - 1) + 1; + } + return true; + } + val.erase(0, pos+1); + } + LOGE("invalid \"%s %s\", all %d ports must be in range [%d,%d]", + option.c_str(), value, nports, LOWEST_ALLOWED_PORT, HIGHEST_PORT); + return false; } static bool get_videoflip (const char *str, videoflip_t *videoflip) { @@ -222,8 +249,9 @@ int main (int argc, char *argv[]) { bool use_audio = true; bool use_random_hw_addr = false; bool debug_log = DEFAULT_DEBUG_LOG; - unsigned short display[4] = {0}, tcp[2] = {0}, udp[3] = {0}; + unsigned short display[5] = {0}, tcp[2] = {0}, udp[3] = {0}; videoflip_t videoflip[2] = { NONE , NONE }; + std::string videosink = "autovideosink"; #ifdef SUPPRESS_AVAHI_COMPAT_WARNING // suppress avahi_compat nag message. avahi emits a "nag" warning (once) @@ -236,7 +264,7 @@ int main (int argc, char *argv[]) { for (int i = 1; i < argc; i++) { std::string arg(argv[i]); if (arg == "-n") { - if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); + if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); server_name = std::string(argv[++i]); } else if (arg == "-s") { if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); @@ -247,19 +275,21 @@ int main (int argc, char *argv[]) { exit(1); } } else if (arg == "-fps") { - if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); + if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); if (!get_fps(argv[++i], &display[3])) { fprintf(stderr, "invalid \"-fps %s\"; -fps n : max n=255, default n=30\n", argv[i]); exit(1); } + } else if (arg == "-o") { + display[4] = 1; } else if (arg == "-f") { - if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); + if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); if (!get_videoflip(argv[++i], &videoflip[0])) { fprintf(stderr,"invalid \"-f %s\" , unknown flip type, choices are H, V, I\n",argv[i]); exit(1); } } else if (arg == "-r") { - if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); + if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); if (!get_videorotate(argv[++i], &videoflip[1])) { fprintf(stderr,"invalid \"-r %s\" , unknown rotation type, choices are R, L\n",argv[i]); exit(1); @@ -270,16 +300,18 @@ int main (int argc, char *argv[]) { udp[0] = 7011; udp[1] = 6001; udp[2] = 6000; continue; } - unsigned short n; - if(get_lowest_port(argv[++i], &n)) { - for (int i = 0; i < 3; i++) { - udp[i] = n++; - if (i < 2) tcp[i] = udp[i]; - } + std::string value(argv[++i]); + if (value == "tcp") { + arg.append(" tcp"); + if(!get_ports(3, arg, argv[++i], tcp)) exit(1); + } else if (value == "udp") { + arg.append( " udp"); + if(!get_ports(3, arg, argv[++i], udp)) exit(1); } else { - fprintf(stderr, "Error: \"-p %s\" is invalid (%d-%d is allowed)\n", - argv[i], LOWEST_ALLOWED_PORT, HIGHEST_PORT); - exit(1); + if(!get_ports(3, arg, argv[i], tcp)) exit(1); + for (int j = 1; j < 3; j++) { + udp[j] = tcp[j]; + } } } else if (arg == "-m") { use_random_hw_addr = true; @@ -290,6 +322,10 @@ int main (int argc, char *argv[]) { } else if (arg == "-h" || arg == "-v") { print_info(argv[0]); exit(0); + } else if (arg == "-vs") { + if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); + videosink.erase(); + videosink.append(argv[++i]); } else { LOGE("unknown option %s, stopping\n",argv[i]); exit(1); @@ -297,7 +333,7 @@ int main (int argc, char *argv[]) { } if (udp[0]) LOGI("using network ports UDP %d %d %d TCP %d %d %d\n", - udp[0],udp[1], udp[2], tcp[0], tcp[1], tcp[1] + 1); + udp[0],udp[1], udp[2], tcp[0], tcp[1], tcp[2]); std::string mac_address; if (!use_random_hw_addr) mac_address = find_mac(); @@ -311,7 +347,7 @@ int main (int argc, char *argv[]) { relaunch: if (start_server(server_hw_addr, server_name, display, tcp, udp, - videoflip,use_audio, debug_log) != 0) { + videoflip,use_audio, debug_log, videosink)) { return 1; } running = true; @@ -383,9 +419,9 @@ extern "C" void log_callback (void *cls, int level, const char *msg) { } -int start_server (std::vector hw_addr, std::string name, unsigned short display[4], +int start_server (std::vector hw_addr, std::string name, unsigned short display[5], unsigned short tcp[2], unsigned short udp[3], videoflip_t videoflip[2], - bool use_audio, bool debug_log) { + bool use_audio, bool debug_log, std::string videosink) { raop_callbacks_t raop_cbs; memset(&raop_cbs, 0, sizeof(raop_cbs)); raop_cbs.conn_init = conn_init; @@ -402,6 +438,14 @@ int start_server (std::vector hw_addr, std::string name, unsigned short di return -1; } + /* write desired display pixel width, pixel height, refresh_rate, max_fps, overscanned. */ + /* use 0 for default values 1920,1080,60,30,0; these are sent to the Airplay client */ + 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) */ + raop_set_tcp_ports(raop, tcp); + raop_set_udp_ports(raop, udp); + raop_set_log_callback(raop, log_callback, NULL); raop_set_log_level(raop, debug_log ? RAOP_LOG_DEBUG : LOGGER_INFO); @@ -409,8 +453,9 @@ int start_server (std::vector hw_addr, std::string name, unsigned short di logger_set_callback(render_logger, log_callback, NULL); logger_set_level(render_logger, debug_log ? LOGGER_DEBUG : LOGGER_INFO); - if ((video_renderer = video_renderer_init(render_logger, name.c_str(), videoflip)) == NULL) { + if ((video_renderer = video_renderer_init(render_logger, name.c_str(), videoflip, videosink.c_str())) == NULL) { LOGE("Could not init video renderer"); + stop_server(); return -1; } @@ -419,20 +464,13 @@ int start_server (std::vector hw_addr, std::string name, unsigned short di } else if ((audio_renderer = audio_renderer_init(render_logger, video_renderer)) == NULL) { LOGE("Could not init audio renderer"); + stop_server(); return -1; } if (video_renderer) video_renderer_start(video_renderer); if (audio_renderer) audio_renderer_start(audio_renderer); - /* write desired display pixel width, pixel height, refresh_rate, */ - /* and max_fps to raop (use 0 for default values) */ - raop_set_display(raop, display[0], display[1], display[2], display[3]); - - /* network port selection (ports listed as "0" will be dynamically assigned) */ - raop_set_tcp_ports(raop, tcp); - raop_set_udp_ports(raop, udp); - unsigned short port = raop_get_port(raop); raop_start(raop, &port); raop_set_port(raop, port); @@ -441,22 +479,30 @@ int start_server (std::vector hw_addr, std::string name, unsigned short di dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &error); if (error) { LOGE("Could not initialize dnssd library!"); + stop_server(); return -2; } raop_set_dnssd(raop, dnssd); dnssd_register_raop(dnssd, port); - dnssd_register_airplay(dnssd, port + 1); + if (tcp[2]) { + port = tcp[2]; + } else if (port < 56535) { + port++; + } else { + port--; + } + dnssd_register_airplay(dnssd, port); return 0; } int stop_server () { - raop_destroy(raop); - dnssd_unregister_raop(dnssd); - dnssd_unregister_airplay(dnssd); + if (raop) raop_destroy(raop); + if (dnssd) dnssd_unregister_raop(dnssd); + if (dnssd) dnssd_unregister_airplay(dnssd); if (audio_renderer) audio_renderer_destroy(audio_renderer); - video_renderer_destroy(video_renderer); + if (video_renderer) video_renderer_destroy(video_renderer); return 0; }