Add avahi code to look for the rmeote control information for the client and get the port number from it.

This commit is contained in:
Mike Brady
2017-10-05 17:39:32 +01:00
parent 44c39fee6a
commit 139c18bf3e
12 changed files with 314 additions and 137 deletions
+1
View File
@@ -23,6 +23,7 @@ man/Makefile
man/Makefile.in
scripts/shairport-sync.service
scripts/shairport-sync
shairport-sync.core
#Some dbus files that are automatically generated
dbus/data/org.gnome.ShairportSync.service
+16
View File
@@ -104,6 +104,22 @@ void mdns_unregister(void) {
}
}
void mdns_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer) {
if ((config.mdns) && (config.mdns->mdns_dacp_monitor)) {
int error = config.mdns->mdns_dacp_monitor(dacp_id,port,private_pointer);
if (error) {
debug(1,"Error starting a DACP monitor.");
}
} else
debug(1,"Can't start a DACP monitor.");
}
void mdns_dacp_dont_monitor(void** private_pointer) {
if ((config.mdns) && (config.mdns->mdns_dacp_dont_monitor)) {
config.mdns->mdns_dacp_dont_monitor(private_pointer);
} else
debug(1,"Can't stop a DACP monitor.");
}
void mdns_ls_backends(void) {
mdns_backend **b = NULL;
printf("Available mDNS backends: \n");
+6
View File
@@ -1,18 +1,24 @@
#ifndef _MDNS_H
#define _MDNS_H
#include <stdint.h>
#include "config.h"
extern int mdns_pid;
void mdns_unregister(void);
void mdns_register(void);
void mdns_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer);
void mdns_dacp_dont_monitor(void** private_pointer);
void mdns_ls_backends(void);
typedef struct {
char *name;
int (*mdns_register)(char *apname, int port);
void (*mdns_unregister)(void);
int (*mdns_dacp_monitor)(char* dacp_id,uint16_t *port,void** private_pointer);
void (*mdns_dacp_dont_monitor)(void** private_pointer);
} mdns_backend;
#ifdef CONFIG_METADATA
+247 -118
View File
@@ -26,6 +26,7 @@
*/
#include <stdlib.h>
#include <pthread.h>
#include "common.h"
#include "mdns.h"
@@ -40,112 +41,119 @@
#include <avahi-client/lookup.h>
#include <avahi-common/alternative.h>
static AvahiServiceBrowser *sb = NULL;
typedef struct {
AvahiThreadedPoll *service_poll;
AvahiClient *service_client;
AvahiServiceBrowser *service_browser;
char *dacp_id;
uint16_t *dacp_port;
} dacp_browser_struct;
//static AvahiServiceBrowser *sb = NULL;
static AvahiClient *client = NULL;
// static AvahiClient *service_client = NULL;
static AvahiEntryGroup *group = NULL;
static AvahiThreadedPoll *tpoll = NULL;
// static AvahiThreadedPoll *service_poll = NULL;
static char *name = NULL;
static char *service_name = NULL;
static int port = 0;
static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface,
AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event,
const char *name, const char *type, const char *domain,
const char *host_name, const AvahiAddress *address, uint16_t port,
AvahiStringList *txt, AvahiLookupResultFlags flags,
AVAHI_GCC_UNUSED void *userdata) {
assert(r);
/* Called whenever a service has been resolved successfully or timed out */
switch (event) {
case AVAHI_RESOLVER_FAILURE:
debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name,
type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
break;
case AVAHI_RESOLVER_FOUND: {
if (flags & AVAHI_LOOKUP_RESULT_OUR_OWN) {
char a[AVAHI_ADDRESS_STR_MAX], *t;
// debug(1, "avahi: service '%s' of type '%s' in domain '%s' added.", name, type,
// domain);
avahi_address_snprint(a, sizeof(a), address);
debug(1, "avahi: address advertised is: \"%s\".", a);
/*
t = avahi_string_list_to_string(txt);
debug(1,
"\t%s:%u (%s)\n"
"\tTXT=%s\n"
"\tcookie is %u\n"
"\tis_local: %i\n"
"\tour_own: %i\n"
"\twide_area: %i\n"
"\tmulticast: %i\n"
"\tcached: %i\n",
host_name, port, a,
t,
avahi_string_list_get_service_cookie(txt),
!!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
!!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
!!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
!!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
!!(flags & AVAHI_LOOKUP_RESULT_CACHED));
avahi_free(t);
*/
static void resolve_callback(
AvahiServiceResolver *r,
AVAHI_GCC_UNUSED AvahiIfIndex interface,
AVAHI_GCC_UNUSED AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name,
const char *type,
const char *domain,
const char *host_name,
const AvahiAddress *address,
uint16_t port,
AvahiStringList *txt,
AvahiLookupResultFlags flags,
void* userdata) {
assert(r);
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
/* Called whenever a service has been resolved successfully or timed out */
switch (event) {
case AVAHI_RESOLVER_FAILURE:
debug(1, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s.", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
break;
case AVAHI_RESOLVER_FOUND: {
char a[AVAHI_ADDRESS_STR_MAX], *t;
//debug(1, "Resolve callback: Service '%s' of type '%s' in domain '%s':", name, type, domain);
char* dacpid = strstr(name,"iTunes_Ctrl_");
if (dacpid) {
dacpid+=strlen("iTunes_Ctrl_");
if (strcmp(dacpid,dbs->dacp_id)==0) {
uint16_t *p = dbs->dacp_port;
if (*p != port) {
debug(1,"Client's DACP port: %u.",port);
*p = port;
}
}
} else {
debug(1,"Resolve callback: Can't see a DACP string in a DACP Record!");
}
}
}
}
}
avahi_service_resolver_free(r);
}
static void browse_callback(
AvahiServiceBrowser *b,
AvahiIfIndex interface,
AvahiProtocol protocol,
AvahiBrowserEvent event,
const char *name,
const char *type,
const char *domain,
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
void* userdata) {
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
assert(b);
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
switch (event) {
case AVAHI_BROWSER_FAILURE:
warn("avahi: browser failure.", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
avahi_threaded_poll_quit(tpoll);
break;
case AVAHI_BROWSER_NEW:
// debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'.", name, type, domain);
/* We ignore the returned resolver object. In the callback
function we free it. If the server is terminated before
the callback function is called the server will free
the resolver for us. */
if (!(avahi_service_resolver_new(dbs->service_client, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, userdata)))
debug(1, "Failed to resolve service '%s': %s.", name, avahi_strerror(avahi_client_errno(dbs->service_client)));
break;
case AVAHI_BROWSER_REMOVE:
debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain);
char* dacpid = strstr(name,"iTunes_Ctrl_");
if (dacpid) {
dacpid+=strlen("iTunes_Ctrl_");
if (strcmp(dacpid,dbs->dacp_id)==0) {
uint16_t *p = dbs->dacp_port;
if (*p != 0) {
debug(1,"Client's DACP status withdrawn.");
*p = 0;
}
}
} else {
debug(1,"Browse callback: Can't see a DACP string in a DACP Record!");
}
avahi_service_resolver_free(r);
break;
case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
// debug(1, "(Browser) %s.", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
break;
}
}
static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
AvahiBrowserEvent event, const char *name, const char *type,
const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
void *userdata) {
AvahiClient *c = userdata;
assert(b);
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
switch (event) {
case AVAHI_BROWSER_FAILURE:
// debug(1, "(Browser) %s\n",
// avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
return;
case AVAHI_BROWSER_NEW:
// debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type,
// domain);
/* We ignore the returned resolver object. In the callback
function we free it. If the server is terminated before
the callback function is called the server will free
the resolver for us. */
if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC,
0, resolve_callback, c)))
debug(1, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
break;
case AVAHI_BROWSER_REMOVE:
// debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name,
// type, domain);
break;
case AVAHI_BROWSER_ALL_FOR_NOW:
case AVAHI_BROWSER_CACHE_EXHAUSTED:
// debug(1, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ?
// "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
break;
}
}
static void register_service(AvahiClient *c);
@@ -154,7 +162,7 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
switch (state) {
case AVAHI_ENTRY_GROUP_ESTABLISHED:
/* The entry group has been established successfully */
debug(1, "avahi: service '%s' successfully added.", name);
debug(1, "avahi: service '%s' successfully added.", service_name);
break;
case AVAHI_ENTRY_GROUP_COLLISION: {
@@ -162,11 +170,11 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
/* A service name collision with a remote service
* happened. Let's pick a new name */
n = avahi_alternative_service_name(name);
avahi_free(name);
name = n;
n = avahi_alternative_service_name(service_name);
avahi_free(service_name);
service_name = n;
debug(2, "avahi: service name collision, renaming service to '%s'", name);
debug(2, "avahi: service name collision, renaming service to '%s'", service_name);
/* And recreate the services */
register_service(avahi_entry_group_get_client(g));
@@ -179,11 +187,11 @@ static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
break;
case AVAHI_ENTRY_GROUP_UNCOMMITED:
debug(2, "avahi: service '%s' group is not yet committed.", name);
debug(2, "avahi: service '%s' group is not yet committed.", service_name);
break;
case AVAHI_ENTRY_GROUP_REGISTERING:
debug(2, "avahi: service '%s' group is registering.", name);
debug(2, "avahi: service '%s' group is registering.", service_name);
break;
default:
@@ -211,14 +219,14 @@ static void register_service(AvahiClient *c) {
selected_interface = AVAHI_IF_UNSPEC;
#ifdef CONFIG_METADATA
if (config.metadata_enabled) {
ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, name,
ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, service_name,
config.regtype, NULL, NULL, port,
MDNS_RECORD_WITH_METADATA, NULL);
if (ret == 0)
debug(1, "avahi: request to add \"%s\" service with metadata", config.regtype);
} else {
#endif
ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, name,
ret = avahi_entry_group_add_service(group, selected_interface, AVAHI_PROTO_UNSPEC, 0, service_name,
config.regtype, NULL, NULL, port,
MDNS_RECORD_WITHOUT_METADATA, NULL);
if (ret == 0)
@@ -273,7 +281,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state,
break;
case AVAHI_CLIENT_S_COLLISION:
debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", name);
debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", service_name);
break;
case AVAHI_CLIENT_CONNECTING:
@@ -286,9 +294,56 @@ static void client_callback(AvahiClient *c, AvahiClientState state,
}
}
static void service_client_callback(AvahiClient *c, AvahiClientState state,
void *userdata) {
int err;
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
switch (state) {
case AVAHI_CLIENT_S_REGISTERING:
break;
case AVAHI_CLIENT_S_RUNNING:
break;
case AVAHI_CLIENT_FAILURE:
err = avahi_client_errno(c);
debug(1, "avahi: service client failure: %s", avahi_strerror(err));
if (err == AVAHI_ERR_DISCONNECTED) {
/* We have been disconnected, so lets reconnect */
avahi_client_free(c);
c = NULL;
if (!(dbs->service_client = avahi_client_new(avahi_threaded_poll_get(dbs->service_poll), AVAHI_CLIENT_NO_FAIL,
service_client_callback, userdata, &err))) {
warn("avahi: failed to create service client object: %s", avahi_strerror(err));
avahi_threaded_poll_quit(dbs->service_poll);
}
} else {
warn("avahi: service client failure: %s", avahi_strerror(err));
avahi_threaded_poll_quit(dbs->service_poll);
}
break;
case AVAHI_CLIENT_S_COLLISION:
debug(2, "avahi: service client state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", service_name);
break;
case AVAHI_CLIENT_CONNECTING:
debug(2, "avahi: service client received AVAHI_CLIENT_CONNECTING");
break;
default:
debug(1, "avahi: unexpected and unhandled avahi service client state: %d", state);
break;
}
}
static int avahi_register(char *srvname, int srvport) {
debug(1, "avahi: avahi_register.");
name = strdup(srvname);
service_name = strdup(srvname);
port = srvport;
int err;
@@ -302,13 +357,6 @@ static int avahi_register(char *srvname, int srvport) {
return -1;
}
// we need this to detect the IPv6 number we're advertising...
// if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
// config.regtype, NULL, 0, browse_callback, client))) {
// warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
// return -1;
// }
if (avahi_threaded_poll_start(tpoll) < 0) {
warn("couldn't start avahi tpoll thread");
return -1;
@@ -323,10 +371,91 @@ static void avahi_unregister(void) {
avahi_threaded_poll_stop(tpoll);
tpoll = NULL;
if (name)
free(name);
name = NULL;
if (service_name)
free(service_name);
service_name = NULL;
}
int avahi_dacp_monitor(char* dacp_id,uint16_t *port,void** private_pointer) {
dacp_browser_struct **pdbs = (dacp_browser_struct **)private_pointer;
dacp_browser_struct *dbs = (dacp_browser_struct*)malloc(sizeof(dacp_browser_struct));
if (dbs==NULL)
die("can not allocate a dacp_browser_struct.");
dbs->dacp_id=dacp_id;
dbs->dacp_port=port;
// create the threaded poll code
int err;
if (!(dbs->service_poll = avahi_threaded_poll_new())) {
warn("couldn't create avahi threaded service_poll!");
if(dbs) {
free((char*)dbs);
}
return -1;
}
// create the service client
if (!(dbs->service_client = avahi_client_new(avahi_threaded_poll_get(dbs->service_poll), AVAHI_CLIENT_NO_FAIL,
service_client_callback, (void*)dbs, &err))) {
warn("couldn't create avahi service client: %s!", avahi_strerror(err));
if(dbs) { //should free the threaded poll code
avahi_threaded_poll_free(dbs->service_poll);
free((char*)dbs);
}
return -1;
}
/* Create the service browser */
if (!(dbs->service_browser = avahi_service_browser_new(dbs->service_client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_dacp._tcp", NULL, 0, browse_callback, (void *)dbs))) {
warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(dbs->service_client)));
if(dbs) { //should free the threaded poll code and the service client
avahi_client_free(dbs->service_client);
avahi_threaded_poll_free(dbs->service_poll);
free((char*)dbs);
}
return -1;
}
// start the polling thread
if (avahi_threaded_poll_start(dbs->service_poll) < 0) {
warn("couldn't start avahi service_poll thread");
if(dbs) { //should free the threaded poll code and the service client and the service browser
avahi_service_browser_free(dbs->service_browser);
avahi_client_free(dbs->service_client);
avahi_threaded_poll_free(dbs->service_poll);
free((char*)dbs);
}
return -1;
}
*pdbs = dbs;
return 0;
}
void avahi_dacp_dont_monitor(void** private_pointer) {
dacp_browser_struct **pdbs = (dacp_browser_struct **)private_pointer;
// stop and dispose of everything
if ((*pdbs)->service_poll)
avahi_threaded_poll_stop((*pdbs)->service_poll);
if ((*pdbs)->service_browser)
avahi_service_browser_free((*pdbs)->service_browser);
if ((*pdbs)->service_client)
avahi_client_free((*pdbs)->service_client);
if ((*pdbs)->service_poll)
avahi_threaded_poll_free((*pdbs)->service_poll);
free((char*)(*pdbs));
*pdbs = NULL;
}
mdns_backend mdns_avahi = {
.name = "avahi", .mdns_register = avahi_register, .mdns_unregister = avahi_unregister};
.name = "avahi",
.mdns_register = avahi_register,
.mdns_unregister = avahi_unregister,
.mdns_dacp_monitor = avahi_dacp_monitor,
.mdns_dacp_dont_monitor = avahi_dacp_dont_monitor
};
+4 -2
View File
@@ -24,8 +24,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "common.h"
#include "mdns.h"
#include "common.h"
#include <arpa/inet.h>
#include <dns_sd.h>
#include <stdlib.h>
@@ -92,4 +92,6 @@ static void mdns_dns_sd_unregister(void) {
mdns_backend mdns_dns_sd = {.name = "dns-sd",
.mdns_register = mdns_dns_sd_register,
.mdns_unregister = mdns_dns_sd_unregister};
.mdns_unregister = mdns_dns_sd_unregister,
.mdns_dacp_monitor = NULL,
.mdns_dacp_dont_monitor = NULL};
+7 -3
View File
@@ -24,8 +24,8 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "common.h"
#include "mdns.h"
#include "common.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
@@ -161,8 +161,12 @@ static void kill_mdns_child(void) {
mdns_backend mdns_external_avahi = {.name = "external-avahi",
.mdns_register = mdns_external_avahi_register,
.mdns_unregister = kill_mdns_child};
.mdns_unregister = kill_mdns_child,
.mdns_dacp_monitor = NULL,
.mdns_dacp_dont_monitor = NULL};
mdns_backend mdns_external_dns_sd = {.name = "external-dns-sd",
.mdns_register = mdns_external_dns_sd_register,
.mdns_unregister = kill_mdns_child};
.mdns_unregister = kill_mdns_child,
.mdns_dacp_monitor = NULL,
.mdns_dacp_dont_monitor = NULL};
+3 -1
View File
@@ -163,4 +163,6 @@ static void mdns_tinysvcmdns_unregister(void) {
mdns_backend mdns_tinysvcmdns = {.name = "tinysvcmdns",
.mdns_register = mdns_tinysvcmdns_register,
.mdns_unregister = mdns_tinysvcmdns_unregister};
.mdns_unregister = mdns_tinysvcmdns_unregister,
.mdns_dacp_monitor = NULL,
.mdns_dacp_dont_monitor = NULL};
+12
View File
@@ -1561,6 +1561,9 @@ static void *player_thread_func(void *arg) {
// as a null operand, so we'll use it like that too
int sync_error_out_of_bounds =
0; // number of times in a row that there's been a serious sync error
// start an mdns/zeroconf thread to look for DACP messages containing our DACP_ID and getting the port number
mdns_dacp_monitor(conn->dacp_id,&conn->dacp_port,&conn->dacp_private);
conn->framesProcessedInThisEpoch = 0;
conn->framesGeneratedInThisEpoch = 0;
@@ -2166,10 +2169,15 @@ static void *player_thread_func(void *arg) {
elapsedSec);
}
// stop watching for DACP port number stuff
mdns_dacp_dont_monitor(&conn->dacp_private); // begin looking out for information about the client as a remote control. Specifically we might need the port number
if (config.output->stop)
config.output->stop();
usleep(100000); // allow this time to (?) allow the alsa subsystem to finish cleaning up after
// itself. 50 ms seems too short
debug(2, "Shut down audio, control and timing threads");
conn->please_stop = 1;
pthread_kill(rtp_audio_thread, SIGUSR1);
@@ -2201,6 +2209,10 @@ static void *player_thread_func(void *arg) {
debug(1, "Error destroying vol_mutex variable.");
debug(1, "Player thread exit on RTSP conversation thread %d.", conn->connection_number);
if (conn->dacp_id) {
free(conn->dacp_id);
conn->dacp_id = NULL;
}
if (outbuf)
free(outbuf);
if (silence)
+8
View File
@@ -158,6 +158,14 @@ typedef struct {
int64_t session_corrections;
int play_number_after_flush;
// remote control stuff. The port to which to send commands is not specified, so you have to use mdns to find it.
// at present, only avahi can do this
char* dacp_id; // id of the client -- used to find the port to be used
uint16_t dacp_port; // port on the client to send remote control messages to, else zero
uint32_t dacp_active_remote; // key to send to the remote controller
void* dacp_private; // private storage (just a pointer) for the dacp_port resolver
} rtsp_conn_info;
+4 -6
View File
@@ -593,7 +593,7 @@ static int bind_port(int ip_family, const char *self_ip_address, uint32_t scope_
return sport;
}
void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t active_remote,
void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport,
int *lsport, int *lcport, int *ltport, rtsp_conn_info *conn) {
// this gets the local and remote ip numbers (and ports used for the TCD stuff)
@@ -605,8 +605,6 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t
debug(2, "rtp_setup: cport=%d tport=%d.", cport, tport);
conn->client_active_remote = active_remote;
// print out what we know about the client
void *client_addr, *self_addr;
int client_port, self_port;
@@ -762,11 +760,11 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) {
void rtp_request_client_pause(rtsp_conn_info *conn) {
if (conn->rtp_running) {
if (conn->client_active_remote == 0) {
if (conn->dacp_active_remote == 0) {
debug(1, "Can't request a client pause: no valid active remote.");
} else {
// debug(1,"Send a client pause request to %s:3689 with active remote
// %u.",client_ip_string,client_active_remote);
// %u.",client_ip_string,dacp_active_remote);
struct addrinfo hints, *res;
int sockfd;
@@ -799,7 +797,7 @@ void rtp_request_client_pause(rtsp_conn_info *conn) {
sprintf(message,
"GET /ctrl-int/1/pause HTTP/1.1\r\nHost: %s:3689\r\nActive-Remote: %u\r\n\r\n",
conn->client_ip_string, conn->client_active_remote);
conn->client_ip_string, conn->dacp_active_remote);
// debug(1,"Sending this message: \"%s\".",message);
// Send some data
+1 -1
View File
@@ -13,7 +13,7 @@ void *rtp_control_receiver(void *arg);
void *rtp_timing_receiver(void *arg);
void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int controlport, int timingport,
uint32_t active_remote, int *local_server_port, int *local_control_port,
int *local_server_port, int *local_control_port,
int *local_timing_port, rtsp_conn_info *conn);
void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn);
void rtp_request_client_pause(rtsp_conn_info *conn); // ask the client to pause
+5 -6
View File
@@ -59,7 +59,6 @@
#endif
#include "common.h"
#include "mdns.h"
#include "player.h"
#include "rtp.h"
#include "rtsp.h"
@@ -696,26 +695,26 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
debug(3, "Connection %d: SETUP", conn->connection_number);
int cport, tport;
int lsport, lcport, ltport;
uint32_t active_remote = 0;
char *ar = msg_get_header(req, "Active-Remote");
if (ar) {
debug(1, "Active-Remote string seen: \"%s\".", ar);
// get the active remote
char *p;
active_remote = strtoul(ar, &p, 10);
conn->dacp_active_remote = strtoul(ar, &p, 10);
#ifdef CONFIG_METADATA
send_metadata('ssnc', 'acre', ar, strlen(ar), req, 1);
#endif
}
#ifdef CONFIG_METADATA
ar = msg_get_header(req, "DACP-ID");
if (ar) {
debug(1, "DACP-ID string seen: \"%s\".", ar);
conn->dacp_id = strdup(ar);
#ifdef CONFIG_METADATA
send_metadata('ssnc', 'daid', ar, strlen(ar), req, 1);
}
#endif
}
// This latency-setting mechanism is deprecated and will be removed.
// If no non-standard latency is chosen, automatic negotiated latency setting
@@ -793,7 +792,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *
tport = atoi(p);
// rtsp_take_player();
rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, &ltport,
rtp_setup(&conn->local, &conn->remote, cport, tport, &lsport, &lcport, &ltport,
conn);
if (!lsport)
goto error;