]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Begin to add support for a central metadata bundle or respository. Lots more to do.
authorMike Brady <mikebrady@eircom.net>
Tue, 26 Dec 2017 20:28:14 +0000 (20:28 +0000)
committerMike Brady <mikebrady@eircom.net>
Tue, 26 Dec 2017 20:28:14 +0000 (20:28 +0000)
Makefile.am
dacp.c
metadata.c [new file with mode: 0644]
metadata.h [new file with mode: 0644]
rtp.c
shairport.c

index 9762325d53f3ed20788122c57784dda61001b141..0d89417acbaef5405cea68f807eac6aa9371e9f1 100644 (file)
@@ -88,7 +88,7 @@ dbus-interface.c:  org.gnome.ShairportSync.xml
 endif
 
 if USE_DBUS_CORE_AND_DACP
-shairport_sync_SOURCES += dacp.c tinyhttp/chunk.c tinyhttp/header.c tinyhttp/http.c 
+shairport_sync_SOURCES += dacp.c metadata.c tinyhttp/chunk.c tinyhttp/header.c tinyhttp/http.c 
 endif
 
 if USE_MPRIS
diff --git a/dacp.c b/dacp.c
index 3d97cbf5a3f567e496193f0718c6386b2907124b..5852eb2afbd9e83cf67482f41dcf637cf453eb95 100644 (file)
--- a/dacp.c
+++ b/dacp.c
@@ -10,7 +10,6 @@
  * copy, modify, merge, publish, distribute, sublicense, and/or
  * sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
- *
  * The above copyright notice and this permission notice shall be
  * included in all copies or substantial portions of the Software.
  *
@@ -24,6 +23,9 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
+// Information about the four-character codes is from many sources, with thanks, including
+// https://github.com/melloware/dacp-net/blob/master/Melloware.DACP/
+
 #include "dacp.h"
 #include "common.h"
 #include "config.h"
