From d2be2e03ebdfe9ec91b9b4b7e5419a8ef7975b44 Mon Sep 17 00:00:00 2001 From: Mark Hills Date: Fri, 11 Sep 2009 16:40:27 +0100 Subject: [PATCH] trx based on libortp --- Makefile | 13 +-- defaults.h | 10 +- jitter.c | 130 -------------------------- jitter.h | 34 ------- rx.c | 251 ++++++++++++++++++++++---------------------------- test-jitter.c | 34 ------- tx.c | 172 +++++++++++++++------------------- 7 files changed, 198 insertions(+), 446 deletions(-) delete mode 100644 jitter.c delete mode 100644 jitter.h delete mode 100644 test-jitter.c diff --git a/Makefile b/Makefile index 8447902..d9c89eb 100644 --- a/Makefile +++ b/Makefile @@ -2,23 +2,24 @@ CFLAGS+=-MMD -Wall +LDLIBS_ASOUND?=-lasound +LDLIBS_CELT?=-lcelt +LDLIBS_ORTP?=-lortp + +LDLIBS+=$(LDLIBS_ASOUND) $(LDLIBS_CELT) $(LDLIBS_ORTP) + .PHONY: all clean all: rx tx -rx: rx.o device.o jitter.o sched.o -rx: LDLIBS+=-lcelt -lasound +rx: rx.o device.o sched.o tx: tx.o device.o sched.o -tx: LDLIBS+=-lcelt -lasound - -test-jitter: test-jitter.o jitter.o clean: rm -f *.o rm -f *.d rm -f tx rm -f rx - rm -f test-jitter -include *.d diff --git a/defaults.h b/defaults.h index 1785e85..90426ee 100644 --- a/defaults.h +++ b/defaults.h @@ -4,11 +4,15 @@ #define DEFAULT_DEVICE "default" #define DEFAULT_BUFFER 16 -#define DEFAULT_SERVICE "1350" -#define DEFAULT_FRAME 128 +#define DEFAULT_ADDR "0.0.0.0" +#define DEFAULT_PORT 1350 +#define DEFAULT_FRAME 256 +#define DEFAULT_JITTER 16 -#define DEFAULT_RATE 44100 +#define DEFAULT_RATE 48000 #define DEFAULT_CHANNELS 2 #define DEFAULT_BITRATE 128 +#define DEFAULT_VERBOSE 1 + #endif diff --git a/jitter.c b/jitter.c deleted file mode 100644 index e9dea1d..0000000 --- a/jitter.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include - -#include "jitter.h" - -void jitbuf_init(struct jitbuf_t *jb) -{ - size_t n; - - for (n = 0; n < JITBUF_MAX; n++) - jb->buf[n] = NULL; - - jb->base = 0; - jb->out = 0; - jb->entries = 0; -} - -void jitbuf_clear(struct jitbuf_t *jb) -{ -} - -/* - * Push an entry into the buffer, with the given sequence number - * - * Pre: data is not NULL - */ - -int jitbuf_push(struct jitbuf_t *jb, seq_t t, void *data) -{ - void **entry; - - assert(data != NULL); - - if (jb->entries == 0 && t != jb->base) { - fprintf(stderr, "Restarting (%d)\n", t); - jb->base = t; - } else { - if (t < jb->base) { - fprintf(stderr, "Late (%d)\n", t); - return -1; - } - if (t >= jb->base + JITBUF_MAX) { - fprintf(stderr, "Early (%d)\n", t); - return -1; - } - } - - entry = &jb->buf[(t - jb->base + jb->out) % JITBUF_MAX]; - - if (*entry != NULL) { - fprintf(stderr, "Dup (%d)\n", t); - return -1; - } - - *entry = data; - jb->entries++; - - return 0; -} - -/* - * Get the entry at the front of the buffer, in sequence number order - * - * Return: NULL if no entry, otherwise entry next in sequence - */ - -void* jitbuf_front(const struct jitbuf_t *jb) -{ - return jb->buf[jb->out]; -} - -/* - * Pop the next entry in the buffer - */ - -void jitbuf_pop(struct jitbuf_t *jb) -{ - void **entry; - - entry = &jb->buf[jb->out]; - if (*entry != NULL) { - jb->entries--; - *entry = NULL; - } - jb->base++; - jb->out++; - if (jb->out >= JITBUF_MAX) - jb->out = 0; -} - -/* - * Return true if this buffer has enough data flow to be declared ready - */ - -bool jitbuf_ready(const struct jitbuf_t *jb, seq_t count) -{ - size_t n; - - assert(count <= JITBUF_MAX); - - for (n = 0; n < count; n++) { - if (jb->buf[(jb->out + n) % JITBUF_MAX] == NULL) - return false; - } - return true; -} - -bool jitbuf_empty(const struct jitbuf_t *jb) -{ - if (jb->entries > 0) - return false; - else - return true; -} - -void jitbuf_debug(struct jitbuf_t *jb, FILE *fd) -{ - seq_t n; - - fprintf(fd, "% 3d ", jb->entries); - - for (n = 0; n < JITBUF_MAX; n++) { - if (jb->buf[(jb->out + n) % JITBUF_MAX] != NULL) { - fputc('#', fd); - } else { - fputc(' ', fd); - } - } - fputc('\n', fd); -} diff --git a/jitter.h b/jitter.h deleted file mode 100644 index a42cd1a..0000000 --- a/jitter.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef JITTER_H -#define JITTER_H - -#include -#include -#include - -#define JITBUF_MAX 64 - -typedef unsigned int seq_t; - -/* - * De-jitter buffer - */ - -struct jitbuf_t { - seq_t base; - size_t out, entries, contiguous; - void *buf[JITBUF_MAX]; -}; - -void jitbuf_init(struct jitbuf_t *jb); -void jitbuf_clear(struct jitbuf_t *jb); - -int jitbuf_push(struct jitbuf_t *jb, seq_t t, void *data); -void* jitbuf_front(const struct jitbuf_t *jb); -void jitbuf_pop(struct jitbuf_t *jb); - -bool jitbuf_ready(const struct jitbuf_t *jb, seq_t count); -bool jitbuf_empty(const struct jitbuf_t *jb); - -void jitbuf_debug(struct jitbuf_t *jb, FILE *fd); - -#endif diff --git a/rx.c b/rx.c index 38e395d..e3e2e3a 100644 --- a/rx.c +++ b/rx.c @@ -2,168 +2,106 @@ #include #include #include +#include #include #include #include "defaults.h" #include "device.h" -#include "jitter.h" #include "sched.h" -#define ENCODED_BYTES 71 +static unsigned int verbose = DEFAULT_VERBOSE; -/* - * Bind to a network socket for receiving packets on the given port - */ - -static int listen_on_network(const char *service) +static RtpSession* create_rtp_recv(const char *addr_desc, const int port, + unsigned int jitter) { - int r, sd; - struct addrinfo hints, *servinfo, *p; + RtpSession *session; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; /* use my IP */ - - r = getaddrinfo(NULL, service, &hints, &servinfo); - if (r != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r)); - return -1; + session = rtp_session_new(RTP_SESSION_RECVONLY); + rtp_session_set_scheduling_mode(session, 0); + rtp_session_set_blocking_mode(session, 0); + rtp_session_set_local_addr(session, addr_desc, port); + rtp_session_set_connected_mode(session, FALSE); + rtp_session_enable_adaptive_jitter_compensation(session, TRUE); + rtp_session_set_jitter_compensation(session, jitter); /* ms */ + if (rtp_session_set_payload_type(session, 0) != 0) + abort(); + if (rtp_session_signal_connect(session, "timestamp_jump", + (RtpCallback)rtp_session_resync, 0) != 0) + { + abort(); } - /* Bind to the first one we can */ - - for (p = servinfo; p != NULL; p = p->ai_next) { - sd = socket(p->ai_family, p->ai_socktype | SOCK_NONBLOCK, - p->ai_protocol); - if (sd == -1) { - perror("socket"); - continue; - } - - if (bind(sd, p->ai_addr, p->ai_addrlen) == -1) { - if (close(sd) == -1) - abort(); - perror("bind"); - continue; - } - - break; - } - - freeaddrinfo(servinfo); - - if (p == NULL) { - fputs("Failed to bind socket\n", stderr); - return -1; - } else { - return sd; - } + return session; } -/* - * Playback audio from the buffer to the audio device - */ - -static int play_audio(struct jitbuf_t *jb, CELTDecoder *decoder, - snd_pcm_t *snd) +static int play_one_frame(void *packet, + size_t len, + CELTDecoder *decoder, + snd_pcm_t *snd, + const unsigned int channels, + const snd_pcm_uframes_t samples) { int r; - void *data; float *pcm; snd_pcm_sframes_t f; - pcm = alloca(sizeof(float) * DEFAULT_FRAME * DEFAULT_CHANNELS); + pcm = alloca(sizeof(float) * samples * channels); - data = jitbuf_front(jb); - if (data == NULL) { + if (packet == NULL) { r = celt_decode_float(decoder, NULL, 0, pcm); } else { - r = celt_decode_float(decoder, data, ENCODED_BYTES, pcm); + r = celt_decode_float(decoder, packet, len, pcm); } if (r != 0) { fputs("Error in celt_decode\n", stderr); return -1; } - f = snd_pcm_writei(snd, pcm, DEFAULT_FRAME); + f = snd_pcm_writei(snd, pcm, samples); if (f < 0) { aerror("snd_pcm_writei", f); return -1; } - if (f < DEFAULT_FRAME) + if (f < samples) fprintf(stderr, "Short write %ld\n", f); - jitbuf_pop(jb); - free(data); - return 0; } -/* - * Read from the network into the buffer - */ - -static int read_from_network(int sd, struct jitbuf_t *jb) +static int run_rx(RtpSession *session, + CELTDecoder *decoder, + snd_pcm_t *snd, + const unsigned int channels, + const snd_pcm_uframes_t frame) { - size_t z; - char buf[32768]; - void *data; - seq_t seq; - - z = recvfrom(sd, buf, sizeof(buf), 0, NULL, NULL); - if (z == -1) { - if (errno == EAGAIN) - return -EAGAIN; - perror("recvfrom"); - return -1; - } - if (z != sizeof(uint32_t) + ENCODED_BYTES) { - fputs("small packet", stderr); - return -1; - } - - /* First 32-bits is sequence number, rest is data */ - seq = ntohl(*(uint32_t*)buf); - z -= sizeof(uint32_t); - assert(z >= 0); - data = malloc(z); - memcpy(data, buf + sizeof(uint32_t), z); - - if (jitbuf_push(jb, seq, data) == -1) - free(data); - - return 0; -} - -/* - * The main loop of receiving audio and playing it back - */ - -static int run_rx(int sd, CELTDecoder *decoder, snd_pcm_t *snd) -{ - int r; - struct jitbuf_t jb; - - jitbuf_init(&jb); + int ts = 0; for (;;) { - for (;;) { - r = read_from_network(sd, &jb); - if (r == -EAGAIN) - break; - if (r != 0) - return -1; + int r, have_more; + char buf[32768]; + void *packet; + + r = rtp_session_recv_with_ts(session, buf, + sizeof(buf), ts, &have_more); + assert(r >= 0); + assert(have_more == 0); + if (r == 0) { + packet = NULL; + if (verbose > 1) + fputc('#', stderr); + } else { + packet = buf; + if (verbose > 1) + fputc('.', stderr); } - //jitbuf_debug(&jb, stderr); - - if (play_audio(&jb, decoder, snd) == -1) + r = play_one_frame(packet, r, decoder, snd, channels, frame); + if (r == -1) return -1; - } - jitbuf_clear(&jb); + ts += frame; + } } static void usage(FILE *fd) @@ -171,32 +109,54 @@ static void usage(FILE *fd) fprintf(fd, "Usage: rx []\n"); fprintf(fd, "\nAudio device (ALSA) parameters:\n"); - fprintf(fd, " -d Device name (default '%s')\n", + fprintf(fd, " -d Device name (default '%s')\n", DEFAULT_DEVICE); - fprintf(fd, " -m Buffer time (milliseconds, default %d)\n", + fprintf(fd, " -m Buffer time (milliseconds, default %d)\n", DEFAULT_BUFFER); fprintf(fd, "\nNetwork parameters:\n"); - fprintf(fd, " -p UDP port number or name (default %s)\n", - DEFAULT_SERVICE); + fprintf(fd, " -h IP address to listen on (default %s)\n", + DEFAULT_ADDR); + fprintf(fd, " -p UDP port number (default %d)\n", + DEFAULT_PORT); + fprintf(fd, " -j Jitter buffer (milliseconds, default %d)\n", + DEFAULT_JITTER); + + fprintf(fd, "\nEncoding parameters (must match sender):\n"); + fprintf(fd, " -r Sample rate (default %d)\n", + DEFAULT_RATE); + fprintf(fd, " -c Number of channels (default %d)\n", + DEFAULT_CHANNELS); + fprintf(fd, " -f Frame size (default %d)\n", + DEFAULT_FRAME); + + fprintf(fd, "\nDisplay parameters:\n"); + fprintf(fd, " -v Verbosity level (default %d)\n", + DEFAULT_VERBOSE); } int main(int argc, char *argv[]) { - int sd, r; + int r; snd_pcm_t *snd; CELTMode *mode; CELTDecoder *decoder; + RtpSession *session; /* command-line options */ const char *device = DEFAULT_DEVICE, - *service = DEFAULT_SERVICE; - unsigned int buffer = DEFAULT_BUFFER; + *addr = DEFAULT_ADDR; + unsigned int buffer = DEFAULT_BUFFER, + rate = DEFAULT_RATE, + frame = DEFAULT_FRAME, + jitter = DEFAULT_JITTER, + channels = DEFAULT_CHANNELS, + port = DEFAULT_PORT; for (;;) { int c; - c = getopt(argc, argv, "d:m:p:"); + c = getopt(argc, argv, "d:h:j:m:p:v:"); if (c == -1) break; @@ -204,11 +164,20 @@ int main(int argc, char *argv[]) case 'd': device = optarg; break; + case 'h': + addr = optarg; + break; + case 'j': + jitter = atoi(optarg); + break; case 'm': buffer = atoi(optarg); break; case 'p': - service = optarg; + port = atoi(optarg); + break; + case 'v': + verbose = atoi(optarg); break; default: usage(stderr); @@ -216,8 +185,7 @@ int main(int argc, char *argv[]) } } - mode = celt_mode_create(DEFAULT_RATE, DEFAULT_CHANNELS, DEFAULT_FRAME, - NULL); + mode = celt_mode_create(rate, channels, frame, NULL); if (mode == NULL) { fputs("celt_mode_create failed\n", stderr); return -1; @@ -228,36 +196,35 @@ int main(int argc, char *argv[]) return -1; } - sd = listen_on_network(service); - if (sd == -1) + if (go_realtime() != 0) return -1; + ortp_init(); + ortp_scheduler_init(); + session = create_rtp_recv(addr, port, jitter); + assert(session != NULL); + r = snd_pcm_open(&snd, device, SND_PCM_STREAM_PLAYBACK, 0); if (r < 0) { aerror("snd_pcm_open", r); return -1; } - if (set_alsa_hw(snd, DEFAULT_RATE, DEFAULT_CHANNELS, - buffer * 1000) == -1) - { + if (set_alsa_hw(snd, rate, channels, buffer * 1000) == -1) return -1; - } if (set_alsa_sw(snd) == -1) return -1; - if (go_realtime() != 0) - return -1; - - r = run_rx(sd, decoder, snd); + r = run_rx(session, decoder, snd, channels, frame); if (snd_pcm_close(snd) < 0) abort(); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + celt_decoder_destroy(decoder); celt_mode_destroy(mode); - if (close(sd) == -1) - abort(); - return r; } diff --git a/test-jitter.c b/test-jitter.c deleted file mode 100644 index ab4adc4..0000000 --- a/test-jitter.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include - -#include "jitter.h" - -int main(int argc, char *argv[]) -{ - int n; - struct jitbuf_t jb; - const char *test = "abcdefghijklmnopqrstuvwxyz1234567890"; - - jitbuf_init(&jb); - - for (n = 0; n < strlen(test); n++) { - int m; - char *out; - size_t pos; - - out = jitbuf_front(&jb); - if (out != NULL) - fputc(*out, stdout); - else - fputc('#', stdout); - jitbuf_pop(&jb); - - for (m = 0; m < 8; m++) { - pos = n + rand() % (strlen(test) - n); - jitbuf_push(&jb, pos, (void*)&test[pos]); - } - } - fputc('\n', stdout); - - jitbuf_clear(&jb); -} diff --git a/tx.c b/tx.c index c178fc2..fe2a61a 100644 --- a/tx.c +++ b/tx.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,162 +10,139 @@ #include "device.h" #include "sched.h" -typedef unsigned int seq_t; +static unsigned int verbose = DEFAULT_VERBOSE; -/* - * Bind to network socket, for sending to the given host and port - */ - -static int bind_to_network(const char *host, const char *service, - struct addrinfo **servinfo, struct addrinfo **theirs) +static RtpSession* create_rtp_send(const char *addr_desc, const int port) { - int r, sd; - struct addrinfo hints, *p; + RtpSession *session; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; + session = rtp_session_new(RTP_SESSION_SENDONLY); + assert(session != NULL); - r = getaddrinfo(host, service, &hints, servinfo); - if (r != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(r)); - return -1; - } + rtp_session_set_scheduling_mode(session, 0); + rtp_session_set_blocking_mode(session, 0); + rtp_session_set_connected_mode(session, FALSE); + if (rtp_session_set_remote_addr(session, addr_desc, port) != 0) + abort(); + if (rtp_session_set_payload_type(session, 0) != 0) + abort(); + if (rtp_session_set_multicast_ttl(session, 16) != 0) + abort(); - for (p = *servinfo; p != NULL; p = p->ai_next) { - sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (sd == -1) { - perror("socket"); - continue; - } - break; - } - - if (p == NULL) { - fputs("Failed to bind socket\n", stderr); - return -1; - } else { - *theirs = p; - return sd; - } + return session; } -/* - * Encode a frame of audio and send it over the network - */ - -static int send_audio(snd_pcm_t *snd, - const snd_pcm_uframes_t samples, +static int send_one_frame(snd_pcm_t *snd, const unsigned int channels, + const snd_pcm_uframes_t samples, CELTEncoder *encoder, const size_t bytes_per_frame, - int sd, struct addrinfo *theirs, seq_t *seq) + RtpSession *session) { float *pcm; - void *packet, *encoded; + void *packet; ssize_t z; snd_pcm_sframes_t f; + static int ts = 0; pcm = alloca(sizeof(float) * samples * channels); - packet = alloca(bytes_per_frame + sizeof(uint32_t)); - encoded = packet + sizeof(uint32_t); + packet = alloca(bytes_per_frame); f = snd_pcm_readi(snd, pcm, samples); if (f < 0) { aerror("snd_pcm_readi", f); return -1; } - if (f < DEFAULT_FRAME) + if (f < samples) fprintf(stderr, "Short read, %ld\n", f); - z = celt_encode_float(encoder, pcm, NULL, encoded, bytes_per_frame); + z = celt_encode_float(encoder, pcm, NULL, packet, bytes_per_frame); if (z < 0) { fputs("celt_encode_float failed\n", stderr); return -1; } - *(uint32_t*)packet = htonl(*seq); - (*seq)++; - - z = sendto(sd, packet, sizeof(uint32_t) + bytes_per_frame, 0, - theirs->ai_addr, theirs->ai_addrlen); - if (z == -1) { - perror("sendto"); - return -1; - } - //fputc('>', stderr); + rtp_session_send_with_ts(session, packet, z, ts); + ts += samples; return 0; } static int run_tx(snd_pcm_t *snd, - const snd_pcm_uframes_t samples, const unsigned int channels, + const snd_pcm_uframes_t frame, CELTEncoder *encoder, const size_t bytes_per_frame, - int sd, struct addrinfo *theirs) + RtpSession *session) { - seq_t seq = 0; - for (;;) { int r; - r = send_audio(snd, samples, channels, + r = send_one_frame(snd, channels, frame, encoder, bytes_per_frame, - sd, theirs, &seq); + session); if (r == -1) return -1; + + if (verbose > 1) + fputc('>', stderr); } } static void usage(FILE *fd) { - fprintf(fd, "Usage: tx [] \n"); + fprintf(fd, "Usage: tx []\n"); fprintf(fd, "\nAudio device (ALSA) parameters:\n"); - fprintf(fd, " -d Device name (default '%s')\n", + fprintf(fd, " -d Device name (default '%s')\n", DEFAULT_DEVICE); - fprintf(fd, " -m Buffer time (milliseconds, default %d)\n", + fprintf(fd, " -m Buffer time (milliseconds, default %d)\n", DEFAULT_BUFFER); fprintf(fd, "\nNetwork parameters:\n"); - fprintf(fd, " -p UDP port number or name (default %s)\n", - DEFAULT_SERVICE); - fprintf(fd, " -f Frame size (default %d)\n", - DEFAULT_FRAME); + fprintf(fd, " -h IP address to send to (default %s)\n", + DEFAULT_ADDR); + fprintf(fd, " -p UDP port number (default %d)\n", + DEFAULT_PORT); fprintf(fd, "\nEncoding parameters:\n"); - fprintf(fd, " -r Sample rate (default %d)\n", + fprintf(fd, " -r Sample rate (default %d)\n", DEFAULT_RATE); - fprintf(fd, " -c Number of channels (default %d)\n", + fprintf(fd, " -c Number of channels (default %d)\n", DEFAULT_CHANNELS); - fprintf(fd, " -b Bitrate (kbps, approx., default %d)\n", + fprintf(fd, " -f Frame size (default %d)\n", + DEFAULT_FRAME); + fprintf(fd, " -b Bitrate (approx., default %d)\n", DEFAULT_BITRATE); + + fprintf(fd, "\nDisplay parameters:\n"); + fprintf(fd, " -v Verbosity level (default %d)\n", + DEFAULT_VERBOSE); } int main(int argc, char *argv[]) { - int sd, r; - struct addrinfo *servinfo, *theirs; + int r; + size_t bytes_per_frame; snd_pcm_t *snd; CELTMode *mode; CELTEncoder *encoder; - size_t bytes_per_frame; + RtpSession *session; /* command-line options */ const char *device = DEFAULT_DEVICE, - *service = DEFAULT_SERVICE, - *host; + *addr = DEFAULT_ADDR; unsigned int buffer = DEFAULT_BUFFER, rate = DEFAULT_RATE, channels = DEFAULT_CHANNELS, frame = DEFAULT_FRAME, - kbps = DEFAULT_BITRATE; + kbps = DEFAULT_BITRATE, + port = DEFAULT_PORT; for (;;) { int c; - c = getopt(argc, argv, "b:c:d:f:m:p:r:"); + c = getopt(argc, argv, "b:c:d:f:h:m:p:r:v:"); if (c == -1) break; @@ -181,28 +159,27 @@ int main(int argc, char *argv[]) case 'f': frame = atol(optarg); break; + case 'h': + addr = optarg; + break; case 'm': buffer = atoi(optarg); break; case 'p': - service = optarg; + port = atoi(optarg); break; case 'r': rate = atoi(optarg); break; + case 'v': + verbose = atoi(optarg); + break; default: usage(stderr); return -1; } } - if (argv[optind] == NULL) { - usage(stderr); - return -1; - } - - host = argv[optind]; - mode = celt_mode_create(rate, channels, frame, NULL); if (mode == NULL) { fputs("celt_mode_create failed\n", stderr); @@ -216,10 +193,15 @@ int main(int argc, char *argv[]) bytes_per_frame = kbps * 1024 * frame / rate / 8; fprintf(stderr, "bytes_per_frame = %d\n", bytes_per_frame); - sd = bind_to_network(host, service, &servinfo, &theirs); - if (sd == -1) + if (go_realtime() != 0) return -1; + ortp_init(); + ortp_scheduler_init(); + ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR); + session = create_rtp_send(addr, port); + assert(session != NULL); + r = snd_pcm_open(&snd, device, SND_PCM_STREAM_CAPTURE, 0); if (r < 0) { aerror("snd_pcm_open", r); @@ -230,21 +212,17 @@ int main(int argc, char *argv[]) if (set_alsa_sw(snd) == -1) return -1; - if (go_realtime() != 0) - return -1; - - r = run_tx(snd, frame, channels, encoder, bytes_per_frame, sd, theirs); - - freeaddrinfo(servinfo); + r = run_tx(snd, channels, frame, encoder, bytes_per_frame, session); if (snd_pcm_close(snd) < 0) abort(); + rtp_session_destroy(session); + ortp_exit(); + ortp_global_stats_display(); + celt_encoder_destroy(encoder); celt_mode_destroy(mode); - if (close(sd) == -1) - abort(); - return r; }