#include <sys/socket.h>
#include <sys/uio.h>
#include <assert.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
#include "configuration.h"
#include "syscalls.h"
#include "addr.h"
#include "timeval.h"
#include "rtp.h"
+#include "ifreq.h"
#include "speaker-protocol.h"
#include "speaker.h"
0
};
static const int one = 1;
- int sndbuf, target_sndbuf = 131072;
+ int sndbuf, target_sndbuf = 131072, n;
socklen_t len;
char *sockname, *ssockname;
+ /* Override sample format */
+ config->sample_format.rate = 44100;
+ config->sample_format.channels = 2;
+ config->sample_format.bits = 16;
+ config->sample_format.byte_format = AO_FMT_BIG;
res = get_address(&config->broadcast, &pref, &sockname);
if(!res) exit(-1);
if(config->broadcast_from.n) {
res->ai_socktype,
res->ai_protocol)) < 0)
fatal(errno, "error creating broadcast socket");
- if(setsockopt(bfd, SOL_SOCKET, SO_BROADCAST, &one, sizeof one) < 0)
- fatal(errno, "error setting SO_BROADCAST on broadcast socket");
+ if((res->ai_family == PF_INET
+ && IN_MULTICAST(
+ ntohl(((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr)
+ ))
+ || (res->ai_family == PF_INET6
+ && IN6_IS_ADDR_MULTICAST(
+ &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr
+ ))) {
+ /* Multicasting */
+ switch(res->ai_family) {
+ case PF_INET: {
+ const int mttl = config->multicast_ttl;
+ if(setsockopt(bfd, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, sizeof mttl) < 0)
+ fatal(errno, "error setting IP_MULTICAST_TTL on multicast socket");
+ break;
+ }
+ case PF_INET6: {
+ const int mttl = config->multicast_ttl;
+ if(setsockopt(bfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &mttl, sizeof mttl) < 0)
+ fatal(errno, "error setting IPV6_MULTICAST_HOPS on multicast socket");
+ break;
+ }
+ default:
+ fatal(0, "unsupported address family %d", res->ai_family);
+ }
+ info("multicasting on %s", sockname);
+ } else {
+ struct ifreq *ifs;
+ int nifs;
+
+ /* See if the address matches the broadcast address of some interface */
+ ifreq_list(bfd, &ifs, &nifs);
+ for(n = 0; n < nifs; ++n) {
+ if(ioctl(bfd, SIOCGIFBRDADDR, &ifs[n]) < 0)
+ fatal(errno, "error calling ioctl SIOCGIFBRDADDR");
+ if(sockaddr_equal(&ifs[n].ifr_broadaddr, res->ai_addr))
+ break;
+ }
+ if(n < nifs) {
+ if(setsockopt(bfd, SOL_SOCKET, SO_BROADCAST, &one, sizeof one) < 0)
+ fatal(errno, "error setting SO_BROADCAST on broadcast socket");
+ info("broadcasting on %s (%s)", sockname, ifs[n].ifr_name);
+ } else
+ info("unicasting on %s", sockname);
+ }
len = sizeof sndbuf;
if(getsockopt(bfd, SOL_SOCKET, SO_SNDBUF,
&sndbuf, &len) < 0)
/* Select an SSRC */
gcry_randomize(&rtp_id, sizeof rtp_id, GCRY_STRONG_RANDOM);
info("selected network backend, sending to %s", sockname);
- if(config->sample_format.byte_format != AO_FMT_BIG) {
- info("forcing big-endian sample format");
- config->sample_format.byte_format = AO_FMT_BIG;
- }
}
/** @brief Play over the network */