]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Tidy up dacp scanner -- stop scanning when audio source goes offline.
authorMike Brady <mikebrady@eircom.net>
Sun, 18 Feb 2018 16:29:09 +0000 (16:29 +0000)
committerMike Brady <mikebrady@eircom.net>
Sun, 18 Feb 2018 16:29:09 +0000 (16:29 +0000)
dacp.c
dacp.h
mdns_avahi.c
metadata_hub.c
metadata_hub.h
mpris-service.c
player.c

diff --git a/dacp.c b/dacp.c
index a87d0137365decf846522ca05bf2e88533ff71eb..79c6bbd036e60a79c555f872d72d9cd6833f437c 100644 (file)
--- a/dacp.c
+++ b/dacp.c
@@ -45,7 +45,8 @@
 #include "tinyhttp/http.h"
 
 typedef struct {
-  uint16_t port;
+  int scan_enable;                  // set to 1 if if sacanning should be considered
+  uint16_t port;                    // zero if no port discovered
   short connection_family;          // AF_INET6 or AF_INET
   uint32_t scope_id;                // if it's an ipv6 connection, this will be its scope id
   char ip_string[INET6_ADDRSTRLEN]; // the ip string pointing to the client
@@ -268,7 +269,10 @@ void set_dacp_server_information(rtsp_conn_info *conn) { // tell the DACP conver
   dacp_server.scope_id = conn->self_scope_id;
   strncpy(dacp_server.ip_string, conn->client_ip_string, INET6_ADDRSTRLEN);
   dacp_server.active_remote_id = conn->dacp_active_remote;
-
+  if (dacp_server.port)
+    dacp_server.scan_enable=1;
+  else
+    dacp_server.scan_enable=0;
   pthread_cond_signal(&dacp_server_information_cv);
   pthread_mutex_unlock(&dacp_server_information_lock);
 }
@@ -280,285 +284,289 @@ void *dacp_monitor_thread_code(void *na) {
   // wait until we get a valid port number to begin monitoring it
   int32_t revision_number = 1;
   while (1) {
+    int result;
     pthread_mutex_lock(&dacp_server_information_lock);
-    while (dacp_server.port == 0) {
+    while (dacp_server.scan_enable == 0) {
       debug(1, "Wait for a valid DACP port");
       pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
     }
+    scan_index++;
+    result = dacp_get_volume(NULL); // just want the http code
+    if ((result==496) || (result==403)|| (result==501)) {
+      debug(1,"Stopping scan because the response to \"dacp_get_volume(NULL)\" is %d.",result);
+      dacp_server.scan_enable = 0;
+    }
     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);
-    scan_index++;
-    ssize_t le;
-    char *response = NULL;
-    int32_t item_size;
-    char command[1024] = "";
-    snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d", revision_number);
-    // debug(1,"Command: \"%s\"",command);
-    int result = dacp_send_command(command, &response, &le);
-    if (result == 200) {
-      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();
-          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);
-
-            //*(uint32_t *)typestring = htonl(type);
-            // typestring[4] = 0;
-            // printf("\"%s\" %4d", typestring, item_size);
-
-            le -= item_size + 8;
-            char *t;
-            char u;
-            char *st;
-            int32_t r;
-            uint64_t s, v;
-            int i;
+    if (result==200) {
+      ssize_t le;
+      char *response = NULL;
+      int32_t item_size;
+      char command[1024] = "";
+      snprintf(command, sizeof(command) - 1, "playstatusupdate?revision-number=%d", revision_number);
+      // debug(1,"Command: \"%s\"",command);
+      result = dacp_send_command(command, &response, &le);
+      // debug(1,"Response to \"%s\" is %d.",command,result);
+      if (result == 200) {
+        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();
+            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;
+              uint64_t s, v;
+              int i;
 
-            switch (type) {
-            case 'cmsr': // revision number
-              t = sp - item_size;
-              revision_number = ntohl(*(uint32_t *)(t));
-              // debug(1,"    Serial Number: %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;
-                  metadata_store.play_status_changed = 1;
-                  debug(1, "Play status set to \"stopped\".");
-                  metadata_store.changed = 1;
-                }
+              switch (type) {
+              case 'cmsr': // revision number
+                t = sp - item_size;
+                revision_number = ntohl(*(uint32_t *)(t));
+                // debug(1,"    Serial Number: %d", revision_number);
                 break;
-              case 3:
-                if (metadata_store.play_status != PS_PAUSED) {
-                  metadata_store.play_status = PS_PAUSED;
-                  metadata_store.play_status_changed = 1;
-                  debug(1, "Play status set to \"paused\".");
-                  metadata_store.changed = 1;
+              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;
+                    metadata_store.play_status_changed = 1;
+                    debug(1, "Play status changed to \"stopped\".");
+                    metadata_store.changed = 1;
+                  }
+                  break;
+                case 3:
+                  if (metadata_store.play_status != PS_PAUSED) {
+                    metadata_store.play_status = PS_PAUSED;
+                    metadata_store.play_status_changed = 1;
+                    debug(1, "Play status changed to \"paused\".");
+                    metadata_store.changed = 1;
+                  }
+                  break;
+                case 4:
+                  if (metadata_store.play_status != PS_PLAYING) {
+                    metadata_store.play_status = PS_PLAYING;
+                    metadata_store.play_status_changed = 1;
+                    debug(1, "Play status changed to \"playing\".");
+                    metadata_store.changed = 1;
+                  }
+                  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;
-                  metadata_store.play_status_changed = 1;
-                  debug(1, "Play status set to \"playing\".");
-                  metadata_store.changed = 1;
+              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;
+                    metadata_store.shuffle_status_changed = 1;
+                    debug(1, "Shuffle status changed to \"off\".");
+                    metadata_store.changed = 1;
+                  }
+                  break;
+                case 1:
+                  if (metadata_store.shuffle_status != SS_ON) {
+                    metadata_store.shuffle_status = SS_ON;
+                    metadata_store.shuffle_status_changed = 1;
+                    debug(1, "Shuffle status changed to \"on\".");
+                    metadata_store.changed = 1;
+                  }
+                  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_NONE) {
+                    metadata_store.repeat_status = RS_NONE;
+                    metadata_store.repeat_status_changed = 1;
+                    debug(1, "Repeat status changed to \"none\".");
+                    metadata_store.changed = 1;
+                  }
+                  break;
+                case 1:
+                  if (metadata_store.repeat_status != RS_SINGLE) {
+                    metadata_store.repeat_status = RS_SINGLE;
+                    metadata_store.repeat_status_changed = 1;
+                    debug(1, "Repeat status changed to \"single\".");
+                    metadata_store.changed = 1;
+                  }
+                  break;
+                case 2:
+                  if (metadata_store.repeat_status != RS_ALL) {
+                    metadata_store.repeat_status = RS_ALL;
+                    metadata_store.repeat_status_changed = 1;
+                    debug(1, "Repeat status changed to \"all\".");
+                    metadata_store.changed = 1;
+                  }
+                  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;
-                  metadata_store.shuffle_status_changed = 1;
-                  debug(1, "Shuffle status set to \"off\".");
+              case 'cann': // track name
+                t = sp - item_size;
+                if ((metadata_store.track_name == NULL) ||
+                    (strncmp(metadata_store.track_name, t, item_size) != 0)) {
+                  if (metadata_store.track_name)
+                    free(metadata_store.track_name);
+                  metadata_store.track_name = strndup(t, item_size);
+                  debug(1, "Track name changed to: \"%s\"", metadata_store.track_name);
+                  metadata_store.track_name_changed = 1;
                   metadata_store.changed = 1;
                 }
                 break;
-              case 1:
-                if (metadata_store.shuffle_status != SS_ON) {
-                  metadata_store.shuffle_status = SS_ON;
-                  metadata_store.shuffle_status_changed = 1;
-                  debug(1, "Shuffle status set to \"on\".");
+              case 'cana': // artist name
+                t = sp - item_size;
+                if ((metadata_store.artist_name == NULL) ||
+                    (strncmp(metadata_store.artist_name, t, item_size) != 0)) {
+                  if (metadata_store.artist_name)
+                    free(metadata_store.artist_name);
+                  metadata_store.artist_name = strndup(t, item_size);
+                  debug(1, "Artist name changed to: \"%s\"", metadata_store.artist_name);
+                  metadata_store.artist_name_changed = 1;
                   metadata_store.changed = 1;
                 }
                 break;
-              default:
-                debug(1, "Unrecognised shuffle status %d received.", r);
-                break;
-              }
-              break;
-            case 'carp': // repeat status
-              t = sp - item_size;
-              r = *(unsigned char *)(t);
-              switch (r) {
-              case 0:
-                if (metadata_store.repeat_status != RS_NONE) {
-                  metadata_store.repeat_status = RS_NONE;
-                  metadata_store.repeat_status_changed = 1;
-                  debug(1, "Repeat status set to \"none\".");
+              case 'canl': // album name
+                t = sp - item_size;
+                if ((metadata_store.album_name == NULL) ||
+                    (strncmp(metadata_store.album_name, t, item_size) != 0)) {
+                  if (metadata_store.album_name)
+                    free(metadata_store.album_name);
+                  metadata_store.album_name = strndup(t, item_size);
+                  debug(1, "Album name changed to: \"%s\"", metadata_store.album_name);
+                  metadata_store.album_name_changed = 1;
                   metadata_store.changed = 1;
                 }
                 break;
-              case 1:
-                if (metadata_store.repeat_status != RS_SINGLE) {
-                  metadata_store.repeat_status = RS_SINGLE;
-                  metadata_store.repeat_status_changed = 1;
-                  debug(1, "Repeat status set to \"single\".");
+              case 'cang': // genre
+                t = sp - item_size;
+                if ((metadata_store.genre == NULL) ||
+                    (strncmp(metadata_store.genre, t, item_size) != 0)) {
+                  if (metadata_store.genre)
+                    free(metadata_store.genre);
+                  metadata_store.genre = strndup(t, item_size);
+                  debug(1, "Genre changed to: \"%s\"", metadata_store.genre);
+                  metadata_store.genre_changed = 1;
                   metadata_store.changed = 1;
                 }
                 break;
-              case 2:
-                if (metadata_store.repeat_status != RS_ALL) {
-                  metadata_store.repeat_status = RS_ALL;
-                  metadata_store.repeat_status_changed = 1;
-                  debug(1, "Repeat status set to \"all\".");
+              case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
+                           // see reference above)
+                t = sp - item_size;
+                if (memcmp(metadata_store.item_composite_id, t,
+                           sizeof(metadata_store.item_composite_id)) != 0) {
+                  memcpy(metadata_store.item_composite_id, t,
+                         sizeof(metadata_store.item_composite_id));
+
+                  char st[33];
+                  char *pt = st;
+                  int it;
+                  for (it = 0; it < 16; it++) {
+                    sprintf(pt, "%02X", metadata_store.item_composite_id[it]);
+                    pt += 2;
+                  }
+                  *pt = 0;
+                  // debug(1, "Item composite ID set to 0x%s.", st);
+                  metadata_store.item_id_changed = 1;
                   metadata_store.changed = 1;
                 }
                 break;
-              default:
-                debug(1, "Unrecognised repeat status %d received.", r);
+              case 'astm':
+                t = sp - item_size;
+                r = ntohl(*(uint32_t *)(t));
+                metadata_store.songtime_in_milliseconds = ntohl(*(uint32_t *)(t));
                 break;
-              }
-              break;
-            case 'cann': // track name
-              t = sp - item_size;
-              if ((metadata_store.track_name == NULL) ||
-                  (strncmp(metadata_store.track_name, t, item_size) != 0)) {
-                if (metadata_store.track_name)
-                  free(metadata_store.track_name);
-                metadata_store.track_name = strndup(t, item_size);
-                debug(1, "Track name set to: \"%s\"", metadata_store.track_name);
-                metadata_store.track_name_changed = 1;
-                metadata_store.changed = 1;
-              }
-              break;
-            case 'cana': // artist name
-              t = sp - item_size;
-              if ((metadata_store.artist_name == NULL) ||
-                  (strncmp(metadata_store.artist_name, t, item_size) != 0)) {
-                if (metadata_store.artist_name)
-                  free(metadata_store.artist_name);
-                metadata_store.artist_name = strndup(t, item_size);
-                debug(1, "Artist name set to: \"%s\"", metadata_store.artist_name);
-                metadata_store.artist_name_changed = 1;
-                metadata_store.changed = 1;
-              }
-              break;
-            case 'canl': // album name
-              t = sp - item_size;
-              if ((metadata_store.album_name == NULL) ||
-                  (strncmp(metadata_store.album_name, t, item_size) != 0)) {
-                if (metadata_store.album_name)
-                  free(metadata_store.album_name);
-                metadata_store.album_name = strndup(t, item_size);
-                debug(1, "Album name set to: \"%s\"", metadata_store.album_name);
-                metadata_store.album_name_changed = 1;
-                metadata_store.changed = 1;
-              }
-              break;
-            case 'cang': // genre
-              t = sp - item_size;
-              if ((metadata_store.genre == NULL) ||
-                  (strncmp(metadata_store.genre, t, item_size) != 0)) {
-                if (metadata_store.genre)
-                  free(metadata_store.genre);
-                metadata_store.genre = strndup(t, item_size);
-                debug(1, "Genre set to: \"%s\"", metadata_store.genre);
-                metadata_store.genre_changed = 1;
-                metadata_store.changed = 1;
-              }
-              break;
-            case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
-                         // see reference above)
-              t = sp - item_size;
-              if (memcmp(metadata_store.item_composite_id, t,
-                         sizeof(metadata_store.item_composite_id)) != 0) {
-                memcpy(metadata_store.item_composite_id, t,
-                       sizeof(metadata_store.item_composite_id));
-
-                char st[33];
-                char *pt = st;
-                int it;
-                for (it = 0; it < 16; it++) {
-                  sprintf(pt, "%02X", metadata_store.item_composite_id[it]);
-                  pt += 2;
-                }
-                *pt = 0;
-                debug(1, "Item composite ID set to 0x%s.", st);
-                metadata_store.item_id_changed = 1;
-                metadata_store.changed = 1;
-              }
-              break;
-            case 'astm':
-              t = sp - item_size;
-              r = ntohl(*(uint32_t *)(t));
-              metadata_store.songtime_in_milliseconds = ntohl(*(uint32_t *)(t));
-              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++;
-                }
+                          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;
                */
-              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();
+            // finished possibly writing to the metadata hub
+            metadata_hub_modify_epilog(1);
+          } else {
+            debug(1,"Status Update not found.\n");
+          }
         } else {
-          printf("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);
-    }
-    if (response) {
-      free(response);
-      response = NULL;
+      } /* 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");
@@ -603,7 +611,7 @@ uint32_t dacp_tlv_crawl(char **p, int32_t *length) {
   return type;
 }
 
-int32_t dacp_get_client_volume(void) {
+int dacp_get_client_volume(int32_t *result) {
   char *server_reply = NULL;
   int32_t overall_volume = -1;
   ssize_t reply_size;
@@ -632,16 +640,18 @@ int32_t dacp_get_client_volume(void) {
     }
     // debug(1, "Overall Volume is %d.", overall_volume);
     free(server_reply);
-  } else {
+  } /* else {
     debug(1, "Unexpected response %d to dacp volume control request", response);
-  }
-  return overall_volume;
+  } */
+  if (result)
+    *result=overall_volume;
+  return response;
 }
 
 int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
   char message[1000];
   memset(message, 0, sizeof(message));
-  sprintf(message, "setproperty?include-speaker-id=%lld&dmcp.volume=%d", machine_number, vo);
+  sprintf(message, "setproperty?include-speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
   // debug(1,"sending \"%s\"",message);
   return send_simple_dacp_command(message);
   // should return 204
@@ -650,16 +660,17 @@ int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) {
 int dacp_set_speaker_volume(int64_t machine_number, int32_t vo) {
   char message[1000];
   memset(message, 0, sizeof(message));
-  sprintf(message, "setproperty?speaker-id=%lld&dmcp.volume=%d", machine_number, vo);
+  sprintf(message, "setproperty?speaker-id=%ld&dmcp.volume=%d", machine_number, vo);
   // debug(1,"sending \"%s\"",message);
   return send_simple_dacp_command(message);
   // should return 204
 }
 
-int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array) {
+int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array, int *actual_speaker_count) {
+                              char typestring[5];
   char *server_reply = NULL;
   int speaker_index = -1; // will be incremented before use
-  int reply = -1;         // will bve fixed if there is no problem
+  int speaker_count = -1;         // will be fixed if there is no problem
   ssize_t le;
 
   int response = dacp_send_command("getspeakers", &server_reply, &le);
@@ -679,7 +690,7 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
             le -= 8;
             speaker_index++;
             if (speaker_index == max_size_of_array)
-              return -1; // too many speakers
+              return 413;// Payload Too Large -- too many speakers
             speaker_info[speaker_index].active = 0;
             speaker_info[speaker_index].speaker_number = 0;
             speaker_info[speaker_index].volume = 0;
@@ -696,19 +707,11 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
               speaker_info[speaker_index].name = strndup(t, item_size);
               // debug(1," \"%s\"",speaker_info[speaker_index].name);
               break;
-            /*
-                            case 'cads':
-                              t = sp-item_size;
-                              r = ntohl(*(uint32_t*)(t));
-                              //debug(1,"CADS: \"%d\".",r);
-                              break;
-            */
             case 'cmvo':
               t = sp - item_size;
               r = ntohl(*(uint32_t *)(t));
               speaker_info[speaker_index].volume = r;
-              // debug(1,"The individual volume of speaker \"%s\" is
-              // \"%d\".",speaker_info[speaker_index].name,r);
+              // debug(1,"The individual volume of speaker \"%s\" is \"%d\".",speaker_info[speaker_index].name,r);
               break;
             case 'msma':
               t = sp - item_size;
@@ -728,9 +731,16 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
                             case 'caip':
                             case 'cavd':
                             case 'caiv':
+                            case 'cads':
+                            
+                              *(uint32_t *)typestring = htonl(type);
+                              typestring[4] = 0;
+
+                            
+                            
                               t = sp-item_size;
                               u = *t;
-                              //debug(1,"Value: \"%d\".",u);
+                              debug(1,"Type: '%s' Value: \"%d\".",typestring,u);
                               break;
             */
             default:
@@ -739,7 +749,7 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
           }
         }
         // debug(1,"Total of %d speakers found. Here are the active ones:",speaker_index+1);
-        reply = speaker_index + 1; // number of speaker entries in the array
+        speaker_count = speaker_index + 1; // number of speaker entries in the array
       } else {
         debug(1, "Speaker array not found.");
       }
@@ -761,10 +771,12 @@ int dacp_get_speaker_list(dacp_spkr_stuff *speaker_info, int max_size_of_array)
   } else {
     debug(1, "Unexpected response %d to dacp speakers request", response);
   }
-  return reply;
+  if (actual_speaker_count)
+    *actual_speaker_count = speaker_count;
+  return response;
 }
 
