diff --git a/src/audio/audio.c b/src/audio/audio.c index 9bcb9ef10..dfd3f1e47 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -121,7 +121,8 @@ typedef void (*audio_device_help_t)(void); static void *audio_sender_thread(void *arg); static void *audio_receiver_thread(void *arg); static struct rtp *initialize_audio_network(char *addr, int recv_port, - int send_port, struct pdb *participants, bool use_ipv6); + int send_port, struct pdb *participants, bool use_ipv6, + char *mcast_if); static void audio_channel_map_usage(void); static void audio_scale_usage(void); @@ -159,7 +160,7 @@ static void audio_scale_usage(void) */ struct state_audio * audio_cfg_init(char *addrs, int recv_port, int send_port, char *send_cfg, char *recv_cfg, char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale, - bool echo_cancellation, bool use_ipv6) + bool echo_cancellation, bool use_ipv6, char *mcast_if) { struct state_audio *s = NULL; char *tmp, *unused = NULL; @@ -227,8 +228,8 @@ struct state_audio * audio_cfg_init(char *addrs, int recv_port, int send_port, c addr = strtok_r(tmp, ",", &unused); if ((s->audio_network_device = initialize_audio_network(addr, recv_port, send_port, - s->audio_participants, use_ipv6)) == - NULL) { + s->audio_participants, use_ipv6, mcast_if)) + == NULL) { printf("Unable to open audio network\n"); goto error; } @@ -344,13 +345,15 @@ void audio_done(struct state_audio *s) } static struct rtp *initialize_audio_network(char *addr, int recv_port, - int send_port, struct pdb *participants, bool use_ipv6) // GiX + int send_port, struct pdb *participants, bool use_ipv6, + char *mcast_if) // GiX { struct rtp *r; double rtcp_bw = 1024 * 512; // FIXME: something about 5% for rtcp is said in rfc - r = rtp_init(addr, recv_port, send_port, 255, rtcp_bw, FALSE, rtp_recv_callback, - (void *)participants, use_ipv6); + r = rtp_init_if(addr, mcast_if, recv_port, send_port, 255, rtcp_bw, + FALSE, rtp_recv_callback, (void *)participants, + use_ipv6); if (r != NULL) { pdb_add(participants, rtp_my_ssrc(r)); rtp_set_option(r, RTP_OPT_WEAK_VALIDATION, TRUE); diff --git a/src/audio/audio.h b/src/audio/audio.h index 0c34896b0..062905954 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -72,7 +72,7 @@ audio_frame; struct state_audio * audio_cfg_init(char *addrs, int recv_port, int send_port, char *send_cfg, char *recv_cfg, char *jack_cfg, char *fec_cfg, char *audio_channel_map, const char *audio_scale, - bool echo_cancellation, bool use_ipv6); + bool echo_cancellation, bool use_ipv6, char *mcast_iface); void audio_finish(struct state_audio *s); void audio_done(struct state_audio *s); void audio_join(struct state_audio *s); diff --git a/src/config_unix.h b/src/config_unix.h index d823f1398..ddfd336da 100644 --- a/src/config_unix.h +++ b/src/config_unix.h @@ -127,6 +127,7 @@ #include #include #include +#include #include #include #include diff --git a/src/main.c b/src/main.c index 0b745d027..170fdf579 100644 --- a/src/main.c +++ b/src/main.c @@ -106,6 +106,7 @@ #define AUDIO_SCALE (('a' << 8) | 's') #define ECHO_CANCELLATION (('E' << 8) | 'C') #define CUDA_DEVICE (('C' << 8) | 'D') +#define MCAST_IF (('M' << 8) | 'I') #ifdef HAVE_MACOSX #define INITIAL_VIDEO_RECV_BUFFER_SIZE 5944320 @@ -175,7 +176,8 @@ static struct state_uv *uv_state; // prototypes // static struct rtp **initialize_network(char *addrs, int recv_port_base, - int send_port_base, struct pdb *participants, bool use_ipv6); + int send_port_base, struct pdb *participants, bool use_ipv6, + char *mcast_if); void list_video_display_devices(void); void list_video_capture_devices(void); @@ -228,9 +230,9 @@ static void usage(void) printf("\nUsage: uv [-d ] [-t ] [-r ]\n"); printf(" [-s ] [-l ] " "[-m ] [-c] [-i] [-6]\n"); - printf(" [-M ] [-p ] " - "[-f ] [-P ]\n"); - printf(" address(es)\n\n"); + printf(" [-m ] [-p ] " + "[-f ] [-p ]\n"); + printf(" [--mcast-if ] address(es)\n\n"); printf ("\t-d \tselect display device, use '-d help'\n"); printf("\t \tto get list of supported devices\n"); @@ -247,6 +249,8 @@ static void usage(void) printf("\t-6 \tUse IPv6\n"); printf("\n"); #endif // HAVE_IPv6 + printf("\t--mcast-if \tBind to specified interface for multicast\n"); + printf("\n"); printf("\t-r \tAudio playback device (see '-r help')\n"); printf("\n"); printf("\t-s \tAudio capture device (see '-s help')\n"); @@ -414,7 +418,8 @@ static void display_buf_increase_warning(int size) } static struct rtp **initialize_network(char *addrs, int recv_port_base, - int send_port_base, struct pdb *participants, bool use_ipv6) + int send_port_base, struct pdb *participants, bool use_ipv6, + char *mcast_if) { struct rtp **devices = NULL; double rtcp_bw = 5 * 1024 * 1024; /* FIXME */ @@ -451,9 +456,10 @@ static struct rtp **initialize_network(char *addrs, int recv_port_base, if (send_port == send_port_base + 2) send_port += 2; - devices[index] = rtp_init(addr, recv_port, send_port, ttl, rtcp_bw, - FALSE, rtp_recv_callback, - (void *)participants, use_ipv6); + devices[index] = rtp_init_if(addr, mcast_if, recv_port, + send_port, ttl, rtcp_bw, FALSE, + rtp_recv_callback, (void *)participants, + use_ipv6); if (devices[index] != NULL) { rtp_set_option(devices[index], RTP_OPT_WEAK_VALIDATION, TRUE); @@ -861,6 +867,7 @@ int main(int argc, char *argv[]) bool echo_cancellation = false; bool use_ipv6 = false; + char *mcast_if = NULL; int bitrate = 0; @@ -906,6 +913,7 @@ int main(int argc, char *argv[]) {"audio-capture-channels", required_argument, 0, AUDIO_CAPTURE_CHANNELS}, {"echo-cancellation", no_argument, 0, ECHO_CANCELLATION}, {"cuda-device", required_argument, 0, CUDA_DEVICE}, + {"mcast-if", required_argument, 0, MCAST_IF}, {0, 0, 0, 0} }; int option_index = 0; @@ -1058,6 +1066,9 @@ int main(int argc, char *argv[]) fprintf(stderr, "CUDA support is not enabled!\n"); return EXIT_FAIL_USAGE; #endif // HAVE_CUDA + case MCAST_IF: + mcast_if = optarg; + break; default: usage(); return EXIT_FAIL_USAGE; @@ -1104,8 +1115,10 @@ int main(int argc, char *argv[]) } char *tmp_requested_fec = strdup(DEFAULT_AUDIO_FEC); - uv->audio = audio_cfg_init (network_device, uv->recv_port_number + 2, uv->send_port_number + 2, audio_send, audio_recv, jack_cfg, - tmp_requested_fec, audio_channel_map, audio_scale, echo_cancellation, use_ipv6); + uv->audio = audio_cfg_init (network_device, uv->recv_port_number + 2, + uv->send_port_number + 2, audio_send, audio_recv, + jack_cfg, tmp_requested_fec, audio_channel_map, + audio_scale, echo_cancellation, use_ipv6, mcast_if); free(tmp_requested_fec); if(!uv->audio) goto cleanup; @@ -1226,7 +1239,7 @@ int main(int argc, char *argv[]) } else { if ((uv->network_devices = initialize_network(network_device, uv->recv_port_number, - uv->send_port_number, uv->participants, use_ipv6)) + uv->send_port_number, uv->participants, use_ipv6, mcast_if)) == NULL) { printf("Unable to open network\n"); exit_uv(EXIT_FAIL_NETWORK); diff --git a/src/rtp/net_udp.c b/src/rtp/net_udp.c index cfcb372ac..eb153e69b 100644 --- a/src/rtp/net_udp.c +++ b/src/rtp/net_udp.c @@ -271,7 +271,7 @@ static socket_udp *udp_init4(const char *addr, const char *iface, int reuse = 1; int udpbufsize = 16 * 1024 * 1024; struct sockaddr_in s_in; - struct in_addr iface_addr; + unsigned int ifindex; socket_udp *s = (socket_udp *) malloc(sizeof(socket_udp)); s->mode = IPv4; s->addr = NULL; @@ -288,13 +288,13 @@ static socket_udp *udp_init4(const char *addr, const char *iface, memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4)); } if (iface != NULL) { - if (inet_pton(AF_INET, iface, &iface_addr) != 1) { + if ((ifindex = if_nametoindex(iface)) == 0) { debug_msg("Illegal interface specification\n"); free(s); return NULL; } } else { - iface_addr.s_addr = 0; + ifindex = 0; } s->fd = socket(AF_INET, SOCK_DGRAM, 0); if (s->fd < 0) { @@ -337,7 +337,7 @@ static socket_udp *udp_init4(const char *addr, const char *iface, struct ip_mreq imr; imr.imr_multiaddr.s_addr = s->addr4.s_addr; - imr.imr_interface.s_addr = iface_addr.s_addr; + imr.imr_interface.s_addr = ifindex; if (SETSOCKOPT (s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&imr, @@ -359,13 +359,11 @@ static socket_udp *udp_init4(const char *addr, const char *iface, socket_error("setsockopt IP_MULTICAST_TTL"); return NULL; } - if (iface_addr.s_addr != 0) { - if (SETSOCKOPT - (s->fd, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&iface_addr, sizeof(iface_addr)) != 0) { - socket_error("setsockopt IP_MULTICAST_IF"); - return NULL; - } + if (SETSOCKOPT + (s->fd, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&ifindex, sizeof(ifindex)) != 0) { + socket_error("setsockopt IP_MULTICAST_IF"); + return NULL; } } s->addr = strdup(addr); @@ -541,11 +539,17 @@ static socket_udp *udp_init6(const char *addr, const char *iface, s->tx_port = tx_port; s->ttl = ttl; struct addrinfo hints, *res0; + unsigned int ifindex; int err; if (iface != NULL) { - debug_msg("Not yet implemented\n"); - abort(); + if ((ifindex = if_nametoindex(iface)) == 0) { + debug_msg("Illegal interface specification\n"); + free(s); + return NULL; + } + } else { + ifindex = 0; } memset(&hints, 0, sizeof(hints)); @@ -607,7 +611,7 @@ static socket_udp *udp_init6(const char *addr, const char *iface, imr.i6mr_multiaddr = s->addr6; #else imr.ipv6mr_multiaddr = s->addr6; - imr.ipv6mr_interface = 0; + imr.ipv6mr_interface = ifindex; #endif if (SETSOCKOPT @@ -629,6 +633,11 @@ static socket_udp *udp_init6(const char *addr, const char *iface, socket_error("setsockopt IPV6_MULTICAST_HOPS"); return NULL; } + if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *)&ifindex, sizeof(ifindex)) != 0) { + socket_error("setsockopt IPV6_MULTICAST_IF"); + return NULL; + } } assert(s != NULL); @@ -722,7 +731,8 @@ static const char *udp_host_addr6(socket_udp * s) int gai_err, newsock; struct addrinfo hints, *ai; struct sockaddr_in6 local, addr6; - int len = sizeof(local), result = 0; + socklen_t len = sizeof(local); + int result = 0; newsock = socket(AF_INET6, SOCK_DGRAM, 0); memset((char *)&addr6, 0, len);