X-Git-Url: https://git.distorted.org.uk/~mdw/disorder/blobdiff_plain/b1f6ca8ccc002bc4529fb1f1fef562cf59a25bd5..0c1d42ad03f7e49b23755209f5b1f295cbe21f6b:/lib/uaudio-rtp.c diff --git a/lib/uaudio-rtp.c b/lib/uaudio-rtp.c index e1768a8..3ce1cbe 100644 --- a/lib/uaudio-rtp.c +++ b/lib/uaudio-rtp.c @@ -97,7 +97,7 @@ static void rtp_get_netconfig(const char *af, na->af = -1; else if(netaddress_parse(na, 3, vec)) - fatal(0, "invalid RTP address"); + disorder_fatal(0, "invalid RTP address"); } static void rtp_set_netconfig(const char *af, @@ -164,6 +164,20 @@ static size_t rtp_play(void *buffer, size_t nsamples, unsigned flags) { vec[1].iov_len = nsamples * uaudio_sample_size; const uint32_t timestamp = uaudio_schedule_sync(); header.timestamp = htonl(rtp_base + (uint32_t)timestamp); + + /* We send ~120 packets a second with current arrangements. So if we log + * once every 8192 packets we log about once a minute. */ + + if(!(ntohs(header.seq) & 8191) + && config->rtp_verbose) + disorder_info("RTP: seq %04"PRIx16" %08"PRIx32"+%08"PRIx32"=%08"PRIx32" ns %zu%s", + ntohs(header.seq), + rtp_base, + timestamp, + header.timestamp, + nsamples, + flags & UAUDIO_PAUSED ? " [paused]" : ""); + /* If we're paused don't actually end a packet, we just pretend */ if(flags & UAUDIO_PAUSED) { uaudio_schedule_sent(nsamples); @@ -174,10 +188,10 @@ static size_t rtp_play(void *buffer, size_t nsamples, unsigned flags) { written_bytes = writev(rtp_fd, vec, 2); } while(written_bytes < 0 && errno == EINTR); if(written_bytes < 0) { - error(errno, "error transmitting audio data"); + disorder_error(errno, "error transmitting audio data"); ++rtp_errors; if(rtp_errors == 10) - fatal(0, "too many audio tranmission errors"); + disorder_fatal(0, "too many audio tranmission errors"); return 0; } else rtp_errors /= 2; /* gradual decay */ @@ -219,7 +233,7 @@ static void rtp_open(void) { if((rtp_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - fatal(errno, "error creating broadcast socket"); + disorder_fatal(errno, "error creating broadcast socket"); if(multicast(res->ai_addr)) { /* Enable multicast options */ const int ttl = atoi(uaudio_get("multicast-ttl", "1")); @@ -228,31 +242,31 @@ static void rtp_open(void) { case PF_INET: { if(setsockopt(rtp_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof ttl) < 0) - fatal(errno, "error setting IP_MULTICAST_TTL on multicast socket"); + disorder_fatal(errno, "error setting IP_MULTICAST_TTL on multicast socket"); if(setsockopt(rtp_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof loop) < 0) - fatal(errno, "error setting IP_MULTICAST_LOOP on multicast socket"); + disorder_fatal(errno, "error setting IP_MULTICAST_LOOP on multicast socket"); break; } case PF_INET6: { if(setsockopt(rtp_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof ttl) < 0) - fatal(errno, "error setting IPV6_MULTICAST_HOPS on multicast socket"); + disorder_fatal(errno, "error setting IPV6_MULTICAST_HOPS on multicast socket"); if(setsockopt(rtp_fd, IPPROTO_IP, IPV6_MULTICAST_LOOP, &loop, sizeof loop) < 0) - fatal(errno, "error setting IPV6_MULTICAST_LOOP on multicast socket"); + disorder_fatal(errno, "error setting IPV6_MULTICAST_LOOP on multicast socket"); break; } default: - fatal(0, "unsupported address family %d", res->ai_family); + disorder_fatal(0, "unsupported address family %d", res->ai_family); } - info("multicasting on %s TTL=%d loop=%s", - format_sockaddr(res->ai_addr), ttl, loop ? "yes" : "no"); + disorder_info("multicasting on %s TTL=%d loop=%s", + format_sockaddr(res->ai_addr), ttl, loop ? "yes" : "no"); } else { struct ifaddrs *ifs; if(getifaddrs(&ifs) < 0) - fatal(errno, "error calling getifaddrs"); + disorder_fatal(errno, "error calling getifaddrs"); while(ifs) { /* (At least on Darwin) IFF_BROADCAST might be set but ifa_broadaddr * still a null pointer. It turns out that there's a subsequent entry @@ -265,35 +279,36 @@ static void rtp_open(void) { } if(ifs) { if(setsockopt(rtp_fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof one) < 0) - fatal(errno, "error setting SO_BROADCAST on broadcast socket"); - info("broadcasting on %s (%s)", + disorder_fatal(errno, "error setting SO_BROADCAST on broadcast socket"); + disorder_info("broadcasting on %s (%s)", format_sockaddr(res->ai_addr), ifs->ifa_name); } else - info("unicasting on %s", format_sockaddr(res->ai_addr)); + disorder_info("unicasting on %s", format_sockaddr(res->ai_addr)); } /* Enlarge the socket buffer */ len = sizeof sndbuf; if(getsockopt(rtp_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, &len) < 0) - fatal(errno, "error getting SO_SNDBUF"); + disorder_fatal(errno, "error getting SO_SNDBUF"); if(target_sndbuf > sndbuf) { if(setsockopt(rtp_fd, SOL_SOCKET, SO_SNDBUF, &target_sndbuf, sizeof target_sndbuf) < 0) - error(errno, "error setting SO_SNDBUF to %d", target_sndbuf); + disorder_error(errno, "error setting SO_SNDBUF to %d", target_sndbuf); else - info("changed socket send buffer size from %d to %d", + disorder_info("changed socket send buffer size from %d to %d", sndbuf, target_sndbuf); } else - info("default socket send buffer is %d", - sndbuf); + disorder_info("default socket send buffer is %d", sndbuf); /* We might well want to set additional broadcast- or multicast-related * options here */ if(sres && bind(rtp_fd, sres->ai_addr, sres->ai_addrlen) < 0) - fatal(errno, "error binding broadcast socket to %s", - format_sockaddr(sres->ai_addr)); + disorder_fatal(errno, "error binding broadcast socket to %s", + format_sockaddr(sres->ai_addr)); if(connect(rtp_fd, res->ai_addr, res->ai_addrlen) < 0) - fatal(errno, "error connecting broadcast socket to %s", - format_sockaddr(res->ai_addr)); + disorder_fatal(errno, "error connecting broadcast socket to %s", + format_sockaddr(res->ai_addr)); + if(config->rtp_verbose) + disorder_info("RTP: prepared socket"); } static void rtp_start(uaudio_callback *callback, @@ -308,16 +323,24 @@ static void rtp_start(uaudio_callback *callback, && uaudio_rate == 44100) rtp_payload = 11; else - fatal(0, "asked for %d/%d/%d 16/44100/1 and 16/44100/2", - uaudio_bits, uaudio_rate, uaudio_channels); + disorder_fatal(0, "asked for %d/%d/%d 16/44100/1 and 16/44100/2", + uaudio_bits, uaudio_rate, uaudio_channels); + if(config->rtp_verbose) + disorder_info("RTP: %d channels %d bits %d Hz payload type %d", + uaudio_channels, uaudio_bits, uaudio_rate, rtp_payload); /* Various fields are required to have random initial values by RFC3550. The * packet contents are highly public so there's no point asking for very * strong randomness. */ gcry_create_nonce(&rtp_id, sizeof rtp_id); gcry_create_nonce(&rtp_base, sizeof rtp_base); gcry_create_nonce(&rtp_sequence, sizeof rtp_sequence); + if(config->rtp_verbose) + disorder_info("RTP: id %08"PRIx32" base %08"PRIx32" initial seq %08"PRIx16, + rtp_id, rtp_base, rtp_sequence); rtp_open(); uaudio_schedule_init(); + if(config->rtp_verbose) + disorder_info("RTP: initialized schedule"); uaudio_thread_start(callback, userdata, rtp_play, @@ -325,6 +348,8 @@ static void rtp_start(uaudio_callback *callback, (NETWORK_BYTES - sizeof(struct rtp_header)) / uaudio_sample_size, 0); + if(config->rtp_verbose) + disorder_info("RTP: created thread"); } static void rtp_stop(void) { @@ -345,6 +370,8 @@ static void rtp_configure(void) { snprintf(buffer, sizeof buffer, "%ld", config->multicast_ttl); uaudio_set("multicast-ttl", buffer); uaudio_set("multicast-loop", config->multicast_loop ? "yes" : "no"); + if(config->rtp_verbose) + disorder_info("RTP: configured"); } const struct uaudio uaudio_rtp = {