@@ -39,6 +41,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "metadata.h"
 #include "tinyhttp/http.h"
 
 typedef struct {
@@ -67,7 +70,8 @@ static void response_body(void *opaque, const char *data, int size) {
 
   ssize_t space_available = response->malloced_size - response->size;
   if (space_available < size) {
-    // debug(1,"Getting more space for the response -- need %d bytes but only %ld bytes left.\n", size,
+    // debug(1,"Getting more space for the response -- need %d bytes but only %ld bytes left.\n",
+    // size,
     //       size - space_available);
     ssize_t size_requested = size - space_available + response->malloced_size + 16384;
     void *t = realloc(response->body, size_requested);
@@ -75,7 +79,7 @@ static void response_body(void *opaque, const char *data, int size) {
     if (t)
       response->body = t;
     else {
-      debug(1,"Can't allocate any more space for parser.\n");
+      debug(1, "Can't allocate any more space for parser.\n");
       exit(-1);
     }
   }
@@ -103,7 +107,7 @@ static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER;
 int dacp_send_command(const char *command, char **body, size_t *bodysize) {
 
   // will malloc space for the body or set it to NULL -- the caller should free it.
-  
+
   // Using some custom HTTP-like return codes
   //  498 Bad Address information for the DACP server
   //  497 Can't establish a socket to the DACP server
@@ -111,7 +115,7 @@ int dacp_send_command(const char *command, char **body, size_t *bodysize) {
   //  495 Error receiving response
   //  494 This client is already busy
   //  493 Client failed to send a message
-  
+
   // try to do this transaction on the DACP server, but don't wait for more than 20 ms to be allowed
   // to do it.
   struct timespec mutex_wait_time;
@@ -142,98 +146,99 @@ int dacp_send_command(const char *command, char **body, size_t *bodysize) {
   hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
 
-  debug(1, "DHCP port string is \"%s:%s\".", server, portstring);
+  // debug(1, "DHCP port string is \"%s:%s\".", server, portstring);
 
   int ires = getaddrinfo(server, portstring, &hints, &res);
   if (ires) {
-    // debug(1,"Error %d \"%s\" at getaddrinfo.",ires,gai_strerror(ires)); 
+    // debug(1,"Error %d \"%s\" at getaddrinfo.",ires,gai_strerror(ires));
     response.code = 498; // Bad Address information for the DACP server
   } else {
 
-  // only do this one at a time -- not sure it is necessary, but better safe than sorry
+    // only do this one at a time -- not sure it is necessary, but better safe than sorry
 
-  int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time);
-  if (mutex_reply == 0) {
+    int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time);
+    if (mutex_reply == 0) {
 
-    // make a socket:
-    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+      // make a socket:
+      sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
 
-    if (sockfd == -1) {
-      // debug(1, "DACP socket could not be created -- error %d: \"%s\".",errno,strerror(errno));
-      response.code = 497; // Can't establish a socket to the DACP server
-    } else {
-
-      // connect!
-                       // debug(1, "DACP socket created.");
-      if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
-        // debug(1, "DACP connect failed.");
-        response.code = 496; // Can't connect to the DACP server
+      if (sockfd == -1) {
+        // debug(1, "DACP socket could not be created -- error %d: \"%s\".",errno,strerror(errno));
+        response.code = 497; // Can't establish a socket to the DACP server
       } else {
-       // debug(1,"DACP connect succeeded.");
 
-        sprintf(message, "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
-                command, dacp_server.ip_string, dacp_server.port, dacp_server.active_remote_id);
+        // connect!
+        // debug(1, "DACP socket created.");
+        if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
+          // debug(1, "DACP connect failed.");
+          response.code = 496; // Can't connect to the DACP server
+        } else {
+          // debug(1,"DACP connect succeeded.");
 
-        // Send command
-        // debug(1,"DACP connect message: \"%s\".",message);
-        if (send(sockfd, message, strlen(message), 0) != strlen(message)) {
-          // debug(1, "Send failed");
-          response.code = 493; // Client failed to send a message
+          sprintf(message,
+                  "GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
+                  command, dacp_server.ip_string, dacp_server.port, dacp_server.active_remote_id);
 
-        } else {
+          // Send command
+          // debug(1,"DACP connect message: \"%s\".",message);
+          if (send(sockfd, message, strlen(message), 0) != strlen(message)) {
+            // debug(1, "Send failed");
+            response.code = 493; // Client failed to send a message
+
+          } else {
 
-          response.body = malloc(2048); // it can resize this if necessary
-          response.malloced_size = 2048;
-
-          struct http_roundtripper rt;
-          http_init(&rt, responseFuncs, &response);
-
-          int needmore = 1;
-          int looperror = 0;
-          char buffer[1024];
-          memset(buffer,0,sizeof(buffer));
-          while (needmore && !looperror) {
-            const char *data = buffer;
-            int ndata = recv(sockfd, buffer, sizeof(buffer), 0);
-            // debug(1,"Received %d bytes: \"%s\".",ndata,buffer);
-            if (ndata <= 0) {
-              debug(1, "Error receiving data.");
+            response.body = malloc(2048); // it can resize this if necessary
+            response.malloced_size = 2048;
+
+            struct http_roundtripper rt;
+            http_init(&rt, responseFuncs, &response);
+
+            int needmore = 1;
+            int looperror = 0;
+            char buffer[1024];
+            memset(buffer, 0, sizeof(buffer));
+            while (needmore && !looperror) {
+              const char *data = buffer;
+              int ndata = recv(sockfd, buffer, sizeof(buffer), 0);
+              // debug(1,"Received %d bytes: \"%s\".",ndata,buffer);
+              if (ndata <= 0) {
+                debug(1, "Error receiving data.");
+                free(response.body);
+                response.body = NULL;
+                response.malloced_size = 0;
+                response.size = 0;
+                response.code = 495; // Error receiving response
+                looperror = 1;
+              }
+
+              while (needmore && ndata && !looperror) {
+                int read;
+                needmore = http_data(&rt, data, ndata, &read);
+                ndata -= read;
+                data += read;
+              }
+            }
+
+            if (http_iserror(&rt)) {
+              debug(1, "Error parsing data.");
               free(response.body);
               response.body = NULL;
               response.malloced_size = 0;
               response.size = 0;
-              response.code = 495; // Error receiving response
-              looperror = 1;
-            }
-
-            while (needmore && ndata && !looperror) {
-              int read;
-              needmore = http_data(&rt, data, ndata, &read);
-              ndata -= read;
-              data += read;
             }
+            // debug(1,"Size of response body is %d",response.size);
+            http_free(&rt);
           }
-
-          if (http_iserror(&rt)) {
-            debug(1, "Error parsing data.");
-            free(response.body);
-            response.body = NULL;
-            response.malloced_size = 0;
-            response.size = 0;
-          }
-          // debug(1,"Size of response body is %d",response.size);
-          http_free(&rt);
-          
-       }
+        }
+        close(sockfd);
+        // debug(1,"DACP socket closed.");
       }
-       close(sockfd);
-       // debug(1,"DACP socket closed.");      
+      pthread_mutex_unlock(&dacp_conversation_lock);
+    } else {
+      // debug(1, "Could not acquire a lock on the dacp transmit/receive section. Possible
+      // timeout?");
+      response.code = 494; // This client is already busy
     }
-    pthread_mutex_unlock(&dacp_conversation_lock);
-  } else {
-    // debug(1, "Could not acquire a lock on the dacp transmit/receive section. Possible timeout?");
-    response.code = 494; // This client is already busy
-  }
   }
   *body = response.body;
   *bodysize = response.size;
@@ -281,8 +286,9 @@ void *dacp_monitor_thread_code(void *na) {
       pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
     }
     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++);
+    // 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;
@@ -292,18 +298,21 @@ void *dacp_monitor_thread_code(void *na) {
     int result = dacp_send_command(command, &response, &le);
     if (result == 200) {
       char *sp = response;
-      if (le >= 0) {
+      if (le >= 8) {
+        // here, we know that we are receiving playerstatusupdates, so set a flag
+        metadata.playerstatusupdates_are_received = 1;
         // here start looking for the contents of the status update
         if (dacp_tlv_crawl(&sp, &item_size) == 'cmst') { // status
           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);
+            //*(uint32_t *)typestring = htonl(type);
+            // typestring[4] = 0;
+            // printf("\"%s\" %4d", typestring, item_size);
 
             le -= item_size + 8;
             char *t;
@@ -312,67 +321,221 @@ void *dacp_monitor_thread_code(void *na) {
             int32_t r;
             uint64_t s, v;
             int i;
-            switch (type) {
 
-            case 'mstt':
-            case 'cant':
-            case 'cast':
-            case 'cmmk':
-            case 'caas':
-            case 'caar':
-            case 'astm':
+            switch (type) {
+            case 'cmsr': // revision number
               t = sp - item_size;
-              r = ntohl(*(int32_t *)(t));
-              printf("    %d", r);
-              printf("    (0x");
+              revision_number = ntohl(*(int32_t *)(t));
+              // debug(1,"    Serial Number: %d", revision_number);
+              break;
+            case 'caps': // play status
               t = sp - item_size;
-              for (i = 0; i < item_size; i++) {
-                printf("%02x", *t&0xff);
-                t++;
+              r = *(unsigned char *)(t);
+              switch (r) {
+              case 2:
+                if (metadata.play_status != PS_STOPPED) {
+                  metadata.play_status = PS_STOPPED;
+                  metadata.play_status_changed = 1;
+                  debug(1, "Play status set to \"stopped\".");
+                  metadata.changed = 1;
+                }
+                break;
+              case 3:
+                if (metadata.play_status != PS_PAUSED) {
+                  metadata.play_status = PS_PAUSED;
+                  metadata.play_status_changed = 1;
+                  debug(1, "Play status set to \"paused\".");
+                  metadata.changed = 1;
+                }
+                break;
+              case 4:
+                if (metadata.play_status != PS_PLAYING) {
+                  metadata.play_status = PS_PLAYING;
+                  metadata.play_status_changed = 1;
+                  debug(1, "Play status set to \"playing\".");
+                  metadata.changed = 1;
+                }
+                break;
+              default:
+                debug(1, "Unrecognised play status %d received.", r);
+                break;
               }
-              printf(")");
               break;
-            case 'cmsr':
+            case 'cash': // shuffle status
               t = sp - item_size;
-              revision_number = ntohl(*(int32_t *)(t));
-              printf("    Serial Number: %d", revision_number);
+              r = *(unsigned char *)(t);
+              switch (r) {
+              case 0:
+                if (metadata.shuffle_status != SS_OFF) {
+                  metadata.shuffle_status = SS_OFF;
+                  metadata.shuffle_status_changed = 1;
+                  debug(1, "Shuffle status set to \"off\".");
+                  metadata.changed = 1;
+                }
+                break;
+              case 1:
+                if (metadata.shuffle_status != SS_ON) {
+                  metadata.shuffle_status = SS_ON;
+                  metadata.shuffle_status_changed = 1;
+                  debug(1, "Shuffle status set to \"on\".");
+                  metadata.changed = 1;
+                }
+                break;
+              default:
+                debug(1, "Unrecognised shuffle status %d received.", r);
+                break;
+              }
               break;
-            case 'cann':
-            case 'cana':
-            case 'canl':
-            case 'cang':
+            case 'carp': // repeat status
               t = sp - item_size;
-              st = strndup(t, item_size);
-              printf("    \"%s\"", st);
-              free(st);
+              r = *(unsigned char *)(t);
+              switch (r) {
+              case 0:
+                if (metadata.repeat_status != RS_NONE) {
+                  metadata.repeat_status = RS_NONE;
+                  metadata.repeat_status_changed = 1;
+                  debug(1, "Repeat status set to \"none\".");
+                  metadata.changed = 1;
+                }
+                break;
+              case 1:
+                if (metadata.repeat_status != RS_SINGLE) {
+                  metadata.repeat_status = RS_SINGLE;
+                  metadata.repeat_status_changed = 1;
+                  debug(1, "Repeat status set to \"single\".");
+                  metadata.changed = 1;
+                }
+                break;
+              case 2:
+                if (metadata.repeat_status != RS_ALL) {
+                  metadata.repeat_status = RS_ALL;
+                  metadata.repeat_status_changed = 1;
+                  debug(1, "Repeat status set to \"all\".");
+                  metadata.changed = 1;
+                }
+                break;
+              default:
+                debug(1, "Unrecognised repeat status %d received.", r);
+                break;
+              }
               break;
-            case 'asai':
+            case 'cann': // track name
               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");
+              if ((metadata.track_name == NULL) ||
+                  (strncmp(metadata.track_name, t, item_size) != 0)) {
+                if (metadata.track_name)
+                  free(metadata.track_name);
+                metadata.track_name = strndup(t, item_size);
+                debug(1, "Track name set to: \"%s\"", metadata.track_name);
+                metadata.track_name_changed = 1;
+                metadata.changed = 1;
+              }
+              break;
+            case 'cana': // artist name
               t = sp - item_size;
-              for (i = 0; i < item_size; i++) {
-                printf("%02x", *t&0xff);
-                t++;
+              if ((metadata.artist_name == NULL) ||
+                  (strncmp(metadata.artist_name, t, item_size) != 0)) {
+                if (metadata.artist_name)
+                  free(metadata.artist_name);
+                metadata.artist_name = strndup(t, item_size);
+                debug(1, "Artist name set to: \"%s\"", metadata.artist_name);
+                metadata.artist_name_changed = 1;
+                metadata.changed = 1;
               }
-              printf(")");
               break;
-            default:
-              printf("    0x");
+            case 'canl': // album name
+              t = sp - item_size;
+              if ((metadata.album_name == NULL) ||
+                  (strncmp(metadata.album_name, t, item_size) != 0)) {
+                if (metadata.album_name)
+                  free(metadata.album_name);
+                metadata.album_name = strndup(t, item_size);
+                debug(1, "Album name set to: \"%s\"", metadata.album_name);
+                metadata.album_name_changed = 1;
+                metadata.changed = 1;
+              }
+              break;
+            case 'cang': // genre
+              t = sp - item_size;
+              if ((metadata.genre == NULL) || (strncmp(metadata.genre, t, item_size) != 0)) {
+                if (metadata.genre)
+                  free(metadata.genre);
+                metadata.genre = strndup(t, item_size);
+                debug(1, "Genre set to: \"%s\"", metadata.genre);
+                metadata.genre_changed = 1;
+                metadata.changed = 1;
+              }
+              break;
+            case 'canp': // nowplaying 4 ids: dbid, plid, playlistItem, itemid (from mellowware --
+                         // see reference above)
               t = sp - item_size;
-              for (i = 0; i < item_size; i++) {
-                printf("%02x", *t&0xff);
-                t++;
+              if (memcmp(metadata.item_composite_id, t, sizeof(metadata.item_composite_id)) != 0) {
+                memcpy(metadata.item_composite_id, t, sizeof(metadata.item_composite_id));
+
+                char st[33];
+                char *pt = st;
+                int it;
+                for (it = 0; it < 16; it++) {
+                  sprintf(pt, "%02X", metadata.item_composite_id[it]);
+                  pt += 2;
+                }
+                *pt = 0;
+                debug(1, "Item composite ID set to 0x%s.", st);
+                metadata.item_id_changed = 1;
+                metadata.changed = 1;
               }
               break;
+            /*
+                        case 'mstt':
+                        case 'cant':
+                        case 'cast':
+                        case 'cmmk':
+                        case 'caas':
+                        case 'caar':
+                        case 'astm':
+                          t = sp - item_size;
+                          r = ntohl(*(int32_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");
           }
+          // now, if the metadata is changed, send a signal
+
         } else {
           printf("Status Update not found.\n");
         }
@@ -381,6 +544,7 @@ void *dacp_monitor_thread_code(void *na) {
         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) {
diff --git a/metadata.c b/metadata.c
new file mode 100644 (file)
index 0000000..7faed20
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Metadata store and access methods.
+ * This file is part of Shairport Sync.
+ * Copyright (c) Mike Brady 2017
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "dacp.h"
+#include "metadata.h"
+
+void metadata_bundle_init(void) {
+  debug(1, "Metadata bundle initialisation.");
+  memset(&metadata, 0, sizeof(metadata));
+}
diff --git a/metadata.h b/metadata.h
new file mode 100644 (file)
index 0000000..13e7e26
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+#include "common.h"
+#include "config.h"
+#include <pthread.h>
+
+enum play_status_type {
+  PS_PLAYING = 0,
+  PS_PAUSED,
+  PS_STOPPED,
+} play_status_type;
+
+enum shuffle_status_type {
+  SS_OFF = 0,
+  SS_ON,
+} shuffle_status_type;
+
+enum repeat_status_type {
+  RS_NONE = 0,
+  RS_SINGLE,
+  RS_ALL,
+} repeat_status_type;
+
+typedef struct metadata_bundle {
+  int changed;                          // normally 0, nonzero if a field has been changed
+  int playerstatusupdates_are_received; // false if it's "traditional" metadata
+
+  enum play_status_type play_status;
+  int play_status_changed;
+
+  enum shuffle_status_type shuffle_status;
+  int shuffle_status_changed;
+
+  enum repeat_status_type repeat_status;
+  int repeat_status_changed;
+
+  char *track_name; // a malloced string -- if non-zero, free it before replacing it
+  int track_name_changed;
+
+  char *artist_name; // a malloced string -- if non-zero, free it before replacing it
+  int artist_name_changed;
+
+  char *album_name; // a malloced string -- if non-zero, free it before replacing it
+  int album_name_changed;
+
+  char *genre; // a malloced string -- if non-zero, free it before replacing it
+  int genre_changed;
+
+  uint32_t item_id; // seems to be a track ID -- see itemid in DACP.c
+  int item_id_changed;
+
+  unsigned char
+      item_composite_id[16]; // seems to be nowplaying 4 ids: dbid, plid, playlistItem, itemid
+
+} metadata_bundle;
+
+struct metadata_bundle metadata;
+
+void metadata_bundle_init(void);
diff --git a/rtp.c b/rtp.c
index ef16f94ad2d805e97ca3e8edd7457f6c4516c053..64fbe6d7cca27950979886d1de3d3a84453e5c62 100644 (file)
--- a/rtp.c
+++ b/rtp.c
@@ -231,8 +231,9 @@ void *rtp_control_receiver(void *arg) {
               sync_rtp_timestamp - rtp_timestamp_less_latency + conn->staticLatencyCorrection;
           if (la != config.latency) {
             config.latency = la;
-            //debug(1,
-            //      "Using negotiated latency of %lld frames and a static latency correction of %lld",
+            // debug(1,
+            //      "Using negotiated latency of %lld frames and a static latency correction of
+            //      %lld",
             //      sync_rtp_timestamp - rtp_timestamp_less_latency, conn->staticLatencyCorrection);
           }
         }
index 6ba0fba5ffb2ca9b6d582bd04ffc3f0f684a549b..0687a2b439c501225f0364317903957ec38476ec 100644 (file)
@@ -60,6 +60,7 @@
 
 #if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
 #include "dacp.h"
+#include "metadata.h"
 #endif
 
 #ifdef HAVE_DBUS
@@ -1540,6 +1541,11 @@ int main(int argc, char **argv) {
   metadata_init(); // create the metadata pipe if necessary
 #endif
 
+#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
+  debug(1, "Initialising metadata bundle");
+  metadata_bundle_init();
+#endif
+
 #if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
   debug(1, "Requesting DACP Monitor");
   dacp_monitor_start();