Pass on rtpmap to raop_buffer in order to add AAC support later
[deb_shairplay.git] / src / lib / raop_rtp.c
index 3400c0c9169e65679b0ec573cb6899bf5573b2eb..e80da78d0d1ee3bc86c2712c377e5e66420a23d7 100644 (file)
@@ -39,13 +39,22 @@ struct raop_rtp_s {
        struct sockaddr_storage remote_saddr;
        socklen_t remote_saddr_len;
 
+       /* MUTEX LOCKED VARIABLES START */
        /* These variables only edited mutex locked */
        int running;
        int joined;
+
        float volume;
+       int volume_changed;
+       unsigned char *metadata;
+       int metadata_len;
+       unsigned char *coverart;
+       int coverart_len;
+
        int flush;
        thread_handle_t thread;
        mutex_handle_t run_mutex;
+       /* MUTEX LOCKED VARIABLES END */
 
        /* Remote control and timing ports */
        unsigned short control_rport;
@@ -94,6 +103,10 @@ raop_rtp_parse_remote(raop_rtp_t *raop_rtp, const char *remote)
                free(original);
                return -1;
        }
+       if (strstr(current, ":")) {
+               /* FIXME: iTunes sends IP4 even with an IPv6 address, does it mean something */
+               family = AF_INET6;
+       }
        ret = netutils_parse_address(family, current,
                                     &raop_rtp->remote_saddr,
                                     sizeof(raop_rtp->remote_saddr));
@@ -108,13 +121,15 @@ raop_rtp_parse_remote(raop_rtp_t *raop_rtp, const char *remote)
 
 raop_rtp_t *
 raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote,
-              const char *fmtp, const unsigned char *aeskey, const unsigned char *aesiv)
+              const char *rtpmap, const char *fmtp,
+              const unsigned char *aeskey, const unsigned char *aesiv)
 {
        raop_rtp_t *raop_rtp;
 
        assert(logger);
        assert(callbacks);
        assert(remote);
+       assert(rtpmap);
        assert(fmtp);
 
        raop_rtp = calloc(1, sizeof(raop_rtp_t));
@@ -123,7 +138,7 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote,
        }
        raop_rtp->logger = logger;
        memcpy(&raop_rtp->callbacks, callbacks, sizeof(raop_callbacks_t));
-       raop_rtp->buffer = raop_buffer_init(fmtp, aeskey, aesiv);
+       raop_rtp->buffer = raop_buffer_init(rtpmap, fmtp, aeskey, aesiv);
        if (!raop_rtp->buffer) {
                free(raop_rtp);
                return NULL;
@@ -149,6 +164,8 @@ raop_rtp_destroy(raop_rtp_t *raop_rtp)
 
                MUTEX_DESTROY(raop_rtp->run_mutex);
                raop_buffer_destroy(raop_rtp->buffer);
+               free(raop_rtp->metadata);
+               free(raop_rtp->coverart);
                free(raop_rtp);
        }
 }
@@ -231,6 +248,78 @@ raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short cou
        return 0;
 }
 
+static int
+raop_rtp_process_events(raop_rtp_t *raop_rtp, void *cb_data)
+{
+       int flush;
+       float volume;
+       int volume_changed;
+       unsigned char *metadata;
+       int metadata_len;
+       unsigned char *coverart;
+       int coverart_len;
+
+       assert(raop_rtp);
+
+       MUTEX_LOCK(raop_rtp->run_mutex);
+       if (!raop_rtp->running) {
+               MUTEX_UNLOCK(raop_rtp->run_mutex);
+               return 1;
+       }
+
+       /* Read the volume level */
+       volume = raop_rtp->volume;
+       volume_changed = raop_rtp->volume_changed;
+       raop_rtp->volume_changed = 0;
+
+       /* Read the flush value */
+       flush = raop_rtp->flush;
+       raop_rtp->flush = NO_FLUSH;
+
+       /* Read the metadata */
+       metadata = raop_rtp->metadata;
+       metadata_len = raop_rtp->metadata_len;
+       raop_rtp->metadata = NULL;
+       raop_rtp->metadata_len = 0;
+
+       /* Read the coverart */
+       coverart = raop_rtp->coverart;
+       coverart_len = raop_rtp->coverart_len;
+       raop_rtp->coverart = NULL;
+       raop_rtp->coverart_len = 0;
+       MUTEX_UNLOCK(raop_rtp->run_mutex);
+
+       /* Call set_volume callback if changed */
+       if (volume_changed) {
+               if (raop_rtp->callbacks.audio_set_volume) {
+                       raop_rtp->callbacks.audio_set_volume(raop_rtp->callbacks.cls, cb_data, volume);
+               }
+       }
+
+       /* Handle flush if requested */
+       if (flush != NO_FLUSH) {
+               raop_buffer_flush(raop_rtp->buffer, flush);
+               if (raop_rtp->callbacks.audio_flush) {
+                       raop_rtp->callbacks.audio_flush(raop_rtp->callbacks.cls, cb_data);
+               }
+       }
+       if (metadata != NULL) {
+               if (raop_rtp->callbacks.audio_set_metadata) {
+                       raop_rtp->callbacks.audio_set_metadata(raop_rtp->callbacks.cls, cb_data, metadata, metadata_len);
+               }
+               free(metadata);
+               metadata = NULL;
+       }
+       if (coverart != NULL) {
+               if (raop_rtp->callbacks.audio_set_coverart) {
+                       raop_rtp->callbacks.audio_set_coverart(raop_rtp->callbacks.cls, cb_data, coverart, coverart_len);
+               }
+               free(coverart);
+               coverart = NULL;
+       }
+       return 0;
+}
+
 static THREAD_RETVAL
 raop_rtp_thread_udp(void *arg)
 {
@@ -239,7 +328,6 @@ raop_rtp_thread_udp(void *arg)
        unsigned int packetlen;
        struct sockaddr_storage saddr;
        socklen_t saddrlen;
-       float volume = 0.0;
 
        const ALACSpecificConfig *config;
        void *cb_data = NULL;
@@ -253,35 +341,14 @@ raop_rtp_thread_udp(void *arg)
                                       config->sampleRate);
 
        while(1) {
-               int volume_changed;
-               int flush;
-
                fd_set rfds;
                struct timeval tv;
                int nfds, ret;
 
-               MUTEX_LOCK(raop_rtp->run_mutex);
-               if (!raop_rtp->running) {
-                       MUTEX_UNLOCK(raop_rtp->run_mutex);
+               /* Check if we are still running and process callbacks */
+               if (raop_rtp_process_events(raop_rtp, cb_data)) {
                        break;
                }
-               /* Read the volume level */
-               volume_changed = (volume != raop_rtp->volume);
-               volume = raop_rtp->volume;
-
-               /* Read the flush value */
-               flush = raop_rtp->flush;
-               raop_rtp->flush = NO_FLUSH;
-               MUTEX_UNLOCK(raop_rtp->run_mutex);
-
-               /* Call set_volume callback if changed */
-               if (volume_changed) {
-                       raop_rtp->callbacks.audio_set_volume(raop_rtp->callbacks.cls, cb_data, volume);
-               }
-               if (flush != NO_FLUSH) {
-                       raop_buffer_flush(raop_rtp->buffer, flush);
-                       raop_rtp->callbacks.audio_flush(raop_rtp->callbacks.cls, cb_data);
-               }
 
                /* Set timeout value to 5ms */
                tv.tv_sec = 0;
@@ -368,7 +435,6 @@ raop_rtp_thread_tcp(void *arg)
        int stream_fd = -1;
        unsigned char packet[RAOP_PACKET_LEN];
        unsigned int packetlen = 0;
-       float volume = 0.0;
 
        const ALACSpecificConfig *config;
        void *cb_data = NULL;
@@ -382,25 +448,14 @@ raop_rtp_thread_tcp(void *arg)
                                       config->sampleRate);
 
        while (1) {
-               int volume_changed;
-
                fd_set rfds;
                struct timeval tv;
                int nfds, ret;
 
-               MUTEX_LOCK(raop_rtp->run_mutex);
-               if (!raop_rtp->running) {
-                       MUTEX_UNLOCK(raop_rtp->run_mutex);
+               /* Check if we are still running and process callbacks */
+               if (raop_rtp_process_events(raop_rtp, cb_data)) {
                        break;
                }
-               volume_changed = (volume != raop_rtp->volume);
-               volume = raop_rtp->volume;
-               MUTEX_UNLOCK(raop_rtp->run_mutex);
-
-               /* Call set_volume callback if changed */
-               if (volume_changed) {
-                       raop_rtp->callbacks.audio_set_volume(raop_rtp->callbacks.cls, cb_data, volume);
-               }
 
                /* Set timeout value to 5ms */
                tv.tv_sec = 0;
@@ -553,6 +608,49 @@ raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume)
        /* Set volume in thread instead */
        MUTEX_LOCK(raop_rtp->run_mutex);
        raop_rtp->volume = volume;
+       raop_rtp->volume_changed = 1;
+       MUTEX_UNLOCK(raop_rtp->run_mutex);
+}
+
+void
+raop_rtp_set_metadata(raop_rtp_t *raop_rtp, const char *data, int datalen)
+{
+       unsigned char *metadata;
+
+       assert(raop_rtp);
+
+       if (datalen <= 0) {
+               return;
+       }
+       metadata = malloc(datalen);
+       assert(metadata);
+       memcpy(metadata, data, datalen);
+
+       /* Set metadata in thread instead */
+       MUTEX_LOCK(raop_rtp->run_mutex);
+       raop_rtp->metadata = metadata;
+       raop_rtp->metadata_len = datalen;
+       MUTEX_UNLOCK(raop_rtp->run_mutex);
+}
+
+void
+raop_rtp_set_coverart(raop_rtp_t *raop_rtp, const char *data, int datalen)
+{
+       unsigned char *coverart;
+
+       assert(raop_rtp);
+
+       if (datalen <= 0) {
+               return;
+       }
+       coverart = malloc(datalen);
+       assert(coverart);
+       memcpy(coverart, data, datalen);
+
+       /* Set coverart in thread instead */
+       MUTEX_LOCK(raop_rtp->run_mutex);
+       raop_rtp->coverart = coverart;
+       raop_rtp->coverart_len = datalen;
        MUTEX_UNLOCK(raop_rtp->run_mutex);
 }