Skip to content

Commit

Permalink
Merge pull request #2 from kubo/scream-pulse-set-nic-name
Browse files Browse the repository at this point in the history
Add an option to set network interface name.
  • Loading branch information
duncanthrax committed Feb 4, 2017
2 parents e50649b + ac26647 commit 59affa0
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 3 deletions.
5 changes: 3 additions & 2 deletions Receivers/pulseaudio/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
CC=gcc
CFLAGS = -Wall

scream-pulse:
$(CC) -o scream-pulse scream-pulse.c -lpulse-simple -lpulse
scream-pulse: scream-pulse.c
$(CC) $(CFLAGS) -o scream-pulse scream-pulse.c -lpulse-simple -lpulse
28 changes: 28 additions & 0 deletions Receivers/pulseaudio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# scream-pulse

scream-pulse is a scream receiver using pulseaudio as audio output.

## Compile

You need pulseaudio headers in advance.

```shell
$ sudo yum install pulseaudio-libs-devel # Redhat, CentOS, etc.
or
$ sudo apt-get install libpulse-dev # Debian, Ubuntu, etc.
```

Run `make` command.

## Usage

```shell
$ scream-pulse
```

If your machine has more than one network interface, you may need to
set the interface name which receives scream packets.

```shell
$ scream-pulse -i eth0
```
69 changes: 68 additions & 1 deletion Receivers/pulseaudio/scream-pulse.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,67 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pulse/simple.h>
#include <pulse/error.h>

#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MULTICAST_TARGET "239.255.77.77"
#define MULTICAST_PORT 4010
#define MAX_SO_PACKETSIZE 1764
#define MIN_PA_PACKETSIZE MAX_SO_PACKETSIZE
#define BUFFER_SIZE MIN_PA_PACKETSIZE * 2

static void show_usage(const char *arg0)
{
fprintf(stderr, "Usage: %s [-i interface_name_or_address]\n",
arg0);
exit(1);
}

static in_addr_t get_interface(const char *name)
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
struct ifreq ifr;
in_addr_t addr = inet_addr(name);
struct if_nameindex *ni;
int i;

if (addr != INADDR_NONE) {
return addr;
}

if (strlen(name) >= sizeof(ifr.ifr_name)) {
fprintf(stderr, "Too long interface name: %s\n\n", name);
goto error_exit;
}
strcpy(ifr.ifr_name, name);

sockfd = socket(AF_INET,SOCK_DGRAM,0);
if (ioctl(sockfd, SIOCGIFADDR, &ifr) != 0) {
fprintf(stderr, "Invalid interface: %s\n\n", name);
goto error_exit;
}
close(sockfd);
return ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr;

error_exit:
ni = if_nameindex();
fprintf(stderr, "Available interfaces:\n");
for (i = 0; ni[i].if_name != NULL; i++) {
strcpy(ifr.ifr_name, ni[i].if_name);
if (ioctl(sockfd, SIOCGIFADDR, &ifr) == 0) {
fprintf(stderr, " %-10s (%s)\n", ni[i].if_name, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
}
}
exit(1);
}

int main(int argc, char*argv[]) {
int sockfd, error;
ssize_t n;
Expand All @@ -21,6 +71,22 @@ int main(int argc, char*argv[]) {
pa_simple *s;
pa_sample_spec ss;
unsigned char buf[BUFFER_SIZE];
in_addr_t interface = INADDR_ANY;
int opt;

while ((opt = getopt(argc, argv, "i:")) != -1) {
switch (opt) {
case 'i':
interface = get_interface(optarg);
break;
default:
show_usage(argv[0]);
}
}
if (optind < argc) {
fprintf(stderr, "Expected argument after options\n");
show_usage(argv[0]);
}

ss.format = PA_SAMPLE_S16NE;
ss.channels = 2;
Expand All @@ -46,7 +112,7 @@ int main(int argc, char*argv[]) {
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

imreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_TARGET);
imreq.imr_interface.s_addr = INADDR_ANY;
imreq.imr_interface.s_addr = interface;

setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&imreq, sizeof(struct ip_mreq));
Expand All @@ -68,4 +134,5 @@ int main(int argc, char*argv[]) {

BAIL:
if (s) pa_simple_free(s);
return 0;
};

0 comments on commit 59affa0

Please sign in to comment.