mirror of
http://www.pogo.org.uk/~mark/trx.git
synced 2025-07-02 05:22:04 +02:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0c5ab0dfc1 | ||
![]() |
5c844e6996 | ||
![]() |
69b6537303 | ||
![]() |
85fe843d61 | ||
![]() |
66b4707a24 | ||
![]() |
e375ceef5a | ||
![]() |
0b53299941 | ||
![]() |
f35eb4efe2 | ||
![]() |
14927fbaa9 | ||
![]() |
e1682f4dd6 | ||
![]() |
b53aa73137 | ||
![]() |
374308b810 | ||
![]() |
591a498725 | ||
![]() |
b7ac96036d | ||
![]() |
ad80d6b1c1 | ||
![]() |
f84c7e0726 | ||
![]() |
1d4c64dd9f | ||
![]() |
55d398c46c | ||
![]() |
a7904a4e08 |
2
README
2
README
@ -1,6 +1,6 @@
|
|||||||
trx: Realtime audio over IP
|
trx: Realtime audio over IP
|
||||||
|
|
||||||
(C) Copyright 2012 Mark Hills <mark@xwax.org>
|
(C) Copyright 2020 Mark Hills <mark@xwax.org>
|
||||||
|
|
||||||
See the COPYING file for licensing terms.
|
See the COPYING file for licensing terms.
|
||||||
|
|
||||||
|
10
device.c
10
device.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -53,7 +53,7 @@ int set_alsa_hw(snd_pcm_t *pcm,
|
|||||||
r = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
|
r = snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
CHK("snd_pcm_hw_params_set_access", r);
|
CHK("snd_pcm_hw_params_set_access", r);
|
||||||
|
|
||||||
r = snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_FLOAT);
|
r = snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_S16);
|
||||||
CHK("snd_pcm_hw_params_set_format", r);
|
CHK("snd_pcm_hw_params_set_format", r);
|
||||||
|
|
||||||
r = snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
|
r = snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
|
||||||
@ -62,9 +62,9 @@ int set_alsa_hw(snd_pcm_t *pcm,
|
|||||||
r = snd_pcm_hw_params_set_channels(pcm, hw, channels);
|
r = snd_pcm_hw_params_set_channels(pcm, hw, channels);
|
||||||
CHK("snd_pcm_hw_params_set_channels", r);
|
CHK("snd_pcm_hw_params_set_channels", r);
|
||||||
|
|
||||||
dir = 0;
|
dir = -1;
|
||||||
r = snd_pcm_hw_params_set_buffer_time_max(pcm, hw, &buffer, &dir);
|
r = snd_pcm_hw_params_set_buffer_time_near(pcm, hw, &buffer, &dir);
|
||||||
CHK("snd_pcm_hw_params_set_buffer_time_max", r);
|
CHK("snd_pcm_hw_params_set_buffer_time_near", r);
|
||||||
|
|
||||||
r = snd_pcm_hw_params(pcm, hw);
|
r = snd_pcm_hw_params(pcm, hw);
|
||||||
CHK("hw_params", r);
|
CHK("hw_params", r);
|
||||||
|
2
device.h
2
device.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
2
notice.h
2
notice.h
@ -1,6 +1,6 @@
|
|||||||
#ifndef NOTICE_H
|
#ifndef NOTICE_H
|
||||||
#define NOTICE_H
|
#define NOTICE_H
|
||||||
|
|
||||||
#define COPYRIGHT "trx (C) Copyright 2012 Mark Hills <mark@xwax.org>"
|
#define COPYRIGHT "trx (C) Copyright 2020 Mark Hills <mark@xwax.org>"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
56
rx.c
56
rx.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -32,26 +32,43 @@
|
|||||||
|
|
||||||
static unsigned int verbose = DEFAULT_VERBOSE;
|
static unsigned int verbose = DEFAULT_VERBOSE;
|
||||||
|
|
||||||
|
static void timestamp_jump(RtpSession *session, void *a, void *b, void *c)
|
||||||
|
{
|
||||||
|
if (verbose > 1)
|
||||||
|
fputc('|', stderr);
|
||||||
|
rtp_session_resync(session);
|
||||||
|
}
|
||||||
|
|
||||||
static RtpSession* create_rtp_recv(const char *addr_desc, const int port,
|
static RtpSession* create_rtp_recv(const char *addr_desc, const int port,
|
||||||
unsigned int jitter)
|
unsigned int jitter)
|
||||||
{
|
{
|
||||||
RtpSession *session;
|
RtpSession *session;
|
||||||
|
|
||||||
session = rtp_session_new(RTP_SESSION_RECVONLY);
|
session = rtp_session_new(RTP_SESSION_RECVONLY);
|
||||||
rtp_session_set_scheduling_mode(session, 0);
|
rtp_session_set_scheduling_mode(session, FALSE);
|
||||||
rtp_session_set_blocking_mode(session, 0);
|
rtp_session_set_blocking_mode(session, FALSE);
|
||||||
rtp_session_set_local_addr(session, addr_desc, port);
|
rtp_session_set_local_addr(session, addr_desc, port, -1);
|
||||||
rtp_session_set_connected_mode(session, FALSE);
|
rtp_session_set_connected_mode(session, FALSE);
|
||||||
rtp_session_enable_adaptive_jitter_compensation(session, TRUE);
|
rtp_session_enable_adaptive_jitter_compensation(session, TRUE);
|
||||||
rtp_session_set_jitter_compensation(session, jitter); /* ms */
|
rtp_session_set_jitter_compensation(session, jitter); /* ms */
|
||||||
|
rtp_session_set_time_jump_limit(session, jitter * 16); /* ms */
|
||||||
if (rtp_session_set_payload_type(session, 0) != 0)
|
if (rtp_session_set_payload_type(session, 0) != 0)
|
||||||
abort();
|
abort();
|
||||||
if (rtp_session_signal_connect(session, "timestamp_jump",
|
if (rtp_session_signal_connect(session, "timestamp_jump",
|
||||||
(RtpCallback)rtp_session_resync, 0) != 0)
|
timestamp_jump, 0) != 0)
|
||||||
{
|
{
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* oRTP in RECVONLY mode attempts to send RTCP packets and
|
||||||
|
* segfaults (v4.3.0 tested)
|
||||||
|
*
|
||||||
|
* https://stackoverflow.com/questions/43591690/receiving-rtcp-issues-within-ortp-library
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtp_session_enable_rtcp(session, FALSE);
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,15 +79,15 @@ static int play_one_frame(void *packet,
|
|||||||
const unsigned int channels)
|
const unsigned int channels)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
float *pcm;
|
int16_t *pcm;
|
||||||
snd_pcm_sframes_t f, samples = 1920;
|
snd_pcm_sframes_t f, samples = 1920;
|
||||||
|
|
||||||
pcm = alloca(sizeof(float) * samples * channels);
|
pcm = alloca(sizeof(*pcm) * samples * channels);
|
||||||
|
|
||||||
if (packet == NULL) {
|
if (packet == NULL) {
|
||||||
r = opus_decode_float(decoder, NULL, 0, pcm, samples, 1);
|
r = opus_decode(decoder, NULL, 0, pcm, samples, 1);
|
||||||
} else {
|
} else {
|
||||||
r = opus_decode_float(decoder, packet, len, pcm, samples, 0);
|
r = opus_decode(decoder, packet, len, pcm, samples, 0);
|
||||||
}
|
}
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
fprintf(stderr, "opus_decode: %s\n", opus_strerror(r));
|
fprintf(stderr, "opus_decode: %s\n", opus_strerror(r));
|
||||||
@ -78,10 +95,14 @@ static int play_one_frame(void *packet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
f = snd_pcm_writei(snd, pcm, r);
|
f = snd_pcm_writei(snd, pcm, r);
|
||||||
|
if (f < 0) {
|
||||||
|
f = snd_pcm_recover(snd, f, 0);
|
||||||
if (f < 0) {
|
if (f < 0) {
|
||||||
aerror("snd_pcm_writei", f);
|
aerror("snd_pcm_writei", f);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (f < r)
|
if (f < r)
|
||||||
fprintf(stderr, "Short write %ld\n", f);
|
fprintf(stderr, "Short write %ld\n", f);
|
||||||
|
|
||||||
@ -119,10 +140,9 @@ static int run_rx(RtpSession *session,
|
|||||||
if (r == -1)
|
if (r == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Follow the RFC, 48kHz is reference rate for
|
/* Follow the RFC, payload 0 has 8kHz reference rate */
|
||||||
* timestamps */
|
|
||||||
|
|
||||||
ts += r * 48000 / rate;
|
ts += r * 8000 / rate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,9 +171,10 @@ static void usage(FILE *fd)
|
|||||||
fprintf(fd, " -c <n> Number of channels (default %d)\n",
|
fprintf(fd, " -c <n> Number of channels (default %d)\n",
|
||||||
DEFAULT_CHANNELS);
|
DEFAULT_CHANNELS);
|
||||||
|
|
||||||
fprintf(fd, "\nDisplay parameters:\n");
|
fprintf(fd, "\nProgram parameters:\n");
|
||||||
fprintf(fd, " -v <n> Verbosity level (default %d)\n",
|
fprintf(fd, " -v <n> Verbosity level (default %d)\n",
|
||||||
DEFAULT_VERBOSE);
|
DEFAULT_VERBOSE);
|
||||||
|
fprintf(fd, " -D <file> Run as a daemon, writing process ID to the given file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
@ -165,7 +186,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* command-line options */
|
/* command-line options */
|
||||||
const char *device = DEFAULT_DEVICE,
|
const char *device = DEFAULT_DEVICE,
|
||||||
*addr = DEFAULT_ADDR;
|
*addr = DEFAULT_ADDR,
|
||||||
|
*pid = NULL;
|
||||||
unsigned int buffer = DEFAULT_BUFFER,
|
unsigned int buffer = DEFAULT_BUFFER,
|
||||||
rate = DEFAULT_RATE,
|
rate = DEFAULT_RATE,
|
||||||
jitter = DEFAULT_JITTER,
|
jitter = DEFAULT_JITTER,
|
||||||
@ -205,6 +227,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'v':
|
case 'v':
|
||||||
verbose = atoi(optarg);
|
verbose = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
pid = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(stderr);
|
usage(stderr);
|
||||||
return -1;
|
return -1;
|
||||||
@ -233,6 +258,9 @@ int main(int argc, char *argv[])
|
|||||||
if (set_alsa_sw(snd) == -1)
|
if (set_alsa_sw(snd) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (pid)
|
||||||
|
go_daemon(pid);
|
||||||
|
|
||||||
go_realtime();
|
go_realtime();
|
||||||
r = run_rx(session, decoder, snd, channels, rate);
|
r = run_rx(session, decoder, snd, channels, rate);
|
||||||
|
|
||||||
|
48
sched.c
48
sched.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -17,8 +17,11 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
|
|
||||||
@ -27,23 +30,48 @@
|
|||||||
int go_realtime(void)
|
int go_realtime(void)
|
||||||
{
|
{
|
||||||
int max_pri;
|
int max_pri;
|
||||||
struct sched_param sp;
|
const struct sched_param sp = {
|
||||||
|
.sched_priority = REALTIME_PRIORITY,
|
||||||
if (sched_getparam(0, &sp)) {
|
};
|
||||||
perror("sched_getparam");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_pri = sched_get_priority_max(SCHED_FIFO);
|
max_pri = sched_get_priority_max(SCHED_FIFO);
|
||||||
sp.sched_priority = REALTIME_PRIORITY;
|
|
||||||
|
|
||||||
if (sp.sched_priority > max_pri) {
|
if (sp.sched_priority > max_pri) {
|
||||||
fprintf(stderr, "Invalid priority (maximum %d)\n", max_pri);
|
fprintf(stderr, "Invalid priority (maximum %d)\n", max_pri);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sched_setscheduler(0, SCHED_FIFO, &sp)) {
|
errno = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp);
|
||||||
perror("sched_setscheduler");
|
if (errno) {
|
||||||
|
perror("pthread_setschedparam");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int go_daemon(const char *pid_file)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (daemon(0, 0) == -1) {
|
||||||
|
perror("daemon");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pid_file)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
f = fopen(pid_file, "w");
|
||||||
|
if (!f) {
|
||||||
|
perror("fopen");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "%d", getpid());
|
||||||
|
|
||||||
|
if (fclose(f) != 0) {
|
||||||
|
perror("fclose");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
sched.h
3
sched.h
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -21,5 +21,6 @@
|
|||||||
#define MISC_H
|
#define MISC_H
|
||||||
|
|
||||||
int go_realtime(void);
|
int go_realtime(void);
|
||||||
|
int go_daemon(const char *pid_file);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
48
tx.c
48
tx.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 Mark Hills <mark@xwax.org>
|
* Copyright (C) 2020 Mark Hills <mark@xwax.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
@ -48,6 +48,8 @@ static RtpSession* create_rtp_send(const char *addr_desc, const int port)
|
|||||||
abort();
|
abort();
|
||||||
if (rtp_session_set_multicast_ttl(session, 16) != 0)
|
if (rtp_session_set_multicast_ttl(session, 16) != 0)
|
||||||
abort();
|
abort();
|
||||||
|
if (rtp_session_set_dscp(session, 40) != 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@ -60,24 +62,38 @@ static int send_one_frame(snd_pcm_t *snd,
|
|||||||
const unsigned int ts_per_frame,
|
const unsigned int ts_per_frame,
|
||||||
RtpSession *session)
|
RtpSession *session)
|
||||||
{
|
{
|
||||||
float *pcm;
|
int16_t *pcm;
|
||||||
void *packet;
|
void *packet;
|
||||||
ssize_t z;
|
ssize_t z;
|
||||||
snd_pcm_sframes_t f;
|
snd_pcm_sframes_t f;
|
||||||
static unsigned int ts = 0;
|
static unsigned int ts = 0;
|
||||||
|
|
||||||
pcm = alloca(sizeof(float) * samples * channels);
|
pcm = alloca(sizeof(*pcm) * samples * channels);
|
||||||
packet = alloca(bytes_per_frame);
|
packet = alloca(bytes_per_frame);
|
||||||
|
|
||||||
f = snd_pcm_readi(snd, pcm, samples);
|
f = snd_pcm_readi(snd, pcm, samples);
|
||||||
|
if (f < 0) {
|
||||||
|
if (f == -ESTRPIPE)
|
||||||
|
ts = 0;
|
||||||
|
|
||||||
|
f = snd_pcm_recover(snd, f, 0);
|
||||||
if (f < 0) {
|
if (f < 0) {
|
||||||
aerror("snd_pcm_readi", f);
|
aerror("snd_pcm_readi", f);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (f < samples)
|
return 0;
|
||||||
fprintf(stderr, "Short read, %ld\n", f);
|
}
|
||||||
|
|
||||||
z = opus_encode_float(encoder, pcm, samples, packet, bytes_per_frame);
|
/* Opus encoder requires a complete frame, so if we xrun
|
||||||
|
* mid-frame then we discard the incomplete audio. The next
|
||||||
|
* read will catch the error condition and recover */
|
||||||
|
|
||||||
|
if (f < samples) {
|
||||||
|
fprintf(stderr, "Short read, %ld\n", f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
z = opus_encode(encoder, pcm, samples, packet, bytes_per_frame);
|
||||||
if (z < 0) {
|
if (z < 0) {
|
||||||
fprintf(stderr, "opus_encode_float: %s\n", opus_strerror(z));
|
fprintf(stderr, "opus_encode_float: %s\n", opus_strerror(z));
|
||||||
return -1;
|
return -1;
|
||||||
@ -138,9 +154,10 @@ static void usage(FILE *fd)
|
|||||||
fprintf(fd, " -b <kbps> Bitrate (approx., default %d)\n",
|
fprintf(fd, " -b <kbps> Bitrate (approx., default %d)\n",
|
||||||
DEFAULT_BITRATE);
|
DEFAULT_BITRATE);
|
||||||
|
|
||||||
fprintf(fd, "\nDisplay parameters:\n");
|
fprintf(fd, "\nProgram parameters:\n");
|
||||||
fprintf(fd, " -v <n> Verbosity level (default %d)\n",
|
fprintf(fd, " -v <n> Verbosity level (default %d)\n",
|
||||||
DEFAULT_VERBOSE);
|
DEFAULT_VERBOSE);
|
||||||
|
fprintf(fd, " -D <file> Run as a daemon, writing process ID to the given file\n");
|
||||||
|
|
||||||
fprintf(fd, "\nAllowed frame sizes (-f) are defined by the Opus codec. For example,\n"
|
fprintf(fd, "\nAllowed frame sizes (-f) are defined by the Opus codec. For example,\n"
|
||||||
"at 48000Hz the permitted values are 120, 240, 480 or 960.\n");
|
"at 48000Hz the permitted values are 120, 240, 480 or 960.\n");
|
||||||
@ -157,7 +174,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
/* command-line options */
|
/* command-line options */
|
||||||
const char *device = DEFAULT_DEVICE,
|
const char *device = DEFAULT_DEVICE,
|
||||||
*addr = DEFAULT_ADDR;
|
*addr = DEFAULT_ADDR,
|
||||||
|
*pid = NULL;
|
||||||
unsigned int buffer = DEFAULT_BUFFER,
|
unsigned int buffer = DEFAULT_BUFFER,
|
||||||
rate = DEFAULT_RATE,
|
rate = DEFAULT_RATE,
|
||||||
channels = DEFAULT_CHANNELS,
|
channels = DEFAULT_CHANNELS,
|
||||||
@ -170,7 +188,7 @@ int main(int argc, char *argv[])
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = getopt(argc, argv, "b:c:d:f:h:m:p:r:v:");
|
c = getopt(argc, argv, "b:c:d:f:h:m:p:r:v:D:");
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -202,6 +220,9 @@ int main(int argc, char *argv[])
|
|||||||
case 'v':
|
case 'v':
|
||||||
verbose = atoi(optarg);
|
verbose = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'D':
|
||||||
|
pid = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage(stderr);
|
usage(stderr);
|
||||||
return -1;
|
return -1;
|
||||||
@ -218,14 +239,12 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
bytes_per_frame = kbps * 1024 * frame / rate / 8;
|
bytes_per_frame = kbps * 1024 * frame / rate / 8;
|
||||||
|
|
||||||
/* Follow the RFC, 48kHz is reference rate for
|
/* Follow the RFC, payload 0 has 8kHz reference rate */
|
||||||
* timestamps */
|
|
||||||
|
|
||||||
ts_per_frame = frame * 48000 / rate;
|
ts_per_frame = frame * 8000 / rate;
|
||||||
|
|
||||||
ortp_init();
|
ortp_init();
|
||||||
ortp_scheduler_init();
|
ortp_scheduler_init();
|
||||||
ortp_set_log_level_mask(ORTP_MESSAGE|ORTP_WARNING|ORTP_ERROR);
|
|
||||||
session = create_rtp_send(addr, port);
|
session = create_rtp_send(addr, port);
|
||||||
assert(session != NULL);
|
assert(session != NULL);
|
||||||
|
|
||||||
@ -239,6 +258,9 @@ int main(int argc, char *argv[])
|
|||||||
if (set_alsa_sw(snd) == -1)
|
if (set_alsa_sw(snd) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (pid)
|
||||||
|
go_daemon(pid);
|
||||||
|
|
||||||
go_realtime();
|
go_realtime();
|
||||||
r = run_tx(snd, channels, frame, encoder, bytes_per_frame,
|
r = run_tx(snd, channels, frame, encoder, bytes_per_frame,
|
||||||
ts_per_frame, session);
|
ts_per_frame, session);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user