]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
If the DACP port is zero, do a zeroconf re-broswe every two seconds in case it has...
authorMike Brady <mikebradydublin@icloud.com>
Wed, 25 Mar 2020 10:16:21 +0000 (10:16 +0000)
committerMike Brady <mikebradydublin@icloud.com>
Wed, 25 Mar 2020 10:16:21 +0000 (10:16 +0000)
common.h
dacp.c
rtsp.c
shairport.c

index ba20078ad4a910ee680c9ee2af22f4183da8880b..95f4decce5e3a64435f165c677e89c743c3a2732 100644 (file)
--- a/common.h
+++ b/common.h
@@ -100,6 +100,7 @@ typedef enum {
 const char *sps_format_description_string(sps_format_t format);
 
 typedef struct {
+  double missing_port_dacp_scan_interval_seconds; // if no DACP port number can be found, check at these intervals
   double resend_control_first_check_time; // wait this long before asking for a missing packet to be resent
   double resend_control_check_interval_time; // wait this long between making requests
   double resend_control_last_check_time; // if the packet is missing this close to the time of use, give up
diff --git a/dacp.c b/dacp.c
index 4c36de3473f4d6e306405288b02d242c06736c67..dc794d4d5b2fed71085a333fc36b6d58f5546526 100644 (file)
--- a/dacp.c
+++ b/dacp.c
@@ -1,6 +1,6 @@
 /*
  * DACP protocol handler. This file is part of Shairport Sync.
- * Copyright (c) Mike Brady 2017 -- 2019
+ * Copyright (c) Mike Brady 2017 -- 2020
  * All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person
@@ -49,7 +49,7 @@
 typedef struct {
   int players_connection_thread_index; // the connection thread index when a player thread is
                                        // associated with this, zero otherwise
-  int scan_enable;                     // set to 1 if if sacanning should be considered
+  int scan_enable;                     // set to 1 if scanning should be considered
   char dacp_id[256];                   // the DACP ID string
   uint16_t port;                       // zero if no port discovered
   short connection_family;             // AF_INET6 or AF_INET
@@ -123,7 +123,7 @@ static const struct http_funcs responseFuncs = {
 // static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t dacp_conversation_lock;
 static pthread_mutex_t dacp_server_information_lock;
-static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER;
+static pthread_cond_t dacp_server_information_cv;
 
 void addrinfo_cleanup(void *arg) {
   // debug(1, "addrinfo cleanup called.");
@@ -154,7 +154,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
   // debug(1,"dacp_send_command: command is: \"%s\".",command);
 
   if (dacp_server.port == 0) {
-    debug(1, "No DACP port specified yet");
+    debug(2, "No DACP port specified yet");
     result = 490; // no port specified
   } else {
 
@@ -169,6 +169,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
     //  493 Client failed to send a message
     //  492 Argument out of range
     //  491 Client refused connection
+    //  490 No port specified
 
     struct addrinfo hints, *res;
     int sockfd;
@@ -421,9 +422,6 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
       dacp_server.always_use_revision_number_1 = 1;
     }
 
-
-    mdns_dacp_monitor_set_id(dacp_server.dacp_id);
-
     metadata_hub_modify_prolog();
     int ch = metadata_store.dacp_server_active != dacp_server.scan_enable;
     metadata_store.dacp_server_active = dacp_server.scan_enable;
@@ -513,14 +511,40 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
             "flag value of %d",
             ch);
       metadata_hub_modify_epilog(ch);
-      while (dacp_server.scan_enable == 0) {
-        // debug(1, "dacp_monitor_thread_code wait for an event to possible enable scan");
-        pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
-        //      debug(1,"dacp_monitor_thread_code wake up.");
+
+      uint64_t time_to_wait_for_wakeup_ns = (uint64_t)(1000000000 * config.missing_port_dacp_scan_interval_seconds);
+
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
+      uint64_t time_of_wakeup_ns = get_absolute_time_in_ns() + time_to_wait_for_wakeup_ns;
+      uint64_t sec = time_of_wakeup_ns / 1000000000;
+      uint64_t nsec = time_of_wakeup_ns % 1000000000;
+#endif
+#ifdef COMPILE_FOR_OSX
+      uint64_t sec = time_to_wait_for_wakeup_ns / 1000000000;
+      uint64_t nsec = time_to_wait_for_wakeup_ns % 1000000000;
+#endif
+
+      struct timespec time_to_wait;
+      time_to_wait.tv_sec = sec;
+      time_to_wait.tv_nsec = nsec;
+
+      while ((dacp_server.scan_enable == 0) && (result != ETIMEDOUT)) {
+        // debug(1, "dacp_monitor_thread_code wait for an event to possibly enable scan");
+
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
+        result = pthread_cond_timedwait(&dacp_server_information_cv, &dacp_server_information_lock,
+                                        &time_to_wait); // this is a pthread cancellation point
+        // debug(1, "result is %d, dacp_server.scan_enable is %d, time_to_wait_for_wakeup_ns is %" PRId64 ".", result, dacp_server.scan_enable, time_to_wait_for_wakeup_ns);
+
+#endif
+#ifdef COMPILE_FOR_OSX
+        result = pthread_cond_timedwait_relative_np(&dacp_server_information_cv, &dacp_server_information_lock, &time_to_wait);
+#endif
+      }
+      if (dacp_server.scan_enable == 1) {
+        bad_result_count = 0;
+        idle_scan_count = 0;
       }
-      // so dacp_server.scan_enable will be true at this point
-      bad_result_count = 0;
-      idle_scan_count = 0;
     }
 
     always_use_revision_number_1 = dacp_server.always_use_revision_number_1; // set this while access is locked
@@ -528,360 +552,367 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
     result = dacp_get_volume(&the_volume); // just want the http code
     pthread_cleanup_pop(1);
 
-    scan_index++;
-    // debug(1,"DACP Scan Result: %d.", result);
-
-    if ((result == 200) || (result == 400)) {
-      bad_result_count = 0;
+    if (result == 490) {  // 490 means no port was specified
+      if ((dacp_server.dacp_id != NULL) && (strlen(dacp_server.dacp_id) != 0)) {
+        // debug(1,"mdns_dacp_monitor_set_id");
+        mdns_dacp_monitor_set_id(dacp_server.dacp_id);
+      }
     } else {
-      if (bad_result_count < config.scan_max_bad_response_count) // limit to some reasonable value
-        bad_result_count++;
-    }
-
-    // here, do the debouncing calculations to see
-    // if the dacp server  and the
-    // advanced dacp server are available
+      scan_index++;
+      // debug(1,"DACP Scan Result: %d.", result);
 
-    // -1 means we don't know because some bad statuses have been reported
-    // 0 means definitely no
-    // +1 means definitely yes
-
-    int dacp_server_status_now = -1;
-    int advanced_dacp_server_status_now = -1;
+      if ((result == 200) || (result == 400)) {
+        bad_result_count = 0;
+      } else {
+        if (bad_result_count < config.scan_max_bad_response_count) // limit to some reasonable value
+          bad_result_count++;
+      }
 
-    if (bad_result_count == 0) {
-      dacp_server_status_now = 1;
-      if (result == 200)
-        advanced_dacp_server_status_now = 1;
-      else if (result == 400)
+      // here, do the debouncing calculations to see
+      // if the dacp server  and the
+      // advanced dacp server are available
+
+      // -1 means we don't know because some bad statuses have been reported
+      // 0 means definitely no
+      // +1 means definitely yes
+
+      int dacp_server_status_now = -1;
+      int advanced_dacp_server_status_now = -1;
+
+      if (bad_result_count == 0) {
+        dacp_server_status_now = 1;
+        if (result == 200)
+          advanced_dacp_server_status_now = 1;
+        else if (result == 400)
+          advanced_dacp_server_status_now = 0;
+      } else if (bad_result_count ==
+                 config.scan_max_bad_response_count) { // if a sequence of bad return codes occurs,
+                                                       // then it's gone
+        dacp_server_status_now = 0;
         advanced_dacp_server_status_now = 0;
-    } else if (bad_result_count ==
-               config.scan_max_bad_response_count) { // if a sequence of bad return codes occurs,
-                                                     // then it's gone
-      dacp_server_status_now = 0;
-      advanced_dacp_server_status_now = 0;
-    }
+      }
 
-    if (metadata_store.player_thread_active == 0)
-      idle_scan_count++;
-    else
-      idle_scan_count = 0;
+      if (metadata_store.player_thread_active == 0)
+        idle_scan_count++;
+      else
+        idle_scan_count = 0;
 
-    debug(3, "Scan Result: %d, Bad Scan Count: %d, Idle Scan Count: %d.", result, bad_result_count,
-          idle_scan_count);
+      debug(3, "Scan Result: %d, Bad Scan Count: %d, Idle Scan Count: %d.", result, bad_result_count,
+            idle_scan_count);
 
-    /* not used
-    // decide if idle for too long
-        if  (idle_scan_count == config.scan_max_inactive_count) {
-          debug(2, "DACP server status scanning stopped.");
-          dacp_server.scan_enable = 0;
-        }
-    */
+      /* not used
+      // decide if idle for too long
+          if  (idle_scan_count == config.scan_max_inactive_count) {
+            debug(2, "DACP server status scanning stopped.");
+            dacp_server.scan_enable = 0;
+          }
+      */
 
-    int update_needed = 0;
-    metadata_hub_modify_prolog();
-    if (dacp_server_status_now != -1) { // if dacp_server_status_now is actually known...
-      if (metadata_store.dacp_server_active != dacp_server_status_now) {
-        debug(2, "metadata_store.dacp_server_active set to %d.", dacp_server_status_now);
-        metadata_store.dacp_server_active = dacp_server_status_now;
-        update_needed = 1;
+      int update_needed = 0;
+      metadata_hub_modify_prolog();
+      if (dacp_server_status_now != -1) { // if dacp_server_status_now is actually known...
+        if (metadata_store.dacp_server_active != dacp_server_status_now) {
+          debug(2, "metadata_store.dacp_server_active set to %d.", dacp_server_status_now);
+          metadata_store.dacp_server_active = dacp_server_status_now;
+          update_needed = 1;
+        }
       }
-    }
-    if (advanced_dacp_server_status_now !=
-        -1) { // if advanced_dacp_server_status_now is actually known...
-      if (metadata_store.advanced_dacp_server_active != advanced_dacp_server_status_now) {
-        debug(2, "metadata_store.advanced_dacp_server_active set to %d.", dacp_server_status_now);
-        metadata_store.advanced_dacp_server_active = advanced_dacp_server_status_now;
-        update_needed = 1;
+      if (advanced_dacp_server_status_now !=
+          -1) { // if advanced_dacp_server_status_now is actually known...
+        if (metadata_store.advanced_dacp_server_active != advanced_dacp_server_status_now) {
+          debug(2, "metadata_store.advanced_dacp_server_active set to %d.", dacp_server_status_now);
+          metadata_store.advanced_dacp_server_active = advanced_dacp_server_status_now;
+          update_needed = 1;
+        }
       }
-    }
 
-    metadata_hub_modify_epilog(update_needed);
+      metadata_hub_modify_epilog(update_needed);
 
-    // pthread_mutex_unlock(&dacp_server_information_lock);
-    // debug(1, "DACP Server ID \"%u\" at \"%s:%u\", scan %d.", dacp_server.active_remote_id,
-    //      dacp_server.ip_string, dacp_server.port, scan_index);
+      // pthread_mutex_unlock(&dacp_server_information_lock);
+      // debug(1, "DACP Server ID \"%u\" at \"%s:%u\", scan %d.", dacp_server.active_remote_id,
+      //      dacp_server.ip_string, dacp_server.port, scan_index);
 
-    if (result == 200) {
-      metadata_hub_modify_prolog();
-      int diff = metadata_store.speaker_volume != the_volume;
-      if (diff)
-        metadata_store.speaker_volume = the_volume;
-      metadata_hub_modify_epilog(diff);
-
-      ssize_t le;
-      char *response = NULL;
-      int32_t item_size;
-      char command[1024] = "";
-      if (always_use_revision_number_1 != 0) // for forked-daapd
-        revision_number = 1;
-      snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d",
-               revision_number);
-      // debug(1,"dacp_monitor_thread_code: command: \"%s\"",command);
-      result = dacp_send_command(command, &response, &le);
-      // debug(1,"Response to \"%s\" is %d.",command,result);
-      // remember: unless the revision_number you pass in is 1,
-      // response will be 200 only if there's something new to report.
       if (result == 200) {
-        // if (0) {
-        char *sp = response;
-        if (le >= 8) {
-          // here start looking for the contents of the status update
-          if (dacp_tlv_crawl(&sp, &item_size) == 'cmst') { // status
-            // here, we know that we are receiving playerstatusupdates, so set a flag
-            metadata_hub_modify_prolog();
-            // debug(1, "playstatusupdate release track metadata");
-            // metadata_hub_reset_track_metadata();
-            // metadata_store.playerstatusupdates_are_received = 1;
-            sp -= item_size; // drop down into the array -- don't skip over it
-            le -= 8;
-            // char typestring[5];
-            // we need to acquire the metadata data structure and possibly update it
-            while (le >= 8) {
-              uint32_t type = dacp_tlv_crawl(&sp, &item_size);
-              le -= item_size + 8;
-              char *t;
-              // char u;
-              // char *st;
-              int32_t r;
-              uint32_t ui;
-              // uint64_t v;
-              // int i;
-
-              switch (type) {
-              case 'cmsr': // revision number
-                t = sp - item_size;
-                revision_number = ntohl(*(uint32_t *)(t));
-                // debug(1,"New revision number received: %d", revision_number);
-                break;
-              case 'caps': // play status
-                t = sp - item_size;
-                r = *(unsigned char *)(t);
-                switch (r) {
-                case 2:
-                  if (metadata_store.play_status != PS_STOPPED) {
-                    metadata_store.play_status = PS_STOPPED;
-                    debug(2, "Play status is \"stopped\".");
-                  }
+        metadata_hub_modify_prolog();
+        int diff = metadata_store.speaker_volume != the_volume;
+        if (diff)
+          metadata_store.speaker_volume = the_volume;
+        metadata_hub_modify_epilog(diff);
+
+        ssize_t le;
+        char *response = NULL;
+        int32_t item_size;
+        char command[1024] = "";
+        if (always_use_revision_number_1 != 0) // for forked-daapd
+          revision_number = 1;
+        snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d",
+                 revision_number);
+        // debug(1,"dacp_monitor_thread_code: command: \"%s\"",command);
+        result = dacp_send_command(command, &response, &le);
+        // debug(1,"Response to \"%s\" is %d.",command,result);
+        // remember: unless the revision_number you pass in is 1,
+        // response will be 200 only if there's something new to report.
+        if (result == 200) {
+          // if (0) {
+          char *sp = response;
+          if (le >= 8) {
+            // here start looking for the contents of the status update
+            if (dacp_tlv_crawl(&sp, &item_size) == 'cmst') { // status
+              // here, we know that we are receiving playerstatusupdates, so set a flag
+              metadata_hub_modify_prolog();
+              // debug(1, "playstatusupdate release track metadata");
+              // metadata_hub_reset_track_metadata();
+              // metadata_store.playerstatusupdates_are_received = 1;
+              sp -= item_size; // drop down into the array -- don't skip over it
+              le -= 8;
+              // char typestring[5];
+              // we need to acquire the metadata data structure and possibly update it
+              while (le >= 8) {
+                uint32_t type = dacp_tlv_crawl(&sp, &item_size);
+                le -= item_size + 8;
+                char *t;
+                // char u;
+                // char *st;
+                int32_t r;
+                uint32_t ui;
+                // uint64_t v;
+                // int i;
+
+                switch (type) {
+                case 'cmsr': // revision number
+                  t = sp - item_size;
+                  revision_number = ntohl(*(uint32_t *)(t));
+                  // debug(1,"New revision number received: %d", revision_number);
                   break;
-                case 3:
-                  if (metadata_store.play_status != PS_PAUSED) {
-                    metadata_store.play_status = PS_PAUSED;
-                    debug(2, "Play status is \"paused\".");
+                case 'caps': // play status
+                  t = sp - item_size;
+                  r = *(unsigned char *)(t);
+                  switch (r) {
+                  case 2:
+                    if (metadata_store.play_status != PS_STOPPED) {
+                      metadata_store.play_status = PS_STOPPED;
+                      debug(2, "Play status is \"stopped\".");
+                    }
+                    break;
+                  case 3:
+                    if (metadata_store.play_status != PS_PAUSED) {
+                      metadata_store.play_status = PS_PAUSED;
+                      debug(2, "Play status is \"paused\".");
+                    }
+                    break;
+                  case 4:
+                    if (metadata_store.play_status != PS_PLAYING) {
+                      metadata_store.play_status = PS_PLAYING;
+                      debug(2, "Play status changed to \"playing\".");
+                    }
+                    break;
+                  default:
+                    debug(1, "Unrecognised play status %d received.", r);
+                    break;
                   }
                   break;
-                case 4:
-                  if (metadata_store.play_status != PS_PLAYING) {
-                    metadata_store.play_status = PS_PLAYING;
-                    debug(2, "Play status changed to \"playing\".");
+                case 'cash': // shuffle status
+                  t = sp - item_size;
+                  r = *(unsigned char *)(t);
+                  switch (r) {
+                  case 0:
+                    if (metadata_store.shuffle_status != SS_OFF) {
+                      metadata_store.shuffle_status = SS_OFF;
+                      debug(2, "Shuffle status is \"off\".");
+                    }
+                    break;
+                  case 1:
+                    if (metadata_store.shuffle_status != SS_ON) {
+                      metadata_store.shuffle_status = SS_ON;
+                      debug(2, "Shuffle status is \"on\".");
+                    }
+                    break;
+                  default:
+                    debug(1, "Unrecognised shuffle status %d received.", r);
+                    break;
                   }
                   break;
-                default:
-                  debug(1, "Unrecognised play status %d received.", r);
+                case 'carp': // repeat status
+                  t = sp - item_size;
+                  r = *(unsigned char *)(t);
+                  switch (r) {
+                  case 0:
+                    if (metadata_store.repeat_status != RS_OFF) {
+                      metadata_store.repeat_status = RS_OFF;
+                      debug(2, "Repeat status is \"none\".");
+                    }
+                    break;
+                  case 1:
+                    if (metadata_store.repeat_status != RS_ONE) {
+                      metadata_store.repeat_status = RS_ONE;
+                      debug(2, "Repeat status is \"one\".");
+                    }
+                    break;
+                  case 2:
+                    if (metadata_store.repeat_status != RS_ALL) {
+                      metadata_store.repeat_status = RS_ALL;
+                      debug(2, "Repeat status is \"all\".");
+                    }
+                    break;
+                  default:
+                    debug(1, "Unrecognised repeat status %d received.", r);
+                    break;
+                  }
                   break;
-                }
-                break;
-              case 'cash': // shuffle status
-                t = sp - item_size;
-                r = *(unsigned char *)(t);
-                switch (r) {
-                case 0:
-                  if (metadata_store.shuffle_status != SS_OFF) {
-                    metadata_store.shuffle_status = SS_OFF;
-                    debug(2, "Shuffle status is \"off\".");
+                case 'cann': // track name
+                  debug(2, "DACP Track Name seen");
+                  if (string_update_with_size(&metadata_store.track_name,
+                                              &metadata_store.track_name_changed, sp - item_size,
+                                              item_size)) {
+                    debug(2, "DACP Track Name set to: \"%s\"", metadata_store.track_name);
                   }
                   break;
-                case 1:
-                  if (metadata_store.shuffle_status != SS_ON) {
-                    metadata_store.shuffle_status = SS_ON;
-                    debug(2, "Shuffle status is \"on\".");
+                case 'cana': // artist name
+                  debug(2, "DACP Artist Name seen");
+                  if (string_update_with_size(&metadata_store.artist_name,
+                                              &metadata_store.artist_name_changed, sp - item_size,
+                                              item_size)) {
+                    debug(2, "DACP Artist Name set to: \"%s\"", metadata_store.artist_name);
                   }
                   break;
-                default:
-                  debug(1, "Unrecognised shuffle status %d received.", r);
+                case 'canl': // album name
+                  debug(2, "DACP Album Name seen");
+                  if (string_update_with_size(&metadata_store.album_name,
+                                              &metadata_store.album_name_changed, sp - item_size,
+                                              item_size)) {
+                    debug(2, "DACP Album Name set to: \"%s\"", metadata_store.album_name);
+                  }
                   break;
-                }
-                break;
-              case 'carp': // repeat status
-                t = sp - item_size;
-                r = *(unsigned char *)(t);
-                switch (r) {
-                case 0:
-                  if (metadata_store.repeat_status != RS_OFF) {
-                    metadata_store.repeat_status = RS_OFF;
-                    debug(2, "Repeat status is \"none\".");
+                case 'cang': // genre
+                  debug(2, "DACP Genre seen");
+                  if (string_update_with_size(&metadata_store.genre, &metadata_store.genre_changed,
+                                              sp - item_size, item_size)) {
+                    debug(2, "DACP Genre set to: \"%s\"", metadata_store.genre);
                   }
                   break;
-                case 1:
-                  if (metadata_store.repeat_status != RS_ONE) {
-                    metadata_store.repeat_status = RS_ONE;
-                    debug(2, "Repeat status is \"one\".");
+                case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware
+                             // see reference above)
+                  debug(2, "DACP Composite ID seen");
+                  if (memcmp(metadata_store.item_composite_id, sp - item_size,
+                             sizeof(metadata_store.item_composite_id)) != 0) {
+                    memcpy(metadata_store.item_composite_id, sp - item_size,
+                           sizeof(metadata_store.item_composite_id));
+                    char st[33];
+                    char *pt = st;
+                    int it;
+                    for (it = 0; it < 16; it++) {
+                      snprintf(pt, 3, "%02X", metadata_store.item_composite_id[it]);
+                      pt += 2;
+                    }
+                    *pt = 0;
+                    debug(2, "Item composite ID changed to 0x%s.", st);
+                    metadata_store.item_composite_id_changed = 1;
                   }
                   break;
-                case 2:
-                  if (metadata_store.repeat_status != RS_ALL) {
-                    metadata_store.repeat_status = RS_ALL;
-                    debug(2, "Repeat status is \"all\".");
+                case 'astm':
+                  t = sp - item_size;
+                  ui = ntohl(*(uint32_t *)(t));
+                  debug(2, "DACP Song Time seen: \"%u\" of length %u.", ui, item_size);
+                  if (ui != metadata_store.songtime_in_milliseconds) {
+                    metadata_store.songtime_in_milliseconds = ui;
+                    metadata_store.songtime_in_milliseconds_changed = 1;
+                    debug(2, "DACP Song Time set to: \"%u\"",
+                          metadata_store.songtime_in_milliseconds);
                   }
                   break;
+
+                /*
+                            case 'mstt':
+                            case 'cant':
+                            case 'cast':
+                            case 'cmmk':
+                            case 'caas':
+                            case 'caar':
+                              t = sp - item_size;
+                              r = ntohl(*(uint32_t *)(t));
+                              printf("    %d", r);
+                              printf("    (0x");
+                              t = sp - item_size;
+                              for (i = 0; i < item_size; i++) {
+                                printf("%02x", *t & 0xff);
+                                t++;
+                              }
+                              printf(")");
+                              break;
+                            case 'asai':
+                              t = sp - item_size;
+                              s = ntohl(*(uint32_t *)(t));
+                              s = s << 32;
+                              t += 4;
+                              v = (ntohl(*(uint32_t *)(t))) & 0xffffffff;
+                              s += v;
+                              printf("    %lu", s);
+                              printf("    (0x");
+                              t = sp - item_size;
+                              for (i = 0; i < item_size; i++) {
+                                printf("%02x", *t & 0xff);
+                                t++;
+                              }
+                              printf(")");
+                              break;
+                 */
                 default:
-                  debug(1, "Unrecognised repeat status %d received.", r);
+                  /*
+                    printf("    0x");
+                    t = sp - item_size;
+                    for (i = 0; i < item_size; i++) {
+                      printf("%02x", *t & 0xff);
+                      t++;
+                    }
+                   */
                   break;
                 }
-                break;
-              case 'cann': // track name
-                debug(2, "DACP Track Name seen");
-                if (string_update_with_size(&metadata_store.track_name,
-                                            &metadata_store.track_name_changed, sp - item_size,
-                                            item_size)) {
-                  debug(2, "DACP Track Name set to: \"%s\"", metadata_store.track_name);
-                }
-                break;
-              case 'cana': // artist name
-                debug(2, "DACP Artist Name seen");
-                if (string_update_with_size(&metadata_store.artist_name,
-                                            &metadata_store.artist_name_changed, sp - item_size,
-                                            item_size)) {
-                  debug(2, "DACP Artist Name set to: \"%s\"", metadata_store.artist_name);
-                }
-                break;
-              case 'canl': // album name
-                debug(2, "DACP Album Name seen");
-                if (string_update_with_size(&metadata_store.album_name,
-                                            &metadata_store.album_name_changed, sp - item_size,
-                                            item_size)) {
-                  debug(2, "DACP Album Name set to: \"%s\"", metadata_store.album_name);
-                }
-                break;
-              case 'cang': // genre
-                debug(2, "DACP Genre seen");
-                if (string_update_with_size(&metadata_store.genre, &metadata_store.genre_changed,
-                                            sp - item_size, item_size)) {
-                  debug(2, "DACP Genre set to: \"%s\"", metadata_store.genre);
-                }
-                break;
-              case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware
-                           // see reference above)
-                debug(2, "DACP Composite ID seen");
-                if (memcmp(metadata_store.item_composite_id, sp - item_size,
-                           sizeof(metadata_store.item_composite_id)) != 0) {
-                  memcpy(metadata_store.item_composite_id, sp - item_size,
-                         sizeof(metadata_store.item_composite_id));
-                  char st[33];
-                  char *pt = st;
-                  int it;
-                  for (it = 0; it < 16; it++) {
-                    snprintf(pt, 3, "%02X", metadata_store.item_composite_id[it]);
-                    pt += 2;
-                  }
-                  *pt = 0;
-                  debug(2, "Item composite ID changed to 0x%s.", st);
-                  metadata_store.item_composite_id_changed = 1;
-                }
-                break;
-              case 'astm':
-                t = sp - item_size;
-                ui = ntohl(*(uint32_t *)(t));
-                debug(2, "DACP Song Time seen: \"%u\" of length %u.", ui, item_size);
-                if (ui != metadata_store.songtime_in_milliseconds) {
-                  metadata_store.songtime_in_milliseconds = ui;
-                  metadata_store.songtime_in_milliseconds_changed = 1;
-                  debug(2, "DACP Song Time set to: \"%u\"",
-                        metadata_store.songtime_in_milliseconds);
-                }
-                break;
-
-              /*
-                          case 'mstt':
-                          case 'cant':
-                          case 'cast':
-                          case 'cmmk':
-                          case 'caas':
-                          case 'caar':
-                            t = sp - item_size;
-                            r = ntohl(*(uint32_t *)(t));
-                            printf("    %d", r);
-                            printf("    (0x");
-                            t = sp - item_size;
-                            for (i = 0; i < item_size; i++) {
-                              printf("%02x", *t & 0xff);
-                              t++;
-                            }
-                            printf(")");
-                            break;
-                          case 'asai':
-                            t = sp - item_size;
-                            s = ntohl(*(uint32_t *)(t));
-                            s = s << 32;
-                            t += 4;
-                            v = (ntohl(*(uint32_t *)(t))) & 0xffffffff;
-                            s += v;
-                            printf("    %lu", s);
-                            printf("    (0x");
-                            t = sp - item_size;
-                            for (i = 0; i < item_size; i++) {
-                              printf("%02x", *t & 0xff);
-                              t++;
-                            }
-                            printf(")");
-                            break;
-               */
-              default:
-                /*
-                  printf("    0x");
-                  t = sp - item_size;
-                  for (i = 0; i < item_size; i++) {
-                    printf("%02x", *t & 0xff);
-                    t++;
-                  }
-                 */
-                break;
+                // printf("\n");
               }
-              // printf("\n");
-            }
 
-            // finished possibly writing to the metadata hub
-            metadata_hub_modify_epilog(
-                1); // should really see if this can be made responsive to changes
+              // finished possibly writing to the metadata hub
+              metadata_hub_modify_epilog(
+                  1); // should really see if this can be made responsive to changes
+            } else {
+              debug(1, "Status Update not found.\n");
+            }
           } else {
-            debug(1, "Status Update not found.\n");
+            debug(1, "Can't find any content in playerstatusupdate request");
           }
-        } else {
-          debug(1, "Can't find any content in playerstatusupdate request");
-        }
-      } /* else {
-        if (result != 403)
-          debug(1, "Unexpected response %d to playerstatusupdate request", result);
-      } */
+        } /* else {
+          if (result != 403)
+            debug(1, "Unexpected response %d to playerstatusupdate request", result);
+        } */
+        if (response) {
+          free(response);
+          response = NULL;
+        };
+      };
+      /*
+      strcpy(command,"nowplayingartwork?mw=320&mh=320");
+      debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
       if (response) {
         free(response);
         response = NULL;
-      };
-    };
-    /*
-    strcpy(command,"nowplayingartwork?mw=320&mh=320");
-    debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
-    if (response) {
-      free(response);
-      response = NULL;
-    }
-    strcpy(command,"getproperty?properties=dmcp.volume");
-    debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
-    if (response) {
-      free(response);
-      response = NULL;
-    }
-    strcpy(command,"setproperty?dmcp.volume=100.000000");
-    debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
-    if (response) {
-      free(response);
-      response = NULL;
+      }
+      strcpy(command,"getproperty?properties=dmcp.volume");
+      debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
+      if (response) {
+        free(response);
+        response = NULL;
+      }
+      strcpy(command,"setproperty?dmcp.volume=100.000000");
+      debug(1,"Command: \"%s\", result is %d",command, dacp_send_command(command, &response, &le));
+      if (response) {
+        free(response);
+        response = NULL;
+      }
+      */
+      if (metadata_store.player_thread_active)
+        sleep(config.scan_interval_when_active);
+      else
+        sleep(config.scan_interval_when_inactive);
     }
-    */
-    if (metadata_store.player_thread_active)
-      sleep(config.scan_interval_when_active);
-    else
-      sleep(config.scan_interval_when_inactive);
   }
   debug(1, "DACP monitor thread exiting -- should never happen.");
   pthread_exit(NULL);
@@ -889,6 +920,22 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
 
 void dacp_monitor_start() {
   int rc;
+
+#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
+  pthread_condattr_t attr;
+  pthread_condattr_init(&attr);
+  pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it.
+  rc = pthread_cond_init(&dacp_server_information_cv, &attr);
+  if (rc)
+    debug(1, "Error initialising the DACP Server Information Condition Variable");
+  pthread_condattr_destroy(&attr);
+#endif
+#ifdef COMPILE_FOR_OSX
+  rc = pthread_cond_init(&dacp_server_information_cv, NULL);
+#endif
+
+
+
   pthread_mutexattr_t mta;
 
   rc = pthread_mutexattr_init(&mta);
@@ -947,6 +994,8 @@ void dacp_monitor_stop() {
     pthread_mutex_destroy(&dacp_server_information_lock);
     debug(3, "DACP Conversation Lock Mutex Destroyed");
     pthread_mutex_destroy(&dacp_conversation_lock);
+    pthread_cond_destroy(&dacp_server_information_cv);
+    debug(1, "DACP Server Information Condition Variable destroyed.");
   }
 }
 
diff --git a/rtsp.c b/rtsp.c
index dca0ecb57b8ee874278fdfdc950b77d6dbc84744..4013acb92e8d45cd897c01551cbb820f13bdd7fc 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -2335,6 +2335,7 @@ static void *rtsp_conversation_thread_func(void *pconn) {
   pthread_condattr_init(&attr);
   pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it.
   rc = pthread_cond_init(&conn->flowcontrol, &attr);
+  pthread_condattr_destroy(&attr);
 #endif
 #ifdef COMPILE_FOR_OSX
   rc = pthread_cond_init(&conn->flowcontrol, NULL);
index 881ecd97b0ca02b02cccef660a5326896f16c333..8f80ebdb6c4babb0f62e5a7dedcb46ea794dfefe 100644 (file)
@@ -405,6 +405,7 @@ int parse_options(int argc, char **argv) {
   config.resend_control_first_check_time = 0.10; // wait this many seconds before requesting the resending of a missing packet
   config.resend_control_check_interval_time = 0.25; // wait this many seconds before again requesting the resending of a missing packet
   config.resend_control_last_check_time = 0.10; // give up if the packet is still missing this close to when it's needed
+  config.missing_port_dacp_scan_interval_seconds = 2.0; // check at this interval if no DACP port number is known
 
 #ifdef CONFIG_METADATA_HUB
   config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart";