X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fraop_rtp.c;h=1896e160b562c50e1b67081cb65c1950c86165fe;hb=3baaba9d370042e04c70653d46e18bc289d83269;hp=39ac7ab53d2d7c9f13b2ef0b10028e2b868bf275;hpb=23e7e3ae2b2adfa49635495c0950b76e17987c93;p=deb_shairplay.git diff --git a/src/lib/raop_rtp.c b/src/lib/raop_rtp.c index 39ac7ab..1896e16 100644 --- a/src/lib/raop_rtp.c +++ b/src/lib/raop_rtp.c @@ -22,6 +22,7 @@ #include "raop.h" #include "raop_buffer.h" #include "netutils.h" +#include "utils.h" #include "compat.h" #include "logger.h" @@ -31,15 +32,28 @@ struct raop_rtp_s { logger_t *logger; raop_callbacks_t callbacks; + /* Buffer to handle all resends */ raop_buffer_t *buffer; + /* Remote address as sockaddr */ + 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; + 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; @@ -53,18 +67,67 @@ struct raop_rtp_s { unsigned short timing_lport; unsigned short data_lport; + /* Initialized after the first control packet */ struct sockaddr_storage control_saddr; socklen_t control_saddr_len; unsigned short control_seqnum; }; +static int +raop_rtp_parse_remote(raop_rtp_t *raop_rtp, const char *remote) +{ + char *original; + char *current; + char *tmpstr; + int family; + int ret; + + assert(raop_rtp); + + current = original = strdup(remote); + if (!original) { + return -1; + } + tmpstr = utils_strsep(¤t, " "); + if (strcmp(tmpstr, "IN")) { + free(original); + return -1; + } + tmpstr = utils_strsep(¤t, " "); + if (!strcmp(tmpstr, "IP4") && current) { + family = AF_INET; + } else if (!strcmp(tmpstr, "IP6") && current) { + family = AF_INET6; + } else { + 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)); + if (ret < 0) { + free(original); + return -1; + } + raop_rtp->remote_saddr_len = ret; + free(original); + return 0; +} + raop_rtp_t * -raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *fmtp, - const unsigned char *aeskey, const unsigned char *aesiv) +raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, + const char *fmtp, const unsigned char *aeskey, const unsigned char *aesiv) { raop_rtp_t *raop_rtp; assert(logger); + assert(callbacks); + assert(remote); + assert(fmtp); raop_rtp = calloc(1, sizeof(raop_rtp_t)); if (!raop_rtp) { @@ -77,6 +140,10 @@ raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *fmtp, free(raop_rtp); return NULL; } + if (raop_rtp_parse_remote(raop_rtp, remote) < 0) { + free(raop_rtp); + return NULL; + } raop_rtp->running = 0; raop_rtp->joined = 1; @@ -94,6 +161,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); } } @@ -150,11 +219,12 @@ raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short cou unsigned short ourseqnum; struct sockaddr *addr; socklen_t addrlen; + int ret; addr = (struct sockaddr *)&raop_rtp->control_saddr; addrlen = raop_rtp->control_saddr_len; - logger_log(raop_rtp->logger, LOGGER_DEBUG, "Got resend request %d %d\n", seqnum, count); + logger_log(raop_rtp->logger, LOGGER_DEBUG, "Got resend request %d %d", seqnum, count); ourseqnum = raop_rtp->control_seqnum++; /* Fill the request buffer */ @@ -167,7 +237,11 @@ raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short cou packet[6] = (count >> 8); packet[7] = count; - sendto(raop_rtp->csock, (const char *)packet, sizeof(packet), 0, addr, addrlen); + ret = sendto(raop_rtp->csock, (const char *)packet, sizeof(packet), 0, addr, addrlen); + if (ret == -1) { + logger_log(raop_rtp->logger, LOGGER_WARNING, "Resend failed: %d", SOCKET_GET_ERROR()); + } + return 0; } @@ -179,6 +253,7 @@ 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; @@ -186,14 +261,13 @@ raop_rtp_thread_udp(void *arg) assert(raop_rtp); config = raop_buffer_get_config(raop_rtp->buffer); - raop_rtp->callbacks.audio_init(raop_rtp->callbacks.cls, &cb_data, + cb_data = raop_rtp->callbacks.audio_init(raop_rtp->callbacks.cls, config->bitDepth, config->numChannels, config->sampleRate); while(1) { int volume_changed; - float volume = 0.0; int flush; fd_set rfds; @@ -253,14 +327,14 @@ raop_rtp_thread_udp(void *arg) packetlen = recvfrom(raop_rtp->csock, (char *)packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &saddrlen); - /* FIXME: Get destination address here */ + /* Get the destination address here, because we need the sin6_scope_id */ memcpy(&raop_rtp->control_saddr, &saddr, saddrlen); raop_rtp->control_saddr_len = saddrlen; if (packetlen >= 12) { char type = packet[1] & ~0x80; - logger_log(raop_rtp->logger, LOGGER_DEBUG, "Got control packet of type 0x%02x\n", type); + logger_log(raop_rtp->logger, LOGGER_DEBUG, "Got control packet of type 0x%02x", type); if (type == 0x56) { /* Handle resent data packet */ int ret = raop_buffer_queue(raop_rtp->buffer, packet+4, packetlen-4, 1); @@ -268,7 +342,7 @@ raop_rtp_thread_udp(void *arg) } } } else if (FD_ISSET(raop_rtp->tsock, &rfds)) { - logger_log(raop_rtp->logger, LOGGER_INFO, "Would have timing packet in queue\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Would have timing packet in queue"); } else if (FD_ISSET(raop_rtp->dsock, &rfds)) { saddrlen = sizeof(saddr); packetlen = recvfrom(raop_rtp->dsock, (char *)packet, sizeof(packet), 0, @@ -295,7 +369,7 @@ raop_rtp_thread_udp(void *arg) } } } - logger_log(raop_rtp->logger, LOGGER_INFO, "Exiting thread\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Exiting UDP RAOP thread"); raop_rtp->callbacks.audio_destroy(raop_rtp->callbacks.cls, cb_data); return 0; @@ -308,6 +382,7 @@ 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; @@ -315,14 +390,13 @@ raop_rtp_thread_tcp(void *arg) assert(raop_rtp); config = raop_buffer_get_config(raop_rtp->buffer); - raop_rtp->callbacks.audio_init(raop_rtp->callbacks.cls, &cb_data, + cb_data = raop_rtp->callbacks.audio_init(raop_rtp->callbacks.cls, config->bitDepth, config->numChannels, config->sampleRate); while (1) { int volume_changed; - float volume = 0.0; fd_set rfds; struct timeval tv; @@ -361,25 +435,24 @@ raop_rtp_thread_tcp(void *arg) continue; } else if (ret == -1) { /* FIXME: Error happened */ - logger_log(raop_rtp->logger, LOGGER_INFO, "Error in select\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Error in select"); break; } if (stream_fd == -1 && FD_ISSET(raop_rtp->dsock, &rfds)) { struct sockaddr_storage saddr; socklen_t saddrlen; - logger_log(raop_rtp->logger, LOGGER_INFO, "Accepting client\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Accepting client"); saddrlen = sizeof(saddr); stream_fd = accept(raop_rtp->dsock, (struct sockaddr *)&saddr, &saddrlen); if (stream_fd == -1) { /* FIXME: Error happened */ - logger_log(raop_rtp->logger, LOGGER_INFO, "Error in accept %d %s\n", errno, strerror(errno)); + logger_log(raop_rtp->logger, LOGGER_INFO, "Error in accept %d %s", errno, strerror(errno)); break; } } if (stream_fd != -1 && FD_ISSET(stream_fd, &rfds)) { unsigned int rtplen=0; - char type; const void *audiobuf; int audiobuflen; @@ -387,11 +460,11 @@ raop_rtp_thread_tcp(void *arg) ret = recv(stream_fd, (char *)(packet+packetlen), sizeof(packet)-packetlen, 0); if (ret == 0) { /* TCP socket closed */ - logger_log(raop_rtp->logger, LOGGER_INFO, "TCP socket closed\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "TCP socket closed"); break; } else if (ret == -1) { /* FIXME: Error happened */ - logger_log(raop_rtp->logger, LOGGER_INFO, "Error in recv\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Error in recv"); break; } packetlen += ret; @@ -407,7 +480,7 @@ raop_rtp_thread_tcp(void *arg) rtplen = (packet[2] << 8) | packet[3]; if (rtplen > sizeof(packet)) { /* FIXME: Too long packet */ - logger_log(raop_rtp->logger, LOGGER_INFO, "Error, packet too long %d\n", rtplen); + logger_log(raop_rtp->logger, LOGGER_INFO, "Error, packet too long %d", rtplen); break; } if (packetlen < 4+rtplen) { @@ -415,7 +488,6 @@ raop_rtp_thread_tcp(void *arg) } /* Packet is valid, process it */ - type = packet[4+1] & ~0x80; ret = raop_buffer_queue(raop_rtp->buffer, packet+4, rtplen, 0); assert(ret >= 0); @@ -435,7 +507,7 @@ raop_rtp_thread_tcp(void *arg) closesocket(stream_fd); } - logger_log(raop_rtp->logger, LOGGER_INFO, "Exiting thread\n"); + logger_log(raop_rtp->logger, LOGGER_INFO, "Exiting TCP RAOP thread"); raop_rtp->callbacks.audio_destroy(raop_rtp->callbacks.cls, cb_data); return 0; @@ -445,6 +517,8 @@ void raop_rtp_start(raop_rtp_t *raop_rtp, int use_udp, unsigned short control_rport, unsigned short timing_rport, unsigned short *control_lport, unsigned short *timing_lport, unsigned short *data_lport) { + int use_ipv6 = 0; + assert(raop_rtp); MUTEX_LOCK(raop_rtp->run_mutex); @@ -456,8 +530,11 @@ raop_rtp_start(raop_rtp_t *raop_rtp, int use_udp, unsigned short control_rport, /* Initialize ports and sockets */ raop_rtp->control_rport = control_rport; raop_rtp->timing_rport = timing_rport; - if (raop_rtp_init_sockets(raop_rtp, 1, use_udp) < 0) { - logger_log(raop_rtp->logger, LOGGER_INFO, "Initializing sockets failed\n"); + if (raop_rtp->remote_saddr.ss_family == AF_INET6) { + use_ipv6 = 1; + } + if (raop_rtp_init_sockets(raop_rtp, use_ipv6, use_udp) < 0) { + logger_log(raop_rtp->logger, LOGGER_INFO, "Initializing sockets failed"); MUTEX_UNLOCK(raop_rtp->run_mutex); return; } @@ -493,6 +570,48 @@ raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume) 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); +} + void raop_rtp_flush(raop_rtp_t *raop_rtp, int next_seq) {