-void dacp_get_volume(void) {
+int dacp_get_volume(int32_t *the_actual_volume) {
   // get the speaker volume information from the DACP source and store it in the metadata_hub
   // A volume command has been sent from the client
   // let's get the master volume from the DACP remote control
@@ -772,32 +784,51 @@ void dacp_get_volume(void) {
   // we need the overall volume and the speakers information to get this device's relative volume to
   // calculate the real volume
 
-  int32_t overall_volume = dacp_get_client_volume();
+  int32_t overall_volume = 0;
+  int32_t actual_volume = 0;
+  int http_response = dacp_get_client_volume(&overall_volume);
   // debug(1, "DACP Volume: %d.", overall_volume);
-  int speaker_count = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50);
-  // debug(1,"DACP Speaker Count: %d.",speaker_count);
-
-  // get our machine number
-  uint16_t *hn = (uint16_t *)config.hw_addr;
-  uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
-  uint64_t t1 = ntohs(*hn);
-  uint64_t t2 = ntohl(*ln);
-  int64_t machine_number = (t1 << 32) + t2; // this form is useful
-
-  // Let's find our own speaker in the array and pick up its relative volume
-  int i;
-  int32_t relative_volume = 0;
-  for (i = 0; i < speaker_count; i++) {
-    if (speaker_info[i].speaker_number == machine_number) {
-      // debug(1,"Our speaker number found: %ld.",machine_number);
-      relative_volume = speaker_info[i].volume;
+  if (http_response==200) {
+    int speaker_count = 0;
+    http_response = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50,&speaker_count);
+    // debug(1,"DACP Speaker Count: %d.",speaker_count);
+    if (http_response==200) {
+      // get our machine number
+      uint16_t *hn = (uint16_t *)config.hw_addr;
+      uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
+      uint64_t t1 = ntohs(*hn);
+      uint64_t t2 = ntohl(*ln);
+      int64_t machine_number = (t1 << 32) + t2; // this form is useful
+
+      // Let's find our own speaker in the array and pick up its relative volume
+      int i;
+      int32_t relative_volume = 0;
+      for (i = 0; i < speaker_count; i++) {
+        if (speaker_info[i].speaker_number == machine_number) {
+          // debug(1,"Our speaker number found: %ld.",machine_number);
+          relative_volume = speaker_info[i].volume;
+          /*
+          if (speaker_info[i].active)
+            debug(1,"Our speaker is active.");
+          else
+            debug(1,"Our speaker is inactive.");
+          */
+        }
+      }
+      actual_volume = (overall_volume * relative_volume + 50) / 100;
+      // debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
+      // %d.",overall_volume,relative_volume,actual_volume);
+      // debug(1,"Our actual speaker volume is %d.",actual_volume);
+      //metadata_hub_modify_prolog();
+      //metadata_store.speaker_volume = actual_volume;
+      //metadata_hub_modify_epilog(1);
+    } else {
+      debug(1,"Unexpected return code %d from dacp_get_speaker_list.",http_response);
     }
-  }
-  int32_t actual_volume = (overall_volume * relative_volume + 50) / 100;
-  // debug(1,"Overall volume: %d, relative volume: %d%, actual volume:
-  // %d.",overall_volume,relative_volume,actual_volume);
-  // debug(1,"Our actual speaker volume is %d.",actual_volume);
-  metadata_hub_modify_prolog();
-  metadata_store.speaker_volume = actual_volume;
-  metadata_hub_modify_epilog();
+  } /* else {
+    debug(1,"Unexpected return code %d from dacp_get_client_volume.",http_response);
+  } */
+  if (the_actual_volume)
+    *the_actual_volume = actual_volume;
+    return http_response;
 }
diff --git a/dacp.h b/dacp.h
index bcd5e7501002f8a593bb0d0b75b66ac756600534..7c23a8b7c5896dae603dafae98e1fb883b325bcd 100644 (file)
--- a/dacp.h
+++ b/dacp.h
@@ -6,9 +6,6 @@
 
 #include "player.h"
 
-static pthread_mutex_t dacp_server_information_lock;
-static pthread_cond_t dacp_server_information_cv;
-
 typedef struct dacp_speaker_stuff {
   int64_t speaker_number;
   int active;
@@ -24,11 +21,11 @@ uint32_t dacp_tlv_crawl(
 
 int dacp_set_speaker_volume(int64_t machine_number, int32_t vo);
 
-int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array, int max_size_of_array);
+int dacp_get_speaker_list(dacp_spkr_stuff *speaker_array, int max_size_of_array, int *actual_speaker_count);
 void set_dacp_server_information(rtsp_conn_info *conn); // tell the DACP conversation thread that
                                                         // the dacp server information has been set
                                                         // or changed
 int send_simple_dacp_command(const char *command);
 
-void dacp_get_volume(void); // get the speaker volume information from the DACP source and store it
+int dacp_get_volume(int32_t *the_actual_volume); // get the speaker volume information from the DACP source and store it
                             // in the metadata_hub
index 786163b03d2c7271c142e0fe35dc90c942d5d508..41f3354efdc7504500cef3f35a46749e5317686a 100644 (file)
@@ -122,7 +122,7 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah
     avahi_threaded_poll_quit(tpoll);
     break;
   case AVAHI_BROWSER_NEW:
-    debug(3, "(Browser) NEW: service '%s' of type '%s' in domain '%s'.", name, type, domain);
+    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
@@ -133,7 +133,7 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah
             avahi_strerror(avahi_client_errno(dbs->service_client)));
     break;
   case AVAHI_BROWSER_REMOVE:
-    debug(3, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'.", name, type, domain);
+    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_");
index 8f0f0480ce4b9e4eb0fdeecf50e3adeb4e9126e2..9ab9ab31656adfd89b837c7c854c7616f39053d1 100644 (file)
@@ -78,28 +78,29 @@ void add_metadata_watcher(metadata_watcher fn, void *userdata) {
 
 void metadata_hub_modify_prolog(void) {
   // always run this before changing an entry or a sequence of entries in the metadata_hub
-  debug(1, "locking metadata hub for writing");
+  // debug(1, "locking metadata hub for writing");
   pthread_rwlock_wrlock(&metadata_hub_re_lock);
 }
 
 void run_metadata_watchers(void) {
   int i;
-  debug(1, "locking metadata hub for reading");
+  // debug(1, "locking metadata hub for reading");
   pthread_rwlock_rdlock(&metadata_hub_re_lock);
   for (i = 0; i < number_of_watchers; i++) {
     if (metadata_store.watchers[i]) {
       metadata_store.watchers[i](&metadata_store, metadata_store.watchers_data[i]);
     }
   }
-  debug(1, "unlocking metadata hub for reading");
+  // debug(1, "unlocking metadata hub for reading");
   pthread_rwlock_unlock(&metadata_hub_re_lock);
 }
 
-void metadata_hub_modify_epilog(void) {
+void metadata_hub_modify_epilog(int modified) {
   // always run this after changing an entry or a sequence of entries in the metadata_hub
-  debug(1, "unlocking metadata hub for writing");
+  // debug(1, "unlocking metadata hub for writing");
   pthread_rwlock_unlock(&metadata_hub_re_lock);
-  run_metadata_watchers();
+  if (modified)
+    run_metadata_watchers();
 }
 
 char *metadata_write_image_file(const char *buf, int len) {
@@ -359,21 +360,21 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
       break;
 
     case 'mdst':
-      debug(1, "MH Metadata stream processing start.");
+      // debug(1, "MH Metadata stream processing start.");
       metadata_hub_modify_prolog();
       break;
     case 'mden':
-      metadata_hub_modify_epilog();
-      debug(1, "MH Metadata stream processing end.");
+      metadata_hub_modify_epilog(1);
+      // debug(1, "MH Metadata stream processing end.");
       break;
     case 'PICT':
       if (length > 16) {
         metadata_hub_modify_prolog();
-        debug(1, "MH Picture received, length %u bytes.", length);
+        // debug(1, "MH Picture received, length %u bytes.", length);
         if (metadata_store.cover_art_pathname)
           free(metadata_store.cover_art_pathname);
         metadata_store.cover_art_pathname = metadata_write_image_file(data, length);
-        metadata_hub_modify_epilog();
+        metadata_hub_modify_epilog(1);
       }
       break;
     case 'clip':
@@ -383,10 +384,10 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
         if (metadata_store.client_ip)
           free(metadata_store.client_ip);
         metadata_store.client_ip = strndup(data, length);
-        debug(1, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
+        // debug(1, "MH Client IP set to: \"%s\"", metadata_store.client_ip);
         metadata_store.client_ip_changed = 1;
         metadata_store.changed = 1;
-        metadata_hub_modify_epilog();
+        metadata_hub_modify_epilog(1);
       }
       break;
     case 'svip':
@@ -396,8 +397,8 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
         if (metadata_store.server_ip)
           free(metadata_store.server_ip);
         metadata_store.server_ip = strndup(data, length);
-        debug(1, "MH Server IP set to: \"%s\"", metadata_store.server_ip);
-        metadata_hub_modify_epilog();
+        // debug(1, "MH Server IP set to: \"%s\"", metadata_store.server_ip);
+        metadata_hub_modify_epilog(1);
       }
       break;
     default: {
@@ -412,7 +413,7 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
         payload = strndup(data, length);
       else
         payload = NULL;
-      debug(1, "MH \"%s\" \"%s\" (%d bytes): \"%s\".", typestring, codestring, length, payload);
+      // debug(1, "MH \"%s\" \"%s\" (%d bytes): \"%s\".", typestring, codestring, length, payload);
       if (payload)
         free(payload);
     }
index 2a7d844542af573673052b99f26b587d0f83ef1a..bb72a12353ebc97e5f3815894887d00492776515 100644 (file)
@@ -102,4 +102,4 @@ void metadata_hub_process_metadata(uint32_t type, uint32_t code, char *data, uin
 // these functions lock and unlock the read-write mutex on the metadata hub and run the watchers
 // afterwards
 void metadata_hub_modify_prolog(void);
-void metadata_hub_modify_epilog(void);
+void metadata_hub_modify_epilog(int modified); //set to true if modifications occured, 0 otherwise
index f36707cfc88cdd9e7da039c8b1b20297cd8dc813..4da7decb80c3a12a48723b0b083425a2f9abc149 100644 (file)
@@ -15,7 +15,7 @@
 #include "mpris-service.h"
 
 void mpris_metadata_watcher(struct metadata_bundle *argc, void *userdata) {
-  debug(1, "MPRIS metadata watcher called");
+  // debug(1, "MPRIS metadata watcher called");
   char response[100];
   switch (argc->repeat_status) {
   case RS_NONE:
@@ -33,74 +33,89 @@ void mpris_metadata_watcher(struct metadata_bundle *argc, void *userdata) {
   media_player2_player_set_loop_status(mprisPlayerPlayerSkeleton, response);
 
   GVariantBuilder *dict_builder, *aa;
-  GVariant *trackname, *albumname, *trackid, *tracklength, *artUrl;
+   /* Build the metadata array */
+  // debug(1,"Build metadata");
+  dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
 
+  // Make up the artwork URI if we have one
+  if (argc->cover_art_pathname) {
+    char artURIstring[1024];
+    sprintf(artURIstring, "file://%s", argc->cover_art_pathname);
+    // sprintf(artURIstring,"");
+    // debug(1,"artURI String: \"%s\".",artURIstring);
+    GVariant *artUrl = g_variant_new("s", artURIstring);
+    g_variant_builder_add(dict_builder, "{sv}", "mpris:artUrl", artUrl);
+  }
+  
+  // Add the TrackID if we have one
   // Build the Track ID from the 16-byte item_composite_id in hex prefixed by
   // /org/gnome/ShairportSync
-
   char st[33];
   char *pt = st;
   int it;
+  int non_zero = 0;
   for (it = 0; it < 16; it++) {
+    if (argc->item_composite_id[it])
+      non_zero = 1;
     sprintf(pt, "%02X", argc->item_composite_id[it]);
     pt += 2;
   }
   *pt = 0;
-  // debug(1, "Item composite ID set to 0x%s.", st);
-
-  char artURIstring[1024];
-  char trackidstring[1024];
-  sprintf(trackidstring, "/org/gnome/ShairportSync/%s", st);
-
-  trackid = g_variant_new("o", trackidstring);
-
-  // Make up the track name and album name
-  trackname = g_variant_new("s", argc->track_name);
-  albumname = g_variant_new("s", argc->album_name);
-
-  // Make up the track length in microseconds as an int64
-
-  uint64_t track_length_in_microseconds = argc->songtime_in_milliseconds;
-
-  track_length_in_microseconds *= 1000; // to microseconds in 64-bit precision
-
-  // Make up the track name and album name
-  tracklength = g_variant_new("x", track_length_in_microseconds);
-
-  /* Build the artists array */
-  // debug(1,"Build artists");
-  aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
-  g_variant_builder_add(aa, "s", argc->artist_name);
-  GVariant *artists = g_variant_builder_end(aa);
-  g_variant_builder_unref(aa);
-
-  /* Build the genre array */
-  // debug(1,"Build genre");
-  aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
-  g_variant_builder_add(aa, "s", argc->genre);
-  GVariant *genres = g_variant_builder_end(aa);
-  g_variant_builder_unref(aa);
-
-  /* Build the metadata array */
-  // debug(1,"Build metadata");
-  dict_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
-  // Make up the artwork URI if we have one
-  if (argc->cover_art_pathname) {
-    sprintf(artURIstring, "file://%s", argc->cover_art_pathname);
-    // sprintf(artURIstring,"");
-    artUrl = g_variant_new("s", artURIstring);
-    g_variant_builder_add(dict_builder, "{sv}", "mpris:artUrl", artUrl);
+  if (non_zero) {
+    // debug(1, "Item composite ID set to 0x%s.", st);
+    char trackidstring[1024];
+    sprintf(trackidstring, "/org/gnome/ShairportSync/%s", st);
+    GVariant* trackid = g_variant_new("o", trackidstring);
+    g_variant_builder_add(dict_builder, "{sv}", "mpris:trackid", trackid);
+  }
+  
+  // Add the track length if it's non-zero
+  if (argc->songtime_in_milliseconds) {
+    uint64_t track_length_in_microseconds = argc->songtime_in_milliseconds;
+    track_length_in_microseconds *= 1000; // to microseconds in 64-bit precision
+    // Make up the track name and album name
+    GVariant *tracklength = g_variant_new("x", track_length_in_microseconds);
+    g_variant_builder_add(dict_builder, "{sv}", "mpris:length", tracklength);
   }
-  g_variant_builder_add(dict_builder, "{sv}", "mpris:trackid", trackid);
-  g_variant_builder_add(dict_builder, "{sv}", "mpris:length", tracklength);
 
-  g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
-  g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
-  g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
-  g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
+  // Add the track name if there is one
+  if (argc->track_name) {
+    GVariant *trackname = g_variant_new("s", argc->track_name);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:title", trackname);
+  }
+  
+  // Add the album name if there is one
+   if (argc->album_name) {
+    GVariant *albumname = g_variant_new("s", argc->album_name);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:album", albumname);
+  }
+  
+  // Add the artists if there are any (actually there will be at most one, but put it in an array)
+  if (argc->artist_name) {
+    /* Build the artists array */
+    // debug(1,"Build artist array");
+    aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
+    g_variant_builder_add(aa, "s", argc->artist_name);
+    GVariant *artists = g_variant_builder_end(aa);
+    g_variant_builder_unref(aa);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:artist", artists);
+  }
+  
+  // Add the genres if there are any (actually there will be at most one, but put it in an array)
+  if (argc->genre) {
+    // debug(1,"Build genre");
+    aa = g_variant_builder_new(G_VARIANT_TYPE("as"));
+    g_variant_builder_add(aa, "s", argc->genre);
+    GVariant *genres = g_variant_builder_end(aa);
+    g_variant_builder_unref(aa);
+    g_variant_builder_add(dict_builder, "{sv}", "xesam:genre", genres);
+  }
   GVariant *dict = g_variant_builder_end(dict_builder);
   g_variant_builder_unref(dict_builder);
 
+  // debug(1,"Set metadata");
   media_player2_player_set_metadata(mprisPlayerPlayerSkeleton, dict);
 }
 
index 6a64ee971819436d8775426c47da2b2e929751d2..6b5f5d3b9f88aed74526599991778339009e6e3d 100644 (file)
--- a/player.c
+++ b/player.c
@@ -826,7 +826,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
 #ifdef HAVE_METADATA_HUB
             metadata_hub_modify_prolog();
             metadata_store.player_state = PS_PLAYING;
-            metadata_hub_modify_epilog();
+            metadata_hub_modify_epilog(1);
 #endif
             if (reference_timestamp) { // if we have a reference time
               // debug(1,"First frame seen with timestamp...");
@@ -2501,7 +2501,17 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c
 void player_volume(double airplay_volume, rtsp_conn_info *conn) {
   command_set_volume(airplay_volume);
 #ifdef HAVE_DACP_CLIENT
-  dacp_get_volume();
+  int32_t actual_volume;
+  if (dacp_get_volume(&actual_volume)==200) {
+    metadata_hub_modify_prolog();
+    if (metadata_store.speaker_volume == actual_volume)
+      metadata_hub_modify_epilog(0); // no change
+    else {
+      metadata_store.speaker_volume = actual_volume;
+      metadata_hub_modify_epilog(1); // change      
+    }
+  }
+
 #endif
 
   player_volume_without_notification(airplay_volume, conn);
@@ -2523,7 +2533,7 @@ void player_flush(int64_t timestamp, rtsp_conn_info *conn) {
 #ifdef HAVE_METADATA_HUB
   metadata_hub_modify_prolog();
   metadata_store.player_state = PS_PAUSED;
-  metadata_hub_modify_epilog();
+  metadata_hub_modify_epilog(1);
 #endif
 }
 
@@ -2553,7 +2563,7 @@ int player_play(rtsp_conn_info *conn) {
 #ifdef HAVE_METADATA_HUB
   metadata_hub_modify_prolog();
   metadata_store.player_state = PS_PLAYING;
-  metadata_hub_modify_epilog();
+  metadata_hub_modify_epilog(1);
 #endif
   return 0;
 }
@@ -2573,7 +2583,7 @@ void player_stop(rtsp_conn_info *conn) {
 #ifdef HAVE_METADATA_HUB
     metadata_hub_modify_prolog();
     metadata_store.player_state = PS_STOPPED;
-    metadata_hub_modify_epilog();
+    metadata_hub_modify_epilog(1);
 #endif
   } else {
     debug(3, "player thread of RTSP conversation %d is already deleted.", conn->connection_number);