diff --git a/lib/raop.c b/lib/raop.c index c863109..a0396a1 100644 --- a/lib/raop.c +++ b/lib/raop.c @@ -88,6 +88,7 @@ struct raop_conn_s { unsigned char *remote; int remotelen; + bool have_active_remote; }; typedef struct raop_conn_s raop_conn_t; @@ -152,7 +153,8 @@ conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remot conn->locallen = locallen; conn->remotelen = remotelen; - + conn->have_active_remote = false; + if (raop->callbacks.conn_init) { raop->callbacks.conn_init(raop->callbacks.cls); } @@ -174,6 +176,17 @@ conn_request(void *ptr, http_request_t *request, http_response_t **response) { method = http_request_get_method(request); url = http_request_get_url(request); cseq = http_request_get_header(request, "CSeq"); + if (!conn->have_active_remote) { + const char *active_remote = http_request_get_header(request, "Active-Remote"); + if (active_remote) { + conn->have_active_remote = true; + if (conn->raop->callbacks.export_dacp) { + const char *dacp_id = http_request_get_header(request, "DACP-ID"); + conn->raop->callbacks.export_dacp(conn->raop->callbacks.cls, active_remote, dacp_id); + } + } + } + if (!method || !cseq) { return; } diff --git a/lib/raop.h b/lib/raop.h index 19eb9c3..ffbeab3 100644 --- a/lib/raop.h +++ b/lib/raop.h @@ -62,6 +62,7 @@ struct raop_callbacks_s { void (*display_pin) (void *cls, char * pin); void (*register_client) (void *cls, const char *device_id, const char *pk_str); bool (*check_register) (void *cls, const char *pk_str); + void (*export_dacp) (void *cls, const char *active_remote, const char *dacp_id); }; typedef struct raop_callbacks_s raop_callbacks_t; raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len, diff --git a/uxplay.1 b/uxplay.1 index d7e6214..200e052 100644 --- a/uxplay.1 +++ b/uxplay.1 @@ -110,6 +110,11 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server: .TP \fB\-key\fI fn \fR Store private key in file fn (Default: $HOME/.uxplay.pem) .TP +\fB\-dacp\fI [fn]\fRExport client DACP information to file $HOME/.uxplay.dacp +.IP + (option to use file "fn" instead); used for client remote. +.PP +.TP \fB\-vdmp\fR [n] Dump h264 video output to "fn.h264"; fn="videodump", change .IP with "-vdmp [n] filename". If [n] is given, file fn.x.h264 @@ -137,6 +142,8 @@ UxPlay 1.67: An open\-source AirPlay mirroring (+ audio streaming) server: FILES Private key stored (for persistence) in $HOME/.uxplay.pem (can be changed) .TP +(transient) storage of client DACP info: $HOME/uxplay.dacp (can be changed) +.TP Options in one of $UXPLAYRC, or ~/.uxplayrc, or ~/.config/uxplayrc .TP are applied first (command-line options may modify them). uxplayrc format: @@ -149,9 +156,9 @@ Various, see website or distribution. .SH COPYRIGHT .TP -Various, see website or distribution. License: GPL v3+: GNU GPL version 3 or later. +Various, see website or distribution. License: GPL v3+: .TP -(some parts LGPL v.2.1+ or MIT). +GNU GPL version 3 or later. (some parts LGPL v.2.1+ or MIT). .SH SEE ALSO .TP diff --git a/uxplay.cpp b/uxplay.cpp index 52b89e9..0286e85 100644 --- a/uxplay.cpp +++ b/uxplay.cpp @@ -131,6 +131,7 @@ static bool require_password = false; static unsigned short pin = 0; static std::string keyfile = ""; static std::string mac_address = ""; +static std::string dacpfile = ""; /* logging */ void log(int level, const char* format, ...) { @@ -585,6 +586,8 @@ static void print_info (char *name) { printf("-m [mac] Set MAC address (also Device ID);use for concurrent UxPlays\n"); printf(" if mac xx:xx:xx:xx:xx:xx is not given, a random mac is used\n"); printf("-key Store private key in file (default:$HOME/.uxplay.pem)\n"); + printf("-dacp [fn]Export client DACP information to file $HOME/.uxplay.dacp\n"); + printf(" (option to use file \"fn\" instead); used for client remote\n"); printf("-vdmp [n] Dump h264 video output to \"fn.h264\"; fn=\"videodump\",change\n"); printf(" with \"-vdmp [n] filename\". If [n] is given, file fn.x.h264\n"); printf(" x=1,2,.. opens whenever a new SPS/PPS NAL arrives, and <=n\n"); @@ -1011,6 +1014,14 @@ static void parse_arguments (int argc, char *argv[]) { fprintf(stderr, "option \"-key \" requires a path to a file for persistent key storage\n"); exit(1); } + } else if (arg == "-dacp") { + dacpfile.erase(); + if (i < argc - 1 && *argv[i+1] != '-') { + dacpfile.append(argv[++i]); + } else { + dacpfile.append(get_homedir()); + dacpfile.append("/.uxplay.dacp"); + } } else { fprintf(stderr, "unknown option %s, stopping (for help use option \"-h\")\n",argv[i]); exit(1); @@ -1259,6 +1270,18 @@ extern "C" void display_pin(void *cls, char *pin) { } } +extern "C" void export_dacp(void *cls, const char *active_remote, const char *dacp_id) { + if (dacpfile.length()) { + FILE *fp = fopen(dacpfile.c_str(), "w"); + if (fp) { + fprintf(fp,"%s\n%s\n", dacp_id, active_remote); + fclose(fp); + } else { + LOGE("failed to open DACP export file \"%s\"", dacpfile.c_str()); + } + } +} + extern "C" void conn_init (void *cls) { open_connections++; LOGD("Open connections: %i", open_connections); @@ -1274,6 +1297,9 @@ extern "C" void conn_destroy (void *cls) { if (use_audio) { audio_renderer_stop(); } + if (dacpfile.length()) { + remove (dacpfile.c_str()); + } } } @@ -1523,6 +1549,7 @@ int start_raop_server (unsigned short display[5], unsigned short tcp[3], unsigne raop_cbs.display_pin = display_pin; raop_cbs.register_client = register_client; raop_cbs.check_register = check_register; + raop_cbs.export_dacp = export_dacp; /* set max number of connections = 2 to protect against capture by new client */ raop = raop_init(max_connections, &raop_cbs, keyfile.c_str());