2 * DACP protocol handler. This file is part of Shairport Sync.
3 * Copyright (c) Mike Brady 2017 -- 2020
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 // Information about the four-character codes is from many sources, with thanks, including
27 // https://github.com/melloware/dacp-net/blob/master/Melloware.DACP/
33 #include <arpa/inet.h>
39 #include <netinet/in.h>
46 #include "metadata_hub.h"
47 #include "tinyhttp/http.h"
50 int players_connection_thread_index
; // the connection thread index when a player thread is
51 // associated with this, zero otherwise
52 int scan_enable
; // set to 1 if scanning should be considered
53 char dacp_id
[256]; // the DACP ID string
54 uint16_t port
; // zero if no port discovered
55 short connection_family
; // AF_INET6 or AF_INET
56 int always_use_revision_number_1
; // for dealing with forked-daapd;
57 uint32_t scope_id
; // if it's an ipv6 connection, this will be its scope id
58 char ip_string
[INET6_ADDRSTRLEN
]; // the ip string pointing to the client
59 char *active_remote_id
; // send this when you want to send remote control commands
60 void *port_monitor_private_storage
;
63 int dacp_monitor_initialised
= 0;
64 pthread_t dacp_monitor_thread
;
65 dacp_server_record dacp_server
;
66 void *mdns_dacp_monitor_private_storage_pointer
;
68 // HTTP Response data/funcs (See the tinyhttp example.cpp file for more on this.)
70 void *body
; // this will be a malloc'ed pointer
71 ssize_t malloced_size
; // this will be its allocated size
72 ssize_t size
; // the current size of the content
76 void *response_realloc(__attribute__((unused
)) void *opaque
, void *ptr
, int size
) {
77 void *t
= realloc(ptr
, size
);
78 if ((t
== NULL
) && (size
!= 0))
79 debug(1, "Response realloc of size %d failed!", size
);
83 void response_body(void *opaque
, const char *data
, int size
) {
84 struct HttpResponse
*response
= (struct HttpResponse
*)opaque
;
86 ssize_t space_available
= response
->malloced_size
- response
->size
;
87 if (space_available
< size
) {
88 // debug(1,"Getting more space for the response -- need %d bytes but only %ld bytes left.\n",
90 // size - space_available);
91 ssize_t size_requested
= size
- space_available
+ response
->malloced_size
+ 16384;
92 void *t
= realloc(response
->body
, size_requested
);
93 response
->malloced_size
= size_requested
;
97 die("dacp: can't allocate any more space for parser.");
100 memcpy(response
->body
+ response
->size
, data
, size
);
101 response
->size
+= size
;
105 response_header(__attribute__((unused
)) void *opaque
, __attribute__((unused
)) const char *ckey
,
106 __attribute__((unused
)) int nkey
, __attribute__((unused
)) const char *cvalue
,
107 __attribute__((unused
)) int nvalue
) { /* example doesn't care about headers */
110 static void response_code(void *opaque
, int code
) {
111 struct HttpResponse
*response
= (struct HttpResponse
*)opaque
;
112 response
->code
= code
;
115 static const struct http_funcs responseFuncs
= {
122 // static pthread_mutex_t dacp_conversation_lock = PTHREAD_MUTEX_INITIALIZER;
123 // static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER;
124 static pthread_mutex_t dacp_conversation_lock
;
125 static pthread_mutex_t dacp_server_information_lock
;
126 static pthread_cond_t dacp_server_information_cv
;
128 void addrinfo_cleanup(void *arg
) {
129 // debug(1, "addrinfo cleanup called.");
130 struct addrinfo
**info
= (struct addrinfo
**)arg
;
134 void mutex_lock_cleanup(void *arg
) {
135 pthread_mutex_t
*m
= (pthread_mutex_t
*)arg
;
136 if (pthread_mutex_unlock(m
))
137 debug(1, "Error releasing mutex.");
140 void connect_cleanup(void *arg
) {
141 int *fd
= (int *)arg
;
142 // debug(2, "dacp_send_command: close socket %d.",*fd);
146 void http_cleanup(void *arg
) {
147 // debug(1, "http cleanup called.");
148 struct http_roundtripper
*rt
= (struct http_roundtripper
*)arg
;
152 int dacp_send_command(const char *command
, char **body
, ssize_t
*bodysize
) {
154 // debug(1,"dacp_send_command: command is: \"%s\".",command);
156 if (dacp_server
.port
== 0) {
157 // debug(3, "No DACP port specified yet");
158 result
= 490; // no port specified
161 // will malloc space for the body or set it to NULL -- the caller should free it.
163 // Using some custom HTTP-like return codes
164 // 498 Bad Address information for the DACP server
165 // 497 Can't establish a socket to the DACP server
166 // 496 Can't connect to the DACP server
167 // 495 Error receiving response
168 // 494 This client is already busy
169 // 493 Client failed to send a message
170 // 492 Argument out of range
171 // 491 Client refused connection
172 // 490 No port specified
174 struct addrinfo hints
, *res
;
177 struct HttpResponse response
;
178 response
.body
= NULL
;
179 response
.malloced_size
= 0;
183 char portstring
[10], server
[1024], message
[1024];
184 memset(&portstring
, 0, sizeof(portstring
));
185 if (dacp_server
.connection_family
== AF_INET6
) {
186 snprintf(server
, sizeof(server
), "%s%%%u", dacp_server
.ip_string
, dacp_server
.scope_id
);
188 strcpy(server
, dacp_server
.ip_string
);
190 snprintf(portstring
, sizeof(portstring
), "%u", dacp_server
.port
);
192 // first, load up address structs with getaddrinfo():
194 memset(&hints
, 0, sizeof(hints
));
195 hints
.ai_family
= AF_UNSPEC
;
196 hints
.ai_socktype
= SOCK_STREAM
;
198 // debug(1, "DACP port string is \"%s:%s\".", server, portstring);
200 int ires
= getaddrinfo(server
, portstring
, &hints
, &res
);
202 // debug(1,"Error %d \"%s\" at getaddrinfo.",ires,gai_strerror(ires));
203 response
.code
= 498; // Bad Address information for the DACP server
205 uint64_t start_time
= get_absolute_time_in_ns();
206 pthread_cleanup_push(addrinfo_cleanup
, (void *)&res
);
207 // only do this one at a time -- not sure it is necessary, but better safe than sorry
209 // int mutex_reply = sps_pthread_mutex_timedlock(&dacp_conversation_lock, 2000000, command,
211 int mutex_reply
= debug_mutex_lock(&dacp_conversation_lock
, 2000000, 1);
212 // int mutex_reply = pthread_mutex_lock(&dacp_conversation_lock);
213 if (mutex_reply
== 0) {
214 pthread_cleanup_push(mutex_lock_cleanup
, (void *)&dacp_conversation_lock
);
217 sockfd
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
220 // debug(1, "DACP socket could not be created -- error %d:
221 // \"%s\".",errno,strerror(errno));
222 response
.code
= 497; // Can't establish a socket to the DACP server
224 pthread_cleanup_push(connect_cleanup
, (void *)&sockfd
);
225 // debug(2, "dacp_send_command: open socket %d.",sockfd);
227 // This is for limiting the time to be spent waiting for a response.
232 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVTIMEO
, (const char *)&tv
, sizeof tv
) == -1)
233 debug(1, "dacp_send_command: error %d setting receive timeout.", errno
);
234 if (setsockopt(sockfd
, SOL_SOCKET
, SO_SNDTIMEO
, (const char *)&tv
, sizeof tv
) == -1)
235 debug(1, "dacp_send_command: error %d setting send timeout.", errno
);
238 // debug(1, "DACP socket created.");
239 if (connect(sockfd
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
240 // debug(1, "dacp_send_command: connect failed with errno %d.", errno);
241 if (errno
== ECONNREFUSED
)
242 response
.code
= 491; // DACP server doesn't want to talk anymore...
244 response
.code
= 496; // Can't connect to the DACP server
246 // debug(1,"DACP connect succeeded.");
248 snprintf(message
, sizeof(message
),
249 "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %s\r\n\r\n",
250 command
, dacp_server
.ip_string
, dacp_server
.port
,
251 dacp_server
.active_remote_id
);
254 debug(3, "dacp_send_command: \"%s\".", command
);
255 ssize_t wresp
= send(sockfd
, message
, strlen(message
), 0);
257 char errorstring
[1024];
258 strerror_r(errno
, (char *)errorstring
, sizeof(errorstring
));
259 debug(2, "dacp_send_command: write error %d: \"%s\".", errno
, (char *)errorstring
);
260 struct linger so_linger
;
261 so_linger
.l_onoff
= 1; // "true"
262 so_linger
.l_linger
= 0;
263 int err
= setsockopt(sockfd
, SOL_SOCKET
, SO_LINGER
, &so_linger
, sizeof so_linger
);
265 debug(1, "Could not set the dacp socket to abort due to a write error on closing.");
267 if (wresp
!= (ssize_t
)strlen(message
)) {
268 // debug(1, "dacp_send_command: send failed.");
269 response
.code
= 493; // Client failed to send a message
273 response
.body
= malloc(2048); // it can resize this if necessary
274 response
.malloced_size
= 2048;
275 pthread_cleanup_push(malloc_cleanup
, response
.body
);
277 struct http_roundtripper rt
;
278 http_init(&rt
, responseFuncs
, &response
);
279 pthread_cleanup_push(http_cleanup
, &rt
);
284 memset(buffer
, 0, sizeof(buffer
));
285 while (needmore
&& !looperror
) {
286 const char *data
= buffer
;
287 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVTIMEO
, (const char *)&tv
, sizeof tv
) == -1)
288 debug(1, "dacp_send_command: error %d setting receive timeout.", errno
);
289 ssize_t ndata
= recv(sockfd
, buffer
, sizeof(buffer
), 0);
290 // debug(3, "Received %d bytes: \"%s\".", ndata, buffer);
293 char errorstring
[1024];
294 strerror_r(errno
, (char *)errorstring
, sizeof(errorstring
));
295 debug(2, "dacp_send_command: receiving error %d: \"%s\".", errno
,
296 (char *)errorstring
);
297 struct linger so_linger
;
298 so_linger
.l_onoff
= 1; // "true"
299 so_linger
.l_linger
= 0;
301 setsockopt(sockfd
, SOL_SOCKET
, SO_LINGER
, &so_linger
, sizeof so_linger
);
305 "Could not set the dacp socket to abort due to a read error on closing.");
309 response
.body
= NULL
;
310 response
.malloced_size
= 0;
312 response
.code
= 495; // Error receiving response
316 while (needmore
&& ndata
&& !looperror
) {
318 needmore
= http_data(&rt
, data
, ndata
, &read
);
324 if (http_iserror(&rt
)) {
325 debug(3, "dacp_send_command: error parsing data.");
327 response
.body
= NULL
;
328 response
.malloced_size
= 0;
331 // debug(1,"Size of response body is %d",response.size);
332 pthread_cleanup_pop(1); // this should call http_cleanup
335 0); // this should *not* free the malloced buffer -- just pop the malloc cleanup
338 pthread_cleanup_pop(1); // this should close the socket
340 // debug(1,"DACP socket closed.");
342 pthread_cleanup_pop(1); // this should unlock the dacp_conversation_lock);
343 // pthread_mutex_unlock(&dacp_conversation_lock);
344 // debug(1,"Sent command\"%s\" with a response body of size %d.",command,response.size);
345 // debug(1,"dacp_conversation_lock released.");
348 "dacp_send_command: could not acquire a lock on the dacp transmit/receive section "
349 "when attempting to "
350 "send the command \"%s\". Possible timeout?",
352 response
.code
= 494; // This client is already busy
354 pthread_cleanup_pop(1); // this should free the addrinfo
355 // freeaddrinfo(res);
356 uint64_t et
= get_absolute_time_in_ns() - start_time
; // this will be in nanoseconds
357 debug(3, "dacp_send_command: %f seconds, response code %d, command \"%s\".",
358 (1.0 * et
) / 1000000000, response
.code
, command
);
360 *body
= response
.body
;
361 *bodysize
= response
.size
;
362 result
= response
.code
;
367 int send_simple_dacp_command(const char *command
) {
369 char *server_reply
= NULL
;
370 debug(2, "send_simple_dacp_command: sending command \"%s\".", command
);
371 ssize_t reply_size
= 0;
372 reply
= dacp_send_command(command
, &server_reply
, &reply_size
);
380 void relinquish_dacp_server_information(rtsp_conn_info
*conn
) {
381 // this will set the dacp_server.players_connection_thread_index to zero iff it has the same value
382 // as the conn's connection number
383 // this is to signify that the player has stopped, but only if another thread (with a different
384 // index) hasn't already taken over the dacp service
385 debug_mutex_lock(&dacp_server_information_lock
, 500000, 2);
386 if (dacp_server
.players_connection_thread_index
== conn
->connection_number
)
387 dacp_server
.players_connection_thread_index
= 0;
388 debug_mutex_unlock(&dacp_server_information_lock
, 3);
391 // this will be running on the thread of its caller, not of the conversation thread...
392 // tell the DACP conversation thread what DACP server we are listening to
393 // if the active_remote_id is the same we don't change anything apart from
394 // the conversation number
395 // Thus, we can keep the DACP port that might have previously been discovered
396 void set_dacp_server_information(rtsp_conn_info
*conn
) {
397 // debug(1, "set_dacp_server_information");
398 debug_mutex_lock(&dacp_server_information_lock
, 500000, 2);
399 dacp_server
.players_connection_thread_index
= conn
->connection_number
;
401 if ((conn
->dacp_id
== NULL
) || (strcmp(conn
->dacp_id
, dacp_server
.dacp_id
) != 0)) {
403 strncpy(dacp_server
.dacp_id
, conn
->dacp_id
, sizeof(dacp_server
.dacp_id
) - 1);
405 dacp_server
.dacp_id
[0] = '\0';
406 dacp_server
.port
= 0;
407 dacp_server
.scan_enable
= 0;
408 dacp_server
.connection_family
= conn
->connection_ip_family
;
409 dacp_server
.scope_id
= conn
->self_scope_id
;
410 strncpy(dacp_server
.ip_string
, conn
->client_ip_string
, INET6_ADDRSTRLEN
);
411 debug(2, "set_dacp_server_information set IP to \"%s\" and DACP id to \"%s\".",
412 dacp_server
.ip_string
, dacp_server
.dacp_id
);
416 "long polling" is not implemented by Shairport Sync, whereby by sending the client the
417 last-received revision number, the link will hang until a change occurs.
419 Instead, at present, Shairport Sync always uses a revision number of 1.
423 // always use revision number 1
424 dacp_server
.always_use_revision_number_1
= 1;
426 metadata_hub_modify_prolog();
427 int ch
= metadata_store
.dacp_server_active
!= dacp_server
.scan_enable
;
428 metadata_store
.dacp_server_active
= dacp_server
.scan_enable
;
429 if ((metadata_store
.client_ip
== NULL
) ||
430 (strncmp(metadata_store
.client_ip
, conn
->client_ip_string
, INET6_ADDRSTRLEN
) != 0)) {
431 if (metadata_store
.client_ip
)
432 free(metadata_store
.client_ip
);
433 metadata_store
.client_ip
= strndup(conn
->client_ip_string
, INET6_ADDRSTRLEN
);
434 debug(3, "MH Client IP set to: \"%s\"", metadata_store
.client_ip
);
437 metadata_hub_modify_epilog(ch
);
439 if (dacp_server
.port
) {
440 // debug(1, "Re-enable scanning.");
441 dacp_server
.scan_enable
= 1;
442 // metadata_hub_modify_prolog();
443 // int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
444 // metadata_store.dacp_server_active = dacp_server.scan_enable;
445 // metadata_hub_modify_epilog(ch);
448 if (dacp_server
.active_remote_id
)
449 free(dacp_server
.active_remote_id
);
450 if (conn
->dacp_active_remote
)
451 dacp_server
.active_remote_id
=
452 strdup(conn
->dacp_active_remote
); // even if the dacp_id remains the same,
453 // the active remote will change.
455 dacp_server
.active_remote_id
= NULL
;
457 debug(3, "set_dacp_server_information set active-remote id to %s.", dacp_server
.active_remote_id
);
458 pthread_cond_signal(&dacp_server_information_cv
);
459 debug_mutex_unlock(&dacp_server_information_lock
, 3);
462 void dacp_monitor_port_update_callback(char *dacp_id
, uint16_t port
) {
463 debug_mutex_lock(&dacp_server_information_lock
, 500000, 2);
465 "dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
467 dacp_id
, dacp_server
.dacp_id
, port
);
468 if ((dacp_id
== NULL
) || (dacp_server
.dacp_id
[0] == '\0')) {
469 warn("dacp_id or dacp_server.dacp_id NULL detected");
471 if (strcmp(dacp_id
, dacp_server
.dacp_id
) == 0) {
472 dacp_server
.port
= port
;
474 dacp_server
.scan_enable
= 0;
476 dacp_server
.scan_enable
= 1;
477 // debug(2, "dacp_monitor_port_update_callback enables scan");
479 // metadata_hub_modify_prolog();
480 // int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
481 // metadata_store.dacp_server_active = dacp_server.scan_enable;
482 // metadata_hub_modify_epilog(ch);
484 debug(2, "dacp port monitor reporting on an out-of-use remote.");
487 pthread_cond_signal(&dacp_server_information_cv
);
488 debug_mutex_unlock(&dacp_server_information_lock
, 3);
491 void *dacp_monitor_thread_code(__attribute__((unused
)) void *na
) {
493 int always_use_revision_number_1
= 0;
494 // char server_reply[10000];
495 // debug(1, "DACP monitor thread started.");
496 // wait until we get a valid port number to begin monitoring it
497 int32_t revision_number
= 1;
498 int bad_result_count
= 0;
499 int idle_scan_count
= 0;
503 pthread_cleanup_debug_mutex_lock(&dacp_server_information_lock
, 500000, 2);
504 if (dacp_server
.scan_enable
== 0) {
505 metadata_hub_modify_prolog();
506 int ch
= (metadata_store
.dacp_server_active
!= 0) ||
507 (metadata_store
.advanced_dacp_server_active
!= 0);
508 metadata_store
.dacp_server_active
= 0;
509 metadata_store
.advanced_dacp_server_active
= 0;
512 "setting metadata_store.dacp_server_active and "
513 "metadata_store.advanced_dacp_server_active to 0 with an update "
517 metadata_hub_modify_epilog(ch
);
519 uint64_t time_to_wait_for_wakeup_ns
=
520 (uint64_t)(1000000000 * config
.missing_port_dacp_scan_interval_seconds
);
522 #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
523 uint64_t time_of_wakeup_ns
= get_realtime_in_ns() + time_to_wait_for_wakeup_ns
;
524 uint64_t sec
= time_of_wakeup_ns
/ 1000000000;
525 uint64_t nsec
= time_of_wakeup_ns
% 1000000000;
527 #ifdef COMPILE_FOR_OSX
528 uint64_t sec
= time_to_wait_for_wakeup_ns
/ 1000000000;
529 uint64_t nsec
= time_to_wait_for_wakeup_ns
% 1000000000;
532 struct timespec time_to_wait
;
533 time_to_wait
.tv_sec
= sec
;
534 time_to_wait
.tv_nsec
= nsec
;
536 while ((dacp_server
.scan_enable
== 0) && (result
!= ETIMEDOUT
)) {
537 // debug(1, "dacp_monitor_thread_code wait for an event to possibly enable scan");
539 #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
540 result
= pthread_cond_timedwait(&dacp_server_information_cv
, &dacp_server_information_lock
,
541 &time_to_wait
); // this is a pthread cancellation point
542 // debug(1, "result is %d, dacp_server.scan_enable is %d, time_to_wait_for_wakeup_ns is %"
543 // PRId64 ".", result, dacp_server.scan_enable, time_to_wait_for_wakeup_ns);
546 #ifdef COMPILE_FOR_OSX
547 result
= pthread_cond_timedwait_relative_np(&dacp_server_information_cv
,
548 &dacp_server_information_lock
, &time_to_wait
);
551 if (dacp_server
.scan_enable
== 1) {
552 bad_result_count
= 0;
557 always_use_revision_number_1
=
558 dacp_server
.always_use_revision_number_1
; // set this while access is locked
560 result
= dacp_get_volume(&the_volume
); // just want the http code
561 pthread_cleanup_pop(1);
563 if (result
== 490) { // 490 means no port was specified
564 if (strlen(dacp_server
.dacp_id
) != 0) {
565 // debug(1,"mdns_dacp_monitor_set_id");
566 mdns_dacp_monitor_set_id(dacp_server
.dacp_id
);
570 // debug(1,"DACP Scan Result: %d.", result);
572 if ((result
== 200) || (result
== 400)) {
573 bad_result_count
= 0;
575 if (bad_result_count
< config
.scan_max_bad_response_count
) // limit to some reasonable value
579 // here, do the debouncing calculations to see
580 // if the dacp server and the
581 // advanced dacp server are available
583 // -1 means we don't know because some bad statuses have been reported
584 // 0 means definitely no
585 // +1 means definitely yes
587 int dacp_server_status_now
= -1;
588 int advanced_dacp_server_status_now
= -1;
590 if (bad_result_count
== 0) {
591 dacp_server_status_now
= 1;
593 advanced_dacp_server_status_now
= 1;
594 else if (result
== 400)
595 advanced_dacp_server_status_now
= 0;
596 } else if (bad_result_count
==
597 config
.scan_max_bad_response_count
) { // if a sequence of bad return codes occurs,
599 dacp_server_status_now
= 0;
600 advanced_dacp_server_status_now
= 0;
603 if (metadata_store
.player_thread_active
== 0)
608 debug(3, "Scan Result: %d, Bad Scan Count: %d, Idle Scan Count: %d.", result
,
609 bad_result_count
, idle_scan_count
);
612 // decide if idle for too long
613 if (idle_scan_count == config.scan_max_inactive_count) {
614 debug(2, "DACP server status scanning stopped.");
615 dacp_server.scan_enable = 0;
619 int update_needed
= 0;
620 metadata_hub_modify_prolog();
621 if (dacp_server_status_now
!= -1) { // if dacp_server_status_now is actually known...
622 if (metadata_store
.dacp_server_active
!= dacp_server_status_now
) {
623 debug(2, "metadata_store.dacp_server_active set to %d.", dacp_server_status_now
);
624 metadata_store
.dacp_server_active
= dacp_server_status_now
;
628 if (advanced_dacp_server_status_now
!=
629 -1) { // if advanced_dacp_server_status_now is actually known...
630 if (metadata_store
.advanced_dacp_server_active
!= advanced_dacp_server_status_now
) {
631 debug(2, "metadata_store.advanced_dacp_server_active set to %d.", dacp_server_status_now
);
632 metadata_store
.advanced_dacp_server_active
= advanced_dacp_server_status_now
;
637 metadata_hub_modify_epilog(update_needed
);
639 // pthread_mutex_unlock(&dacp_server_information_lock);
640 // debug(1, "DACP Server ID \"%u\" at \"%s:%u\", scan %d.", dacp_server.active_remote_id,
641 // dacp_server.ip_string, dacp_server.port, scan_index);
644 metadata_hub_modify_prolog();
645 int diff
= metadata_store
.speaker_volume
!= the_volume
;
647 metadata_store
.speaker_volume
= the_volume
;
648 metadata_hub_modify_epilog(diff
);
651 char *response
= NULL
;
653 char command
[1024] = "";
654 if (always_use_revision_number_1
!= 0) // see the "long polling" note above
656 snprintf(command
, sizeof(command
) - 1, "playstatusupdate?revision-number=%d",
658 // debug(1,"dacp_monitor_thread_code: command: \"%s\"",command);
659 result
= dacp_send_command(command
, &response
, &le
);
660 // debug(1,"Response to \"%s\" is %d.",command,result);
661 // remember: unless the revision_number you pass in is 1,
662 // response will be 200 only if there's something new to report.
667 // here start looking for the contents of the status update
668 if (dacp_tlv_crawl(&sp
, &item_size
) == 'cmst') { // status
669 // here, we know that we are receiving playerstatusupdates, so set a flag
670 metadata_hub_modify_prolog();
671 // debug(1, "playstatusupdate release track metadata");
672 // metadata_hub_reset_track_metadata();
673 // metadata_store.playerstatusupdates_are_received = 1;
674 sp
-= item_size
; // drop down into the array -- don't skip over it
676 // char typestring[5];
677 // we need to acquire the metadata data structure and possibly update it
679 uint32_t type
= dacp_tlv_crawl(&sp
, &item_size
);
690 case 'cmsr': // revision number
692 revision_number
= ntohl(*(uint32_t *)(t
));
693 // debug(1,"New revision number received: %d", revision_number);
695 case 'caps': // play status
697 r
= *(unsigned char *)(t
);
700 if (metadata_store
.play_status
!= PS_STOPPED
) {
701 metadata_store
.play_status
= PS_STOPPED
;
702 debug(2, "Play status is \"stopped\".");
706 if (metadata_store
.play_status
!= PS_PAUSED
) {
707 metadata_store
.play_status
= PS_PAUSED
;
708 debug(2, "Play status is \"paused\".");
712 if (metadata_store
.play_status
!= PS_PLAYING
) {
713 metadata_store
.play_status
= PS_PLAYING
;
714 debug(2, "Play status changed to \"playing\".");
718 debug(1, "Unrecognised play status %d received.", r
);
722 case 'cash': // shuffle status
724 r
= *(unsigned char *)(t
);
727 if (metadata_store
.shuffle_status
!= SS_OFF
) {
728 metadata_store
.shuffle_status
= SS_OFF
;
729 debug(2, "Shuffle status is \"off\".");
733 if (metadata_store
.shuffle_status
!= SS_ON
) {
734 metadata_store
.shuffle_status
= SS_ON
;
735 debug(2, "Shuffle status is \"on\".");
739 debug(1, "Unrecognised shuffle status %d received.", r
);
743 case 'carp': // repeat status
745 r
= *(unsigned char *)(t
);
748 if (metadata_store
.repeat_status
!= RS_OFF
) {
749 metadata_store
.repeat_status
= RS_OFF
;
750 debug(2, "Repeat status is \"none\".");
754 if (metadata_store
.repeat_status
!= RS_ONE
) {
755 metadata_store
.repeat_status
= RS_ONE
;
756 debug(2, "Repeat status is \"one\".");
760 if (metadata_store
.repeat_status
!= RS_ALL
) {
761 metadata_store
.repeat_status
= RS_ALL
;
762 debug(2, "Repeat status is \"all\".");
766 debug(1, "Unrecognised repeat status %d received.", r
);
770 case 'cann': // track name
771 debug(2, "DACP Track Name seen");
772 if (string_update_with_size(&metadata_store
.track_name
,
773 &metadata_store
.track_name_changed
, sp
- item_size
,
775 debug(2, "DACP Track Name set to: \"%s\"", metadata_store
.track_name
);
778 case 'cana': // artist name
779 debug(2, "DACP Artist Name seen");
780 if (string_update_with_size(&metadata_store
.artist_name
,
781 &metadata_store
.artist_name_changed
, sp
- item_size
,
783 debug(2, "DACP Artist Name set to: \"%s\"", metadata_store
.artist_name
);
786 case 'canl': // album name
787 debug(2, "DACP Album Name seen");
788 if (string_update_with_size(&metadata_store
.album_name
,
789 &metadata_store
.album_name_changed
, sp
- item_size
,
791 debug(2, "DACP Album Name set to: \"%s\"", metadata_store
.album_name
);
794 case 'cang': // genre
795 debug(2, "DACP Genre seen");
796 if (string_update_with_size(&metadata_store
.genre
, &metadata_store
.genre_changed
,
797 sp
- item_size
, item_size
)) {
798 debug(2, "DACP Genre set to: \"%s\"", metadata_store
.genre
);
801 case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware
802 // see reference above)
803 debug(2, "DACP Composite ID seen");
804 if ((metadata_store
.item_composite_id_is_valid
== 0) ||
805 (memcmp(metadata_store
.item_composite_id
, sp
- item_size
,
806 sizeof(metadata_store
.item_composite_id
)) != 0)) {
807 memcpy(metadata_store
.item_composite_id
, sp
- item_size
,
808 sizeof(metadata_store
.item_composite_id
));
812 for (it
= 0; it
< 16; it
++) {
813 snprintf(pt
, 3, "%02X", metadata_store
.item_composite_id
[it
]);
817 debug(2, "Item composite ID changed to 0x%s.", st
);
818 metadata_store
.item_composite_id_changed
= 1;
819 metadata_store
.item_composite_id_is_valid
= 1;
824 ui
= ntohl(*(uint32_t *)(t
));
825 debug(2, "DACP Song Time seen: \"%u\" of length %u.", ui
, item_size
);
826 if (ui
!= metadata_store
.songtime_in_milliseconds
) {
827 metadata_store
.songtime_in_milliseconds
= ui
;
828 metadata_store
.songtime_in_milliseconds_changed
= 1;
829 metadata_store
.songtime_in_milliseconds_is_valid
= 1;
830 debug(2, "DACP Song Time set to: \"%u\"",
831 metadata_store
.songtime_in_milliseconds
);
843 r = ntohl(*(uint32_t *)(t));
847 for (i = 0; i < item_size; i++) {
848 printf("%02x", *t & 0xff);
855 s = ntohl(*(uint32_t *)(t));
858 v = (ntohl(*(uint32_t *)(t))) & 0xffffffff;
863 for (i = 0; i < item_size; i++) {
864 printf("%02x", *t & 0xff);
874 for (i = 0; i < item_size; i++) {
875 printf("%02x", *t & 0xff);
884 // finished possibly writing to the metadata hub
885 metadata_hub_modify_epilog(
886 1); // should really see if this can be made responsive to changes
888 debug(1, "Status Update not found.\n");
891 debug(1, "Can't find any content in playerstatusupdate request");
895 debug(1, "Unexpected response %d to playerstatusupdate request", result);
903 strcpy(command,"nowplayingartwork?mw=320&mh=320");
904 debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
909 strcpy(command,"getproperty?properties=dmcp.volume");
910 debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
915 strcpy(command,"setproperty?dmcp.volume=100.000000");
916 debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
922 if (metadata_store
.player_thread_active
)
923 sleep(config
.scan_interval_when_active
);
925 sleep(config
.scan_interval_when_inactive
);
928 debug(1, "DACP monitor thread exiting -- should never happen.");
932 void dacp_monitor_start() {
935 rc
= pthread_cond_init(&dacp_server_information_cv
, NULL
);
937 debug(1, "Error initialising the DACP Server Information Condition Variable");
939 pthread_mutexattr_t mta
;
941 rc
= pthread_mutexattr_init(&mta
);
943 debug(1, "Error creating the DACP Conversation Lock Mutex Att Init");
945 rc
= pthread_mutexattr_settype(&mta
, PTHREAD_MUTEX_ERRORCHECK
);
947 debug(1, "Error creating the DACP Conversation Lock Mutex Errorcheck");
949 // rc = pthread_mutexattr_setname_np(&mta, "DACP Conversation Lock");
951 // debug(1,"Error creating the DACP Conversation Lock Mutex Set Name");
953 rc
= pthread_mutex_init(&dacp_conversation_lock
, &mta
);
955 debug(1, "Error creating the DACP Conversation Lock Mutex Init");
957 // debug(1, "DACP Conversation Lock Mutex Init");
959 rc
= pthread_mutexattr_destroy(&mta
);
961 debug(1, "Error creating the DACP Conversation Lock Attr Destroy");
963 rc
= pthread_mutexattr_init(&mta
);
965 debug(1, "Error creating the DACP Server Information Lock Mutex Att Init");
967 rc
= pthread_mutexattr_settype(&mta
, PTHREAD_MUTEX_ERRORCHECK
);
969 debug(1, "Error creating the DACP Server Information Lock Mutex Errorcheck");
971 // rc = pthread_mutexattr_setname_np(&mta, "DACP Conversation Lock");
973 // debug(1,"Error creating the DACP Server Information Lock Mutex Set Name");
975 rc
= pthread_mutex_init(&dacp_server_information_lock
, &mta
);
977 debug(1, "Error creating the DACP Server Information Lock Mutex Init");
979 rc
= pthread_mutexattr_destroy(&mta
);
981 debug(1, "Error creating the DACP Server Information Lock Attr Destroy");
983 memset(&dacp_server
, 0, sizeof(dacp_server_record
));
985 pthread_create(&dacp_monitor_thread
, NULL
, dacp_monitor_thread_code
, NULL
);
986 dacp_monitor_initialised
= 1;
989 void dacp_monitor_stop() {
990 if (dacp_monitor_initialised
) { // only if it's been started and initialised
991 debug(2, "dacp_monitor_stop");
992 pthread_cancel(dacp_monitor_thread
);
993 pthread_join(dacp_monitor_thread
, NULL
);
994 pthread_mutex_destroy(&dacp_server_information_lock
);
995 debug(3, "DACP Conversation Lock Mutex Destroyed");
996 pthread_mutex_destroy(&dacp_conversation_lock
);
997 pthread_cond_destroy(&dacp_server_information_cv
);
998 debug(3, "DACP Server Information Condition Variable destroyed.");
999 if (dacp_server
.active_remote_id
) {
1000 free(dacp_server
.active_remote_id
);
1001 dacp_server
.active_remote_id
= NULL
;
1006 uint32_t dacp_tlv_crawl(char **p
, int32_t *length
) {
1008 memcpy(typecode
, *p
, 4);
1010 uint32_t type
= ntohl(*(uint32_t *)*p
);
1012 *length
= ntohl(*(uint32_t *)*p
);
1014 // debug(1,"Type seen: '%s' of length %d",typecode,*length);
1018 int dacp_get_client_volume(int32_t *result
) {
1019 // debug(1,"dacp_get_client_volume");
1020 char *server_reply
= NULL
;
1021 int32_t overall_volume
= -1;
1023 // debug(1,"dacp_get_client_volume: dacp_send_command");
1025 dacp_send_command("getproperty?properties=dmcp.volume", &server_reply
, &reply_size
);
1026 if (response
== 200) { // if we get an okay
1027 char *sp
= server_reply
;
1029 if (reply_size
>= 8) {
1030 if (dacp_tlv_crawl(&sp
, &item_size
) == 'cmgt') {
1031 sp
-= item_size
; // drop down into the array -- don't skip over it
1033 while (reply_size
>= 8) {
1034 uint32_t type
= dacp_tlv_crawl(&sp
, &item_size
);
1035 reply_size
-= item_size
+ 8;
1036 if (type
== 'cmvo') { // drop down into the dictionary -- don't skip over it
1037 char *t
= sp
- item_size
;
1038 overall_volume
= ntohl(*(uint32_t *)(t
));
1042 debug(1, "Unexpected payload response from getproperty?properties=dmcp.volume");
1045 debug(1, "Too short a response from getproperty?properties=dmcp.volume");
1047 // debug(1, "Overall Volume is %d.", overall_volume);
1051 // debug(1, "Freeing response memory.");
1053 server_reply
= NULL
;
1057 *result
= overall_volume
;
1058 // debug(1,"dacp_get_client_volume returns: %" PRId32 ".",overall_volume);
1063 int dacp_set_include_speaker_volume(int64_t machine_number
, int32_t vo
) {
1064 debug(2, "dacp_set_include_speaker_volume to %" PRId32
".", vo
);
1066 memset(message
, 0, sizeof(message
));
1067 snprintf(message
, sizeof(message
),
1068 "setproperty?include-speaker-id=%" PRId64
"&dmcp.volume=%" PRId32
"", machine_number
,
1070 debug(2, "sending \"%s\"", message
);
1071 return send_simple_dacp_command(message
);
1072 // should return 204
1075 int dacp_set_speaker_volume(int64_t machine_number
, int32_t vo
) {
1077 memset(message
, 0, sizeof(message
));
1078 snprintf(message
, sizeof(message
), "setproperty?speaker-id=%" PRId64
"&dmcp.volume=%" PRId32
"",
1079 machine_number
, vo
);
1080 debug(2, "sending \"%s\"", message
);
1081 return send_simple_dacp_command(message
);
1082 // should return 204
1085 int dacp_get_speaker_list(dacp_spkr_stuff
*speaker_info
, int max_size_of_array
,
1086 int *actual_speaker_count
) {
1087 // char typestring[5];
1088 char *server_reply
= NULL
;
1089 int speaker_index
= -1; // will be incremented before use
1090 int speaker_count
= -1; // will be fixed if there is no problem
1093 // debug(1,"dacp_speaker_list: dacp_send_command");
1094 int response
= dacp_send_command("getspeakers", &server_reply
, &le
);
1095 if (response
== 200) {
1096 char *sp
= server_reply
;
1099 if (dacp_tlv_crawl(&sp
, &item_size
) == 'casp') {
1100 // debug(1,"Speakers:",item_size);
1101 sp
-= item_size
; // drop down into the array -- don't skip over it
1104 uint32_t type
= dacp_tlv_crawl(&sp
, &item_size
);
1105 if (type
== 'mdcl') { // drop down into the dictionary -- don't skip over it
1106 // debug(1,">>>> Dictionary:");
1110 if (speaker_index
== max_size_of_array
) {
1111 return 413; // Payload Too Large -- too many speakers
1113 speaker_info
[speaker_index
].active
= 0;
1114 speaker_info
[speaker_index
].speaker_number
= 0;
1115 speaker_info
[speaker_index
].volume
= 0;
1116 speaker_info
[speaker_index
].name
[0] = '\0';
1118 le
-= item_size
+ 8;
1126 strncpy((char *)&speaker_info
[speaker_index
].name
, t
,
1127 sizeof(speaker_info
[speaker_index
].name
));
1128 speaker_info
[speaker_index
].name
[sizeof(speaker_info
[speaker_index
].name
) - 1] =
1129 '\0'; // just in case
1133 r
= ntohl(*(uint32_t *)(t
));
1134 speaker_info
[speaker_index
].volume
= r
;
1135 // debug(1,"The individual volume of speaker \"%s\" is
1136 // \"%d\".",speaker_info[speaker_index].name,r);
1140 s
= ntohl(*(uint32_t *)(t
));
1143 v
= (ntohl(*(uint32_t *)(t
))) & 0xffffffff;
1145 speaker_info
[speaker_index
].speaker_number
= s
;
1146 // debug(1,"Speaker machine number: %ld",s);
1150 speaker_info
[speaker_index
].active
= 1;
1158 *(uint32_t *)typestring = htonl(type);
1165 debug(1,"Type: '%s' Value: \"%d\".",typestring,u);
1173 // debug(1,"Total of %d speakers found. Here are the active ones:",speaker_index+1);
1174 speaker_count
= speaker_index
+ 1; // number of speaker entries in the array
1176 debug(1, "Speaker array not found.");
1180 for (i=0;i<le;i++) {
1182 debug(1,"%d %02x", i, *sp);
1184 debug(1,"%d %02x '%c'", i, *sp,*sp);
1189 debug(1, "Can't find any content in dacp speakers request");
1192 server_reply
= NULL
;
1194 // debug(1, "Unexpected response %d to dacp speakers request", response);
1196 debug(1, "Freeing response memory.");
1198 server_reply
= NULL
;
1201 if (actual_speaker_count
)
1202 *actual_speaker_count
= speaker_count
;
1206 int dacp_get_volume(int32_t *the_actual_volume
) {
1207 // get the speaker volume information from the DACP source and store it in the metadata_hub
1208 // A volume command has been sent from the client
1209 // let's get the master volume from the DACP remote control
1210 struct dacp_speaker_stuff speaker_info
[50];
1211 // we need the overall volume and the speakers information to get this device's relative volume to
1212 // calculate the real volume
1214 int32_t overall_volume
= 0;
1215 int32_t actual_volume
= 0;
1216 int http_response
= dacp_get_client_volume(&overall_volume
);
1217 if (http_response
== 200) {
1218 // debug(1,"Overall volume is: %u.",overall_volume);
1219 int speaker_count
= 0;
1220 http_response
= dacp_get_speaker_list((dacp_spkr_stuff
*)&speaker_info
, 50, &speaker_count
);
1221 if (http_response
== 200) {
1222 // get our machine number
1223 uint16_t *hn
= (uint16_t *)config
.ap1_prefix
;
1224 uint32_t *ln
= (uint32_t *)(config
.ap1_prefix
+ 2);
1225 uint64_t t1
= ntohs(*hn
);
1226 uint64_t t2
= ntohl(*ln
);
1227 int64_t machine_number
= (t1
<< 32) + t2
; // this form is useful
1229 // Let's find our own speaker in the array and pick up its relative volume
1231 int32_t relative_volume
= 0;
1232 for (i
= 0; i
< speaker_count
; i
++) {
1233 if (speaker_info
[i
].speaker_number
== machine_number
) {
1234 relative_volume
= speaker_info
[i
].volume
;
1236 debug(1,"Our speaker was found with a relative volume of: %u.",relative_volume);
1238 if (speaker_info[i].active)
1239 debug(1,"Our speaker is active.");
1241 debug(1,"Our speaker is inactive.");
1245 actual_volume
= (overall_volume
* relative_volume
+ 50) / 100;
1246 // debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
1247 // %d.",overall_volume,relative_volume,actual_volume);
1248 // debug(1,"Our actual speaker volume is %d.",actual_volume);
1249 // metadata_hub_modify_prolog();
1250 // metadata_store.speaker_volume = actual_volume;
1251 // metadata_hub_modify_epilog(1);
1253 debug(2, "Unexpected return code %d from dacp_get_speaker_list.", http_response
);
1255 } else if ((http_response
!= 400) && (http_response
!= 490)) {
1256 debug(3, "Unexpected return code %d from dacp_get_client_volume.", http_response
);
1258 if (the_actual_volume
) {
1259 // debug(1,"dacp_get_volume returns %d.",actual_volume);
1260 *the_actual_volume
= actual_volume
;
1262 return http_response
;
1265 int dacp_set_volume(int32_t vo
) {
1266 int http_response
= 492; // argument out of range
1267 if ((vo
>= 0) && (vo
<= 100)) {
1268 // get the information we need -- the absolute volume, the speaker list, our ID
1269 struct dacp_speaker_stuff speaker_info
[50];
1270 int32_t overall_volume
;
1271 http_response
= dacp_get_client_volume(&overall_volume
);
1272 if (http_response
== 200) {
1274 http_response
= dacp_get_speaker_list((dacp_spkr_stuff
*)&speaker_info
, 50, &speaker_count
);
1275 if (http_response
== 200) {
1276 // get our machine number
1277 uint16_t *hn
= (uint16_t *)config
.ap1_prefix
;
1278 uint32_t *ln
= (uint32_t *)(config
.ap1_prefix
+ 2);
1279 uint64_t t1
= ntohs(*hn
);
1280 uint64_t t2
= ntohl(*ln
);
1281 int64_t machine_number
= (t1
<< 32) + t2
; // this form is useful
1283 // Let's find our own speaker in the array and pick up its relative volume
1285 int32_t active_speakers
= 0;
1286 for (i
= 0; i
< speaker_count
; i
++) {
1287 if (speaker_info
[i
].speaker_number
== machine_number
) {
1288 debug(2, "Our speaker number found: %ld with relative volume.", machine_number
,
1289 speaker_info
[i
].volume
);
1291 if (speaker_info
[i
].active
== 1) {
1296 if (active_speakers
== 1) {
1297 // must be just this speaker
1298 debug(2, "Remote-setting volume to %d on just one speaker.", vo
);
1299 http_response
= dacp_set_include_speaker_volume(machine_number
, vo
);
1300 } else if (active_speakers
== 0) {
1301 debug(2, "No speakers!");
1303 debug(2, "Speakers: %d, active: %d", speaker_count
, active_speakers
);
1304 if (vo
>= overall_volume
) {
1305 debug(2, "Multiple speakers active, but desired new volume is highest");
1306 http_response
= dacp_set_include_speaker_volume(machine_number
, vo
);
1308 // the desired volume is less than the current overall volume and there is more than
1311 // we must find out the highest other speaker volume.
1312 // If the desired volume is less than it, we must set the current_overall volume to
1315 // and set our volume relative to it.
1316 // If the desired volume is greater than the highest current volume, then we can just
1319 // with dacp_set_include_speaker_volume, setting the new current overall volume to the
1320 // desired new level
1321 // with the speaker at 100%
1323 int32_t highest_other_volume
= 0;
1324 for (i
= 0; i
< speaker_count
; i
++) {
1325 if ((speaker_info
[i
].speaker_number
!= machine_number
) &&
1326 (speaker_info
[i
].active
== 1) &&
1327 (speaker_info
[i
].volume
> highest_other_volume
)) {
1328 highest_other_volume
= speaker_info
[i
].volume
;
1331 highest_other_volume
= (highest_other_volume
* overall_volume
+ 50) / 100;
1332 if (highest_other_volume
<= vo
) {
1334 "Highest other volume %d is less than or equal to the desired new volume %d.",
1335 highest_other_volume
, vo
);
1336 http_response
= dacp_set_include_speaker_volume(machine_number
, vo
);
1338 debug(2, "Highest other volume %d is greater than the desired new volume %d.",
1339 highest_other_volume
, vo
);
1340 // if the present overall volume is higher than the highest other volume at present,
1341 // then bring it down to it.
1342 if (overall_volume
> highest_other_volume
) {
1343 debug(2, "Lower overall volume to new highest volume.");
1344 http_response
= dacp_set_include_speaker_volume(
1346 highest_other_volume
); // set the overall volume to the highest one
1348 if (highest_other_volume
!= 0) {
1349 int32_t desired_relative_volume
=
1350 (vo
* 100 + (highest_other_volume
/ 2)) / highest_other_volume
;
1351 debug(2, "Set our speaker volume relative to the highest volume.");
1352 http_response
= dacp_set_speaker_volume(
1354 desired_relative_volume
); // set the overall volume to the highest one
1360 debug(2, "Can't get speakers list");
1363 debug(2, "Can't get client volume");
1367 debug(2, "Invalid volume: %d -- ignored.", vo
);
1369 return http_response
;