summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/account.c3
-rw-r--r--src/audio.c212
-rw-r--r--src/call.c27
-rw-r--r--src/conf.c18
-rw-r--r--src/config.c78
-rw-r--r--src/core.h75
-rw-r--r--src/event.c10
-rw-r--r--src/h264.c36
-rw-r--r--src/log.c71
-rw-r--r--src/main.c4
-rw-r--r--src/metric.c4
-rw-r--r--src/reg.c5
-rw-r--r--src/srcs.mk3
-rw-r--r--src/stream.c11
-rw-r--r--src/timer.c71
-rw-r--r--src/timestamp.c65
-rw-r--r--src/ua.c30
-rw-r--r--src/video.c177
-rw-r--r--src/vidisp.c7
-rw-r--r--src/vidsrc.c7
-rw-r--r--src/vidutil.c65
21 files changed, 754 insertions, 225 deletions
diff --git a/src/account.c b/src/account.c
index 2a99e58..d7ab9c0 100644
--- a/src/account.c
+++ b/src/account.c
@@ -388,6 +388,9 @@ int account_alloc(struct account **accp, const char *sipaddr)
/* optional password prompt */
if (pl_isset(&acc->laddr.uri.password)) {
+ warning("account: username:password is now deprecated"
+ " please use ;auth_pass=xxx instead\n");
+
err = re_sdprintf(&acc->auth_pass, "%H",
uri_password_unescape,
&acc->laddr.uri.password);
diff --git a/src/audio.c b/src/audio.c
index 17eb5f6..b2b3cca 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -81,23 +81,24 @@ struct autx {
struct auenc_state *enc; /**< Audio encoder state (optional) */
struct aubuf *aubuf; /**< Packetize outgoing stream */
size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */
- volatile bool aubuf_started;
+ volatile bool aubuf_started; /**< Aubuf was started flag */
struct auresamp resamp; /**< Optional resampler for DSP */
struct list filtl; /**< Audio filters in encoding order */
struct mbuf *mb; /**< Buffer for outgoing RTP packets */
char device[64]; /**< Audio source device name */
- int16_t *sampv; /**< Sample buffer */
+ void *sampv; /**< Sample buffer */
int16_t *sampv_rs; /**< Sample buffer for resampler */
uint32_t ptime; /**< Packet time for sending */
uint64_t ts_ext; /**< Ext. Timestamp for outgoing RTP */
- uint32_t ts_base;
+ uint32_t ts_base; /**< First timestamp sent */
uint32_t ts_tel; /**< Timestamp for Telephony Events */
size_t psize; /**< Packet size for sending */
bool marker; /**< Marker bit for outgoing RTP */
bool muted; /**< Audio source is muted */
int cur_key; /**< Currently transmitted event */
- enum aufmt src_fmt;
- bool need_conv;
+ enum aufmt src_fmt; /**< Sample format for audio source */
+ enum aufmt enc_fmt; /**< Sample format for encoder */
+ bool need_conv; /**< Sample format conversion needed */
struct {
uint64_t aubuf_overrun;
@@ -137,24 +138,25 @@ struct aurx {
struct audec_state *dec; /**< Audio decoder state (optional) */
struct aubuf *aubuf; /**< Incoming audio buffer */
size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */
- volatile bool aubuf_started;
+ volatile bool aubuf_started; /**< Aubuf was started flag */
struct auresamp resamp; /**< Optional resampler for DSP */
struct list filtl; /**< Audio filters in decoding order */
char device[64]; /**< Audio player device name */
- int16_t *sampv; /**< Sample buffer */
+ void *sampv; /**< Sample buffer */
int16_t *sampv_rs; /**< Sample buffer for resampler */
uint32_t ptime; /**< Packet time for receiving */
int pt; /**< Payload type for incoming RTP */
double level_last;
bool level_set;
- enum aufmt play_fmt;
- bool need_conv;
- struct timestamp_recv ts_recv;
- uint64_t n_discard;
+ enum aufmt play_fmt; /**< Sample format for audio playback*/
+ enum aufmt dec_fmt; /**< Sample format for decoder */
+ bool need_conv; /**< Sample format conversion needed */
+ struct timestamp_recv ts_recv;/**< Receive timestamp state */
struct {
uint64_t aubuf_overrun;
uint64_t aubuf_underrun;
+ uint64_t n_discard;
} stats;
};
@@ -309,7 +311,7 @@ static inline double calc_ptime(size_t nsamp, uint32_t srate, uint8_t channels)
/**
- * Get the DSP samplerate for an audio-codec (exception for G.722 and MPA)
+ * Get the DSP samplerate for an audio-codec
*/
static inline uint32_t get_srate(const struct aucodec *ac)
{
@@ -448,7 +450,9 @@ static void encode_rtp_send(struct audio *a, struct autx *tx,
len = mbuf_get_space(tx->mb);
- err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, sampv, sampc);
+ err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len,
+ tx->enc_fmt, sampv, sampc);
+
if ((err & 0xffff0000) == 0x00010000) {
/* MPA needs some special treatment here */
tx->ts_ext = err & 0xffff;
@@ -514,11 +518,12 @@ static void poll_aubuf_tx(struct audio *a)
/* timed read from audio-buffer */
- if (tx->src_fmt == AUFMT_S16LE) {
+ if (tx->src_fmt == tx->enc_fmt) {
aubuf_read(tx->aubuf, (uint8_t *)tx->sampv, num_bytes);
}
- else {
+ else if (tx->enc_fmt == AUFMT_S16LE) {
+
/* Convert from ausrc format to 16-bit format */
void *tmp_sampv;
@@ -540,11 +545,23 @@ static void poll_aubuf_tx(struct audio *a)
mem_deref(tmp_sampv);
}
+ else {
+ warning("audio: tx: invalid sample formats (%s -> %s)\n",
+ aufmt_name(tx->src_fmt),
+ aufmt_name(tx->enc_fmt));
+ }
/* optional resampler */
if (tx->resamp.resample) {
size_t sampc_rs = AUDIO_SAMPSZ;
+ if (tx->enc_fmt != AUFMT_S16LE) {
+ warning("audio: skipping resampler due to"
+ " incompatible format (%s)\n",
+ aufmt_name(tx->enc_fmt));
+ return;
+ }
+
err = auresamp(&tx->resamp,
tx->sampv_rs, &sampc_rs,
tx->sampv, sampc);
@@ -555,15 +572,23 @@ static void poll_aubuf_tx(struct audio *a)
sampc = sampc_rs;
}
- /* Process exactly one audio-frame in list order */
- for (le = tx->filtl.head; le; le = le->next) {
- struct aufilt_enc_st *st = le->data;
+ if (tx->enc_fmt == AUFMT_S16LE) {
+
+ /* Process exactly one audio-frame in list order */
+ for (le = tx->filtl.head; le; le = le->next) {
+ struct aufilt_enc_st *st = le->data;
- if (st->af && st->af->ench)
- err |= st->af->ench(st, sampv, &sampc);
+ if (st->af && st->af->ench)
+ err |= st->af->ench(st, sampv, &sampc);
+ }
+ if (err) {
+ warning("audio: aufilter encode: %m\n", err);
+ }
}
- if (err) {
- warning("audio: aufilter encode: %m\n", err);
+ else if (!list_isempty(&tx->filtl)) {
+ warning("audio: skipping audio-filters due to"
+ " incompatible format (%s)\n",
+ aufmt_name(tx->enc_fmt));
}
/* Encode and send */
@@ -623,8 +648,10 @@ static void auplay_write_handler(void *sampv, size_t sampc, void *arg)
++rx->stats.aubuf_underrun;
+#if 0
debug("audio: rx aubuf underrun (total %llu)\n",
rx->stats.aubuf_underrun);
+#endif
}
aubuf_read(rx->aubuf, sampv, num_bytes);
@@ -726,7 +753,7 @@ static void handle_telev(struct audio *a, struct mbuf *mb)
static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
{
size_t sampc = AUDIO_SAMPSZ;
- int16_t *sampv;
+ void *sampv;
struct le *le;
int err = 0;
@@ -735,13 +762,16 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
return 0;
if (mbuf_get_left(mb)) {
- err = rx->ac->dech(rx->dec, rx->sampv, &sampc,
+
+ err = rx->ac->dech(rx->dec,
+ rx->dec_fmt, rx->sampv, &sampc,
mbuf_buf(mb), mbuf_get_left(mb));
+
}
- else if (rx->ac->plch) {
+ else if (rx->ac->plch && rx->dec_fmt == AUFMT_S16LE) {
sampc = rx->ac->srate * rx->ac->ch * rx->ptime / 1000;
- err = rx->ac->plch(rx->dec, rx->sampv, &sampc);
+ err = rx->ac->plch(rx->dec, rx->dec_fmt, rx->sampv, &sampc);
}
else {
/* no PLC in the codec, might be done in filters below */
@@ -754,12 +784,19 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
goto out;
}
- /* Process exactly one audio-frame in reverse list order */
- for (le = rx->filtl.tail; le; le = le->prev) {
- struct aufilt_dec_st *st = le->data;
+ if (rx->dec_fmt == AUFMT_S16LE) {
+ /* Process exactly one audio-frame in reverse list order */
+ for (le = rx->filtl.tail; le; le = le->prev) {
+ struct aufilt_dec_st *st = le->data;
- if (st->af && st->af->dech)
- err |= st->af->dech(st, rx->sampv, &sampc);
+ if (st->af && st->af->dech)
+ err |= st->af->dech(st, rx->sampv, &sampc);
+ }
+ }
+ else if (!list_isempty(&rx->filtl)) {
+ warning("audio: skipping audio-filters due to"
+ " incompatible format (%s)\n",
+ aufmt_name(rx->dec_fmt));
}
if (!rx->aubuf)
@@ -771,6 +808,13 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
if (rx->resamp.resample) {
size_t sampc_rs = AUDIO_SAMPSZ;
+ if (rx->dec_fmt != AUFMT_S16LE) {
+ warning("audio: skipping resampler due to"
+ " incompatible format (%s)\n",
+ aufmt_name(rx->dec_fmt));
+ return ENOTSUP;
+ }
+
err = auresamp(&rx->resamp,
rx->sampv_rs, &sampc_rs,
rx->sampv, sampc);
@@ -789,15 +833,17 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
rx->stats.aubuf_overrun);
}
- if (rx->play_fmt == AUFMT_S16LE) {
- err = aubuf_write_samp(rx->aubuf, sampv, sampc);
+ if (rx->play_fmt == rx->dec_fmt) {
+
+ size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt);
+
+ err = aubuf_write(rx->aubuf, sampv, num_bytes);
if (err)
goto out;
}
- else {
+ else if (rx->dec_fmt == AUFMT_S16LE) {
/* Convert from 16-bit to auplay format */
-
void *tmp_sampv;
size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt);
@@ -822,6 +868,11 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
if (err)
goto out;
}
+ else {
+ warning("audio: decode: invalid sample formats (%s -> %s)\n",
+ aufmt_name(rx->dec_fmt),
+ aufmt_name(rx->play_fmt));
+ }
rx->aubuf_started = true;
@@ -945,7 +996,7 @@ static void stream_recv_handler(const struct rtp_header *hdr,
#endif
if (discard) {
- ++a->rx.n_discard;
+ ++rx->stats.n_discard;
return;
}
@@ -1057,6 +1108,9 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm,
tx->src_fmt = cfg->audio.src_fmt;
rx->play_fmt = cfg->audio.play_fmt;
+ tx->enc_fmt = cfg->audio.enc_fmt;
+ rx->dec_fmt = cfg->audio.dec_fmt;
+
err = stream_alloc(&a->strm, stream_prm, &cfg->avt, call, sdp_sess,
"audio", label,
mnat, mnat_sess, menc, menc_sess,
@@ -1101,8 +1155,11 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm,
}
tx->mb = mbuf_alloc(STREAM_PRESZ + 4096);
- tx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL);
- rx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL);
+ tx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(tx->enc_fmt),
+ NULL);
+
+ rx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(rx->dec_fmt),
+ NULL);
if (!tx->mb || !tx->sampv || !rx->sampv) {
err = ENOMEM;
goto out;
@@ -1480,6 +1537,10 @@ static int start_source(struct autx *tx, struct audio *a)
}
switch (a->cfg.txmode) {
+
+ case AUDIO_MODE_POLL:
+ break;
+
#ifdef HAVE_PTHREAD
case AUDIO_MODE_THREAD:
if (!tx->u.thr.run) {
@@ -1495,7 +1556,9 @@ static int start_source(struct autx *tx, struct audio *a)
#endif
default:
- break;
+ warning("audio: tx mode not supported (%d)\n",
+ a->cfg.txmode);
+ return ENOTSUP;
}
tx->ausrc_prm = prm;
@@ -1602,6 +1665,7 @@ int audio_encoder_set(struct audio *a, const struct aucodec *ac,
struct auenc_param prm;
prm.ptime = tx->ptime;
+ prm.bitrate = 0; /* auto */
err = ac->encupdh(&tx->enc, ac, &prm, params);
if (err) {
@@ -1891,9 +1955,10 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
err = re_hprintf(pf, "\n--- Audio stream ---\n");
- err |= re_hprintf(pf, " tx: %H ptime=%ums\n",
+ err |= re_hprintf(pf, " tx: encode: %H ptime=%ums %s\n",
aucodec_print, tx->ac,
- tx->ptime);
+ tx->ptime,
+ aufmt_name(tx->enc_fmt));
err |= re_hprintf(pf, " aubuf: %H"
" (cur %.2fms, max %.2fms, or %llu, ur %llu)\n",
aubuf_debug, tx->aubuf,
@@ -1905,14 +1970,15 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
tx->ausrc_prm.ch),
tx->stats.aubuf_overrun,
tx->stats.aubuf_underrun);
-
+ err |= re_hprintf(pf, " source: %s\n",
+ aufmt_name(tx->src_fmt));
err |= re_hprintf(pf, " time = %.3f sec\n",
autx_calc_seconds(tx));
err |= re_hprintf(pf,
- " rx: %H\n"
+ " rx: decode: %H %s\n"
" ptime=%ums pt=%d\n",
- aucodec_print, rx->ac,
+ aucodec_print, rx->ac, aufmt_name(rx->dec_fmt),
rx->ptime, rx->pt);
err |= re_hprintf(pf, " aubuf: %H"
" (cur %.2fms, max %.2fms, or %llu, ur %llu)\n",
@@ -1926,9 +1992,9 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
rx->stats.aubuf_overrun,
rx->stats.aubuf_underrun
);
-
+ err |= re_hprintf(pf, " player: %s\n", aufmt_name(rx->play_fmt));
err |= re_hprintf(pf, " n_discard:%llu\n",
- rx->n_discard);
+ rx->stats.n_discard);
if (rx->level_set) {
err |= re_hprintf(pf, " level %.3f dBov\n",
rx->level_last);
@@ -2079,3 +2145,57 @@ int audio_print_rtpstat(struct re_printf *pf, const struct audio *a)
return err;
}
+
+
+int audio_set_bitrate(struct audio *au, uint32_t bitrate)
+{
+ struct autx *tx;
+ const struct aucodec *ac;
+ int err;
+
+ if (!au)
+ return EINVAL;
+
+ tx = &au->tx;
+
+ ac = tx->ac;
+
+ info("audio: set bitrate for encoder '%s' to %u bits/s\n",
+ ac ? ac->name : "?",
+ bitrate);
+
+ if (ac) {
+
+ if (ac->encupdh) {
+ struct auenc_param prm;
+
+ prm.ptime = tx->ptime;
+ prm.bitrate = bitrate;
+
+ err = ac->encupdh(&tx->enc, ac, &prm, NULL);
+ if (err) {
+ warning("audio: encupdh error: %m\n", err);
+ return err;
+ }
+ }
+
+ }
+ else {
+ info("audio: set_bitrate: no audio encoder\n");
+ }
+
+ return 0;
+}
+
+
+bool audio_rxaubuf_started(struct audio *au)
+{
+ struct aurx *rx;
+
+ if (!au)
+ return false;
+
+ rx = &au->rx;
+
+ return rx->aubuf_started;
+}
diff --git a/src/call.c b/src/call.c
index 99bec4b..0868f68 100644
--- a/src/call.c
+++ b/src/call.c
@@ -59,6 +59,7 @@ struct call {
char *local_name; /**< Local display name */
char *peer_uri; /**< Peer SIP Address */
char *peer_name; /**< Peer display name */
+ char *id; /**< Cached session call-id */
struct tmr tmr_inv; /**< Timer for incoming calls */
struct tmr tmr_dtmf; /**< Timer for incoming DTMF events */
time_t time_start; /**< Time when call started */
@@ -378,6 +379,7 @@ static void call_destructor(void *arg)
tmr_cancel(&call->tmr_dtmf);
mem_deref(call->sess);
+ mem_deref(call->id);
mem_deref(call->local_uri);
mem_deref(call->local_name);
mem_deref(call->peer_uri);
@@ -901,6 +903,12 @@ int call_sdp_get(const struct call *call, struct mbuf **descp, bool offer)
}
+const char *call_id(const struct call *call)
+{
+ return call ? call->id : NULL;
+}
+
+
const char *call_peeruri(const struct call *call)
{
return call ? call->peer_uri : NULL;
@@ -940,10 +948,10 @@ int call_debug(struct re_printf *pf, const struct call *call)
err |= re_hprintf(pf,
" local_uri: %s <%s>\n"
" peer_uri: %s <%s>\n"
- " af=%s\n",
+ " af=%s id=%s\n",
call->local_name, call->local_uri,
call->peer_name, call->peer_uri,
- net_af2name(call->af));
+ net_af2name(call->af), call->id);
err |= re_hprintf(pf, " direction: %s\n",
call->outgoing ? "Outgoing" : "Incoming");
@@ -994,6 +1002,9 @@ int call_status(struct re_printf *pf, const struct call *call)
err |= video_print(pf, call->video);
#endif
+ /* remove old junk */
+ err |= re_hprintf(pf, " ");
+
return err;
}
@@ -1293,6 +1304,8 @@ static void sipsess_close_handler(int err, const struct sip_msg *msg,
if (err) {
info("%s: session closed: %m\n", call->peer_uri, err);
+ (void)re_snprintf(reason, sizeof(reason), "%m", err);
+
if (call->not) {
(void)call_notify_sipfrag(call, 500, "%m", err);
}
@@ -1421,6 +1434,11 @@ int call_accept(struct call *call, struct sipsess_sock *sess_sock,
return err;
}
+ err = str_dup(&call->id,
+ sip_dialog_callid(sipsess_dialog(call->sess)));
+ if (err)
+ return err;
+
set_state(call, STATE_INCOMING);
/* New call */
@@ -1525,11 +1543,16 @@ static int send_invite(struct call *call)
ua_print_supported, call->ua);
if (err) {
warning("call: sipsess_connect: %m\n", err);
+ goto out;
}
+ err = str_dup(&call->id,
+ sip_dialog_callid(sipsess_dialog(call->sess)));
+
/* save call setup timer */
call->time_conn = time(NULL);
+ out:
mem_deref(desc);
return err;
diff --git a/src/conf.c b/src/conf.c
index 2046216..2bb7d5a 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -289,6 +289,24 @@ int conf_get_sa(const struct conf *conf, const char *name, struct sa *sa)
}
+int conf_get_float(const struct conf *conf, const char *name, double *val)
+{
+ struct pl opt;
+ int err;
+
+ if (!conf || !name || !val)
+ return EINVAL;
+
+ err = conf_get(conf, name, &opt);
+ if (err)
+ return err;
+
+ *val = pl_float(&opt);
+
+ return 0;
+}
+
+
/**
* Configure the system with default settings
*
diff --git a/src/config.c b/src/config.c
index ce748d3..6c336d9 100644
--- a/src/config.c
+++ b/src/config.c
@@ -43,7 +43,7 @@ static struct config core_config = {
/** Audio */
{
- PREFIX "/share/baresip",
+ SHARE_PATH,
"","",
"","",
"","",
@@ -58,6 +58,8 @@ static struct config core_config = {
false,
AUFMT_S16LE,
AUFMT_S16LE,
+ AUFMT_S16LE,
+ AUFMT_S16LE,
},
#ifdef USE_VIDEO
@@ -69,6 +71,7 @@ static struct config core_config = {
500000,
25,
true,
+ VID_FMT_YUV420P,
},
#endif
@@ -178,6 +181,36 @@ static int conf_get_aufmt(const struct conf *conf, const char *name,
}
+#ifdef USE_VIDEO
+static int conf_get_vidfmt(const struct conf *conf, const char *name,
+ int *fmtp)
+{
+ struct pl pl;
+ int fmt;
+ int err;
+
+ err = conf_get(conf, name, &pl);
+ if (err)
+ return err;
+
+ for (fmt=0; fmt<VID_FMT_N; fmt++) {
+
+ const char *str = vidfmt_name(fmt);
+
+ if (0 == pl_strcasecmp(&pl, str)) {
+
+ *fmtp = fmt;
+ return 0;
+ }
+ }
+
+ warning("config: %s: pixel format not supported (%r)\n", name, &pl);
+
+ return ENOENT;
+}
+#endif
+
+
/**
* Parse the core configuration file and update baresip core config
*
@@ -270,6 +303,8 @@ int config_parse_conf(struct config *cfg, const struct conf *conf)
conf_get_aufmt(conf, "ausrc_format", &cfg->audio.src_fmt);
conf_get_aufmt(conf, "auplay_format", &cfg->audio.play_fmt);
+ conf_get_aufmt(conf, "auenc_format", &cfg->audio.enc_fmt);
+ conf_get_aufmt(conf, "audec_format", &cfg->audio.dec_fmt);
#ifdef USE_VIDEO
/* Video */
@@ -284,8 +319,10 @@ int config_parse_conf(struct config *cfg, const struct conf *conf)
cfg->video.height = size.h;
}
(void)conf_get_u32(conf, "video_bitrate", &cfg->video.bitrate);
- (void)conf_get_u32(conf, "video_fps", &cfg->video.fps);
+ (void)conf_get_float(conf, "video_fps", &cfg->video.fps);
(void)conf_get_bool(conf, "video_fullscreen", &cfg->video.fullscreen);
+
+ conf_get_vidfmt(conf, "videnc_format", &cfg->video.enc_fmt);
#else
(void)size;
#endif
@@ -352,7 +389,7 @@ int config_print(struct re_printf *pf, const struct config *cfg)
"\n"
"# Call\n"
"call_local_timeout\t%u\n"
- "call_max_calls\t%u\n"
+ "call_max_calls\t\t%u\n"
"\n"
"# Audio\n"
"audio_path\t\t%s\n"
@@ -373,7 +410,9 @@ int config_print(struct re_printf *pf, const struct config *cfg)
"video_display\t\t%s,%s\n"
"video_size\t\t\"%ux%u\"\n"
"video_bitrate\t\t%u\n"
- "video_fps\t\t%u\n"
+ "video_fps\t\t%.2f\n"
+ "video_fullscreen\t%s\n"
+ "videnc_format\t\t%s\n"
"\n"
#endif
"# AVT\n"
@@ -416,6 +455,8 @@ int config_print(struct re_printf *pf, const struct config *cfg)
cfg->video.disp_mod, cfg->video.disp_dev,
cfg->video.width, cfg->video.height,
cfg->video.bitrate, cfg->video.fps,
+ cfg->video.fullscreen ? "yes" : "no",
+ vidfmt_name(cfg->video.enc_fmt),
#endif
cfg->avt.rtp_tos,
@@ -467,6 +508,8 @@ static const char *default_video_device(void)
return "avcapture,nil";
#endif
+#elif defined (WIN32)
+ return "dshow,nil";
#else
return "v4l2,/dev/video0";
#endif
@@ -477,6 +520,8 @@ static const char *default_video_display(void)
{
#ifdef DARWIN
return "opengl,nil";
+#elif defined (WIN32)
+ return "sdl2,nil";
#else
return "x11,nil";
#endif
@@ -520,10 +565,12 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"\n"
"# Call\n"
"call_local_timeout\t%u\n"
- "call_max_calls\t%u\n"
+ "call_max_calls\t\t%u\n"
"\n"
"# Audio\n"
-#if defined (PREFIX)
+#if defined (SHARE_PATH)
+ "#audio_path\t\t" SHARE_PATH "\n"
+#elif defined (PREFIX)
"#audio_path\t\t" PREFIX "/share/baresip\n"
#else
"#audio_path\t\t/usr/share/baresip\n"
@@ -541,6 +588,8 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"audio_level\t\tno\n"
"ausrc_format\t\ts16\t\t# s16, float, ..\n"
"auplay_format\t\ts16\t\t# s16, float, ..\n"
+ "auenc_format\t\ts16\t\t# s16, float, ..\n"
+ "audec_format\t\ts16\t\t# s16, float, ..\n"
,
poll_method_name(poll_method_best()),
cfg->call.local_timeout,
@@ -559,12 +608,15 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"#video_display\t\t%s\n"
"video_size\t\t%dx%d\n"
"video_bitrate\t\t%u\n"
- "video_fps\t\t%u\n"
- "video_fullscreen\tyes\n",
+ "video_fps\t\t%.2f\n"
+ "video_fullscreen\tyes\n"
+ "videnc_format\t\t%s\n"
+ ,
default_video_device(),
default_video_display(),
cfg->video.width, cfg->video.height,
- cfg->video.bitrate, cfg->video.fps);
+ cfg->video.bitrate, cfg->video.fps,
+ vidfmt_name(cfg->video.enc_fmt));
#endif
err |= re_hprintf(pf,
@@ -624,7 +676,9 @@ static uint32_t count_modules(const char *path)
static const char *detect_module_path(bool *valid)
{
static const char * const pathv[] = {
-#if defined (PREFIX)
+#if defined (MOD_PATH)
+ MOD_PATH,
+#elif defined (PREFIX)
"" PREFIX "/lib/baresip/modules",
#else
"/usr/local/lib/baresip/modules",
@@ -853,6 +907,7 @@ int config_write_template(const char *file, const struct config *cfg)
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "presence"MOD_EXT"\n");
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "syslog"MOD_EXT"\n");
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "mqtt" MOD_EXT "\n");
+ (void)re_fprintf(f, "#module_app\t\t" MOD_PRE "ctrl_tcp" MOD_EXT "\n");
#ifdef USE_VIDEO
(void)re_fprintf(f, "module_app\t\t" MOD_PRE "vidloop"MOD_EXT"\n");
#endif
@@ -870,6 +925,9 @@ int config_write_template(const char *file, const struct config *cfg)
(void)re_fprintf(f, "http_listen\t\t0.0.0.0:8000\n");
(void)re_fprintf(f, "\n");
+ (void)re_fprintf(f, "ctrl_tcp_listen\t\t0.0.0.0:4444\n");
+
+ (void)re_fprintf(f, "\n");
(void)re_fprintf(f, "evdev_device\t\t/dev/input/event0\n");
(void)re_fprintf(f, "\n# Speex codec parameters\n");
diff --git a/src/core.h b/src/core.h
index a390e0c..ca11ab8 100644
--- a/src/core.h
+++ b/src/core.h
@@ -35,7 +35,8 @@ enum {
/** Media constants */
enum {
- AUDIO_BANDWIDTH = 128000 /**< Bandwidth for audio in bits/s */
+ AUDIO_BANDWIDTH = 128000, /**< Bandwidth for audio in bits/s */
+ VIDEO_SRATE = 90000, /**< Sampling rate for video */
};
@@ -200,6 +201,7 @@ int conf_get_range(const struct conf *conf, const char *name,
struct range *rng);
int conf_get_csv(const struct conf *conf, const char *name,
char *str1, size_t sz1, char *str2, size_t sz2);
+int conf_get_float(const struct conf *conf, const char *name, double *val);
/*
@@ -249,7 +251,7 @@ struct metric {
void metric_init(struct metric *metric);
void metric_reset(struct metric *metric);
void metric_add_packet(struct metric *metric, size_t packetsize);
-uint32_t metric_avg_bitrate(const struct metric *metric);
+double metric_avg_bitrate(const struct metric *metric);
/*
@@ -376,6 +378,7 @@ struct stream {
uint64_t ts_last; /**< Timestamp of last received RTP pkt */
bool terminated; /**< Stream is terminated flag */
uint32_t rtp_timeout_ms; /**< RTP Timeout value in [ms] */
+ bool rtp_estab; /**< True if RTP stream is established */
};
int stream_alloc(struct stream **sp, const struct stream_param *prm,
@@ -419,36 +422,6 @@ const char *uag_allowed_methods(void);
/*
- * Video Display
- */
-
-struct vidisp {
- struct le le;
- const char *name;
- vidisp_alloc_h *alloch;
- vidisp_update_h *updateh;
- vidisp_disp_h *disph;
- vidisp_hide_h *hideh;
-};
-
-struct vidisp *vidisp_get(struct vidisp_st *st);
-
-
-/*
- * Video Source
- */
-
-struct vidsrc {
- struct le le;
- const char *name;
- vidsrc_alloc_h *alloch;
- vidsrc_update_h *updateh;
-};
-
-struct vidsrc *vidsrc_get(struct vidsrc_st *st);
-
-
-/*
* Video Stream
*/
@@ -503,39 +476,5 @@ static inline uint64_t calc_extended_timestamp(uint32_t num_wraps, uint32_t ts)
}
-static inline uint64_t timestamp_duration(const struct timestamp_recv *ts)
-{
- uint64_t last_ext;
-
- if (!ts || !ts->is_set)
- return 0;
-
- last_ext = calc_extended_timestamp(ts->num_wraps, ts->last);
-
- return last_ext - ts->first;
-}
-
-
-/*
- * -1 backwards wrap-around
- * 0 no wrap-around
- * 1 forward wrap-around
- */
-static inline int timestamp_wrap(uint32_t ts_new, uint32_t ts_old)
-{
- int32_t delta;
-
- if (ts_new < ts_old) {
-
- delta = (int32_t)ts_new - (int32_t)ts_old;
-
- if (delta > 0)
- return 1;
- }
- else if ((int32_t)(ts_old - ts_new) > 0) {
-
- return -1;
- }
-
- return 0;
-}
+int timestamp_wrap(uint32_t ts_new, uint32_t ts_old);
+uint64_t timestamp_duration(const struct timestamp_recv *ts);
diff --git a/src/event.c b/src/event.c
index b29ab8b..94db0d2 100644
--- a/src/event.c
+++ b/src/event.c
@@ -79,6 +79,8 @@ static int add_rtcp_stats(struct odict *od_parent, const struct rtcp_stats *rs)
out:
mem_deref(od);
+ mem_deref(tx);
+ mem_deref(rx);
return err;
}
@@ -96,7 +98,12 @@ int event_encode_dict(struct odict *od, struct ua *ua, enum ua_event ev,
err |= odict_entry_add(od, "type", ODICT_STRING, event_str);
err |= odict_entry_add(od, "class",
ODICT_STRING, event_class_name(ev));
- err |= odict_entry_add(od, "accountaor", ODICT_STRING, ua_aor(ua));
+
+ if (ua) {
+ err |= odict_entry_add(od, "accountaor",
+ ODICT_STRING, ua_aor(ua));
+ }
+
if (err)
goto out;
@@ -109,6 +116,7 @@ int event_encode_dict(struct odict *od, struct ua *ua, enum ua_event ev,
err |= odict_entry_add(od, "direction", ODICT_STRING, dir);
err |= odict_entry_add(od, "peeruri",
ODICT_STRING, call_peeruri(call));
+ err |= odict_entry_add(od, "id", ODICT_STRING, call_id(call));
if (err)
goto out;
}
diff --git a/src/h264.c b/src/h264.c
index 2bb4a26..3786559 100644
--- a/src/h264.c
+++ b/src/h264.c
@@ -104,7 +104,7 @@ const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end)
static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz,
const uint8_t *buf, size_t sz,
- bool eof, uint32_t rtp_ts,
+ bool eof, uint64_t rtp_ts,
videnc_packet_h *pkth, void *arg)
{
return pkth(eof, rtp_ts, hdr, hdr_sz, buf, sz, arg);
@@ -112,7 +112,7 @@ static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz,
int h264_nal_send(bool first, bool last,
- bool marker, uint32_t ihdr, uint32_t rtp_ts,
+ bool marker, uint32_t ihdr, uint64_t rtp_ts,
const uint8_t *buf, size_t size, size_t maxsz,
videnc_packet_h *pkth, void *arg)
{
@@ -153,7 +153,7 @@ int h264_nal_send(bool first, bool last,
}
-int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
+int h264_packetize(uint64_t rtp_ts, const uint8_t *buf, size_t len,
size_t pktsize, videnc_packet_h *pkth, void *arg)
{
const uint8_t *start = buf;
@@ -180,3 +180,33 @@ int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
return err;
}
+
+
+/**
+ * Get the name of an H.264 nal unit
+ *
+ * @param type NAL unit type
+ *
+ * @return A string containing the NAL unit name
+ */
+const char *h264_nalunit_name(int type)
+{
+ switch (type) {
+
+ case H264_NAL_SLICE: return "SLICE";
+ case H264_NAL_DPA: return "DPA";
+ case H264_NAL_DPB: return "DPB";
+ case H264_NAL_DPC: return "DPC";
+ case H264_NAL_IDR_SLICE: return "IDR_SLICE";
+ case H264_NAL_SEI: return "SEI";
+ case H264_NAL_SPS: return "SPS";
+ case H264_NAL_PPS: return "PPS";
+ case H264_NAL_AUD: return "AUD";
+ case H264_NAL_FILLER_DATA: return "FILLER";
+
+ case H264_NAL_FU_A: return "FU-A";
+ case H264_NAL_FU_B: return "FU-B";
+ }
+
+ return "???";
+}
diff --git a/src/log.c b/src/log.c
index 650689d..c9debdd 100644
--- a/src/log.c
+++ b/src/log.c
@@ -12,7 +12,7 @@ static struct {
struct list logl;
bool debug;
bool info;
- bool stder;
+ bool enable_stdout;
} lg = {
LIST_INIT,
false,
@@ -21,6 +21,11 @@ static struct {
};
+/**
+ * Register a log handler
+ *
+ * @param log Log handler
+ */
void log_register_handler(struct log *log)
{
if (!log)
@@ -30,6 +35,11 @@ void log_register_handler(struct log *log)
}
+/**
+ * Unregister a log handler
+ *
+ * @param log Log handler
+ */
void log_unregister_handler(struct log *log)
{
if (!log)
@@ -39,24 +49,46 @@ void log_unregister_handler(struct log *log)
}
+/**
+ * Enable debug-level logging
+ *
+ * @param enable True to enable, false to disable
+ */
void log_enable_debug(bool enable)
{
lg.debug = enable;
}
+/**
+ * Enable info-level logging
+ *
+ * @param enable True to enable, false to disable
+ */
void log_enable_info(bool enable)
{
lg.info = enable;
}
-void log_enable_stderr(bool enable)
+/**
+ * Enable logging to standard-out
+ *
+ * @param enable True to enable, false to disable
+ */
+void log_enable_stdout(bool enable)
{
- lg.stder = enable;
+ lg.enable_stdout = enable;
}
+/**
+ * Print a message to the logging system
+ *
+ * @param level Log level
+ * @param fmt Formatted message
+ * @param ap Variable argument list
+ */
void vlog(enum log_level level, const char *fmt, va_list ap)
{
char buf[4096];
@@ -65,7 +97,7 @@ void vlog(enum log_level level, const char *fmt, va_list ap)
if (re_vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
return;
- if (lg.stder) {
+ if (lg.enable_stdout) {
bool color = level == LEVEL_WARN || level == LEVEL_ERROR;
@@ -91,6 +123,13 @@ void vlog(enum log_level level, const char *fmt, va_list ap)
}
+/**
+ * Print a message to the logging system
+ *
+ * @param level Log level
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void loglv(enum log_level level, const char *fmt, ...)
{
va_list ap;
@@ -107,6 +146,12 @@ void loglv(enum log_level level, const char *fmt, ...)
}
+/**
+ * Print a DEBUG message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void debug(const char *fmt, ...)
{
va_list ap;
@@ -120,6 +165,12 @@ void debug(const char *fmt, ...)
}
+/**
+ * Print an INFO message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void info(const char *fmt, ...)
{
va_list ap;
@@ -133,6 +184,12 @@ void info(const char *fmt, ...)
}
+/**
+ * Print a WARNING message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void warning(const char *fmt, ...)
{
va_list ap;
@@ -143,6 +200,12 @@ void warning(const char *fmt, ...)
}
+/**
+ * Print an ERROR message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void error_msg(const char *fmt, ...)
{
va_list ap;
diff --git a/src/main.c b/src/main.c
index b789648..05742d8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -78,7 +78,7 @@ int main(int argc, char *argv[])
int err;
(void)re_fprintf(stdout, "baresip v%s"
- " Copyright (C) 2010 - 2017"
+ " Copyright (C) 2010 - 2018"
" Alfred E. Heggestad et al.\n",
BARESIP_VERSION);
@@ -227,7 +227,7 @@ int main(int argc, char *argv[])
if (err)
goto out;
- log_enable_stderr(false);
+ log_enable_stdout(false);
}
info("baresip is ready.\n");
diff --git a/src/metric.c b/src/metric.c
index f3e8d06..85dad3c 100644
--- a/src/metric.c
+++ b/src/metric.c
@@ -77,7 +77,7 @@ void metric_add_packet(struct metric *metric, size_t packetsize)
}
-uint32_t metric_avg_bitrate(const struct metric *metric)
+double metric_avg_bitrate(const struct metric *metric)
{
int diff;
@@ -86,5 +86,5 @@ uint32_t metric_avg_bitrate(const struct metric *metric)
diff = (int)(tmr_jiffies() - metric->ts_start);
- return 1000 * 8 * (metric->n_bytes / diff);
+ return 1000.0 * 8 * (double)metric->n_bytes / (double)diff;
}
diff --git a/src/reg.c b/src/reg.c
index 23bb337..7756636 100644
--- a/src/reg.c
+++ b/src/reg.c
@@ -183,6 +183,7 @@ int reg_add(struct list *lst, struct ua *ua, int regid)
int reg_register(struct reg *reg, const char *reg_uri, const char *params,
uint32_t regint, const char *outbound)
{
+ struct account *acc;
const char *routev[1];
int err;
@@ -191,10 +192,12 @@ int reg_register(struct reg *reg, const char *reg_uri, const char *params,
reg->scode = 0;
routev[0] = outbound;
+ acc = ua_account(reg->ua);
reg->sipreg = mem_deref(reg->sipreg);
err = sipreg_register(&reg->sipreg, uag_sip(), reg_uri,
- ua_aor(reg->ua), ua_aor(reg->ua),
+ ua_aor(reg->ua),
+ acc ? acc->dispname : NULL, ua_aor(reg->ua),
regint, ua_local_cuser(reg->ua),
routev[0] ? routev : NULL,
routev[0] ? 1 : 0,
diff --git a/src/srcs.mk b/src/srcs.mk
index a35e0d8..be7906c 100644
--- a/src/srcs.mk
+++ b/src/srcs.mk
@@ -34,6 +34,8 @@ SRCS += rtpkeep.c
SRCS += sdp.c
SRCS += sipreq.c
SRCS += stream.c
+SRCS += timer.c
+SRCS += timestamp.c
SRCS += ua.c
SRCS += ui.c
@@ -46,6 +48,7 @@ SRCS += vidcodec.c
SRCS += vidfilt.c
SRCS += vidisp.c
SRCS += vidsrc.c
+SRCS += vidutil.c
endif
ifneq ($(STATIC),)
diff --git a/src/stream.c b/src/stream.c
index 38db2d6..e4fb655 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -110,8 +110,8 @@ static void print_rtp_stats(const struct stream *s)
,
sdp_media_name(s->sdp),
s->metric_tx.n_packets, s->metric_rx.n_packets,
- 1.0*metric_avg_bitrate(&s->metric_tx)/1000,
- 1.0*metric_avg_bitrate(&s->metric_rx)/1000,
+ 1.0*metric_avg_bitrate(&s->metric_tx)/1000.0,
+ 1.0*metric_avg_bitrate(&s->metric_rx)/1000.0,
s->metric_tx.n_err, s->metric_rx.n_err
);
@@ -223,6 +223,13 @@ static void rtp_handler(const struct sa *src, const struct rtp_header *hdr,
metric_add_packet(&s->metric_rx, mbuf_get_left(mb));
+ if (!s->rtp_estab) {
+ info("stream: incoming rtp for '%s' established"
+ ", receiving from %J\n",
+ sdp_media_name(s->sdp), src);
+ s->rtp_estab = true;
+ }
+
if (hdr->ssrc != s->ssrc_rx) {
if (s->ssrc_rx) {
flush = true;
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..d12f650
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,71 @@
+/**
+ * @file timer.c Timer functions
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <time.h>
+#endif
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Get the timer jiffies in microseconds [us]
+ *
+ * @return Jiffies in [us]
+ */
+uint64_t tmr_jiffies_usec(void)
+{
+ uint64_t jfs;
+
+#if defined(WIN32)
+ FILETIME ft;
+ ULARGE_INTEGER li;
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ jfs = li.QuadPart/10;
+#elif defined(HAVE_CLOCK_GETTIME)
+ struct timespec now;
+ clockid_t clock_id;
+
+#if defined (CLOCK_BOOTTIME)
+ clock_id = CLOCK_BOOTTIME;
+#else
+ clock_id = CLOCK_MONOTONIC;
+#endif
+
+ if (0 != clock_gettime(clock_id, &now)) {
+ warning("timer: clock_gettime() failed (%m)\n", errno);
+ return 0;
+ }
+
+ jfs = (long)now.tv_sec * (uint64_t)1000000;
+ jfs += now.tv_nsec / (uint64_t)1000;
+
+#else
+ struct timeval now;
+
+ if (0 != gettimeofday(&now, NULL)) {
+ warning("timer: gettimeofday() failed (%m)\n", errno);
+ return 0;
+ }
+
+ jfs = (long)now.tv_sec * (uint64_t)1000000;
+ jfs += now.tv_usec;
+#endif
+
+ return jfs;
+}
diff --git a/src/timestamp.c b/src/timestamp.c
new file mode 100644
index 0000000..dedf8d9
--- /dev/null
+++ b/src/timestamp.c
@@ -0,0 +1,65 @@
+/**
+ * @file timestamp.c Timestamp helpers
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Check if a 32-bit timestamp wraps around
+ *
+ * @param ts_new Timestamp of the current packet
+ * @param ts_old Timestamp of the previous packet
+ *
+ * @return Integer describing the wrap-around
+
+ * @retval -1 backwards wrap-around
+ * @retval 0 no wrap-around
+ * @retval 1 forward wrap-around
+ */
+int timestamp_wrap(uint32_t ts_new, uint32_t ts_old)
+{
+ int32_t delta;
+
+ if (ts_new < ts_old) {
+
+ delta = (int32_t)ts_new - (int32_t)ts_old;
+
+ if (delta > 0)
+ return 1;
+ }
+ else if ((int32_t)(ts_old - ts_new) > 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Calculate the total timestamp duration, in timestamp units.
+ * The duration is calculated as the delta between the
+ * last extended timestamp and the first extended timestamp.
+ *
+ * @param ts Receiver timestamp struct
+ *
+ * @return Timestamp duration
+ */
+uint64_t timestamp_duration(const struct timestamp_recv *ts)
+{
+ uint64_t last_ext;
+
+ if (!ts || !ts->is_set)
+ return 0;
+
+ last_ext = calc_extended_timestamp(ts->num_wraps, ts->last);
+
+ return last_ext - ts->first;
+}
+
+
diff --git a/src/ua.c b/src/ua.c
index 0467e35..76023d5 100644
--- a/src/ua.c
+++ b/src/ua.c
@@ -30,6 +30,7 @@ struct ua {
int af; /**< Preferred Address Family */
int af_media; /**< Preferred Address Family for media */
enum presence_status my_status; /**< Presence Status */
+ bool catchall; /**< Catch all inbound requests */
};
struct ua_eh {
@@ -201,6 +202,8 @@ int ua_register(struct ua *ua)
acc->regint, acc->outboundv[i]);
if (err) {
warning("ua: SIP register failed: %m\n", err);
+
+ ua_event(ua, UA_EVENT_REGISTER_FAIL, NULL, "%m", err);
goto out;
}
}
@@ -837,7 +840,8 @@ void ua_hangup(struct ua *ua, struct call *call,
(void)call_hangup(call, scode, reason);
- ua_event(ua, UA_EVENT_CALL_CLOSED, call, reason);
+ ua_event(ua, UA_EVENT_CALL_CLOSED, call,
+ reason ? reason : "Connection reset by user");
mem_deref(call);
@@ -1658,6 +1662,14 @@ struct ua *uag_find(const struct pl *cuser)
return ua;
}
+ /* Last resort, try any catchall UAs */
+ for (le = uag.ual.head; le; le = le->next) {
+ struct ua *ua = le->data;
+
+ if (ua->catchall)
+ return ua;
+ }
+
return NULL;
}
@@ -1895,6 +1907,22 @@ void ua_set_media_af(struct ua *ua, int af_media)
}
+/**
+ * Enable handling of all inbound requests, even if
+ * the request uri is not matching.
+ *
+ * @param ua User-Agent
+ * @param enabled True to enable, false to disable
+ */
+void ua_set_catchall(struct ua *ua, bool enabled)
+{
+ if (!ua)
+ return;
+
+ ua->catchall = enabled;
+}
+
+
int uag_set_extra_params(const char *eprm)
{
uag.eprm = mem_deref(uag.eprm);
diff --git a/src/video.c b/src/video.c
index f191215..e21b626 100644
--- a/src/video.c
+++ b/src/video.c
@@ -18,14 +18,7 @@
#include "magic.h"
-/** Internal video-encoder format */
-#ifndef VIDENC_INTERNAL_FMT
-#define VIDENC_INTERNAL_FMT (VID_FMT_YUV420P)
-#endif
-
-
enum {
- SRATE = 90000,
MAX_MUTED_FRAMES = 3,
};
@@ -103,9 +96,14 @@ struct vtx {
bool picup; /**< Send picture update */
bool muted; /**< Muted flag */
int frames; /**< Number of frames sent */
- int efps; /**< Estimated frame-rate */
- uint32_t ts_min;
- uint32_t ts_max;
+ double efps; /**< Estimated frame-rate */
+ uint64_t ts_base; /**< First RTP timestamp sent */
+ uint64_t ts_last; /**< Last RTP timestamp sent */
+
+ /** Statistics */
+ struct {
+ uint64_t src_frames; /**< Total frames from vidsrc */
+ } stats;
};
@@ -135,15 +133,21 @@ struct vrx {
struct list filtl; /**< Filters in decoding order */
struct tmr tmr_picup; /**< Picture update timer */
struct vidsz size; /**< Incoming video resolution */
+ enum vidfmt fmt; /**< Incoming pixel format */
enum vidorient orient; /**< Display orientation */
char device[128]; /**< Display device name */
int pt_rx; /**< Incoming RTP payload type */
int frames; /**< Number of frames received */
- int efps; /**< Estimated frame-rate */
+ double efps; /**< Estimated frame-rate */
unsigned n_intra; /**< Intra-frames decoded */
unsigned n_picup; /**< Picture updates sent */
uint32_t ts_min;
uint32_t ts_max;
+
+ /** Statistics */
+ struct {
+ uint64_t disp_frames; /** Total frames displayed */
+ } stats;
};
@@ -325,23 +329,21 @@ static void video_destructor(void *arg)
}
-static int get_fps(const struct video *v)
+static double get_fps(const struct video *v)
{
const char *attr;
/* RFC4566 */
attr = sdp_media_rattr(stream_sdpmedia(v->strm), "framerate");
if (attr) {
- /* NOTE: fractional values are ignored */
- const double fps = atof(attr);
- return (int)fps;
+ return atof(attr);
}
else
return v->cfg.fps;
}
-static int packet_handler(bool marker, uint32_t ts,
+static int packet_handler(bool marker, uint64_t ts,
const uint8_t *hdr, size_t hdr_len,
const uint8_t *pld, size_t pld_len,
void *arg)
@@ -352,14 +354,12 @@ static int packet_handler(bool marker, uint32_t ts,
uint32_t rtp_ts;
int err;
- /* NOTE: does not handle timestamp wrap around */
- if (ts < vtx->ts_min)
- vtx->ts_min = ts;
- if (ts > vtx->ts_max)
- vtx->ts_max = ts;
+ if (!vtx->ts_base)
+ vtx->ts_base = ts;
+ vtx->ts_last = ts;
/* add random timestamp offset */
- rtp_ts = vtx->ts_offset + ts;
+ rtp_ts = vtx->ts_offset + (ts & 0xffffffff);
err = vidqent_alloc(&qent, marker, strm->pt_enc, rtp_ts,
hdr, hdr_len, pld, pld_len);
@@ -404,13 +404,14 @@ static void encode_rtp_send(struct vtx *vtx, struct vidframe *frame)
lock_write_get(vtx->lock);
/* Convert image */
- if (frame->fmt != VIDENC_INTERNAL_FMT) {
+ if (frame->fmt != (enum vidfmt)vtx->video->cfg.enc_fmt) {
vtx->vsrc_size = frame->size;
if (!vtx->frame) {
- err = vidframe_alloc(&vtx->frame, VIDENC_INTERNAL_FMT,
+ err = vidframe_alloc(&vtx->frame,
+ vtx->video->cfg.enc_fmt,
&vtx->vsrc_size);
if (err)
goto unlock;
@@ -452,12 +453,17 @@ static void encode_rtp_send(struct vtx *vtx, struct vidframe *frame)
*
* @note This function has REAL-TIME properties
*/
-static void vidsrc_frame_handler(struct vidframe *frame, void *arg)
+static void vidsrc_frame_handler(struct vidframe *frame, uint64_t timestamp,
+ void *arg)
{
struct vtx *vtx = arg;
+ /* XXX: save timestamp(s) and pass to encoder */
+
++vtx->frames;
+ ++vtx->stats.src_frames;
+
/* Is the video muted? If so insert video mute image */
if (vtx->muted)
frame = vtx->mute_frame;
@@ -501,8 +507,6 @@ static int vtx_alloc(struct vtx *vtx, struct video *video)
tmr_start(&vtx->tmr_rtp, 1, rtp_tmr_handler, vtx);
- vtx->ts_min = ~0;
-
return err;
}
@@ -522,6 +526,7 @@ static int vrx_alloc(struct vrx *vrx, struct video *video)
str_ncpy(vrx->device, video->cfg.disp_dev, sizeof(vrx->device));
vrx->ts_min = ~0;
+ vrx->fmt = (enum vidfmt)-1;
return err;
}
@@ -618,6 +623,7 @@ static int video_stream_decode(struct vrx *vrx, const struct rtp_header *hdr,
goto out;
vrx->size = frame->size;
+ vrx->fmt = frame->fmt;
if (!list_isempty(&vrx->filtl)) {
@@ -639,6 +645,8 @@ static int video_stream_decode(struct vrx *vrx, const struct rtp_header *hdr,
err |= st->vf->dech(st, frame);
}
+ ++vrx->stats.disp_frames;
+
err = vidisp_display(vrx->vidisp, v->peer, frame);
frame_filt = mem_deref(frame_filt);
if (err == ENODEV) {
@@ -827,7 +835,7 @@ int video_alloc(struct video **vp, const struct stream_param *stream_prm,
}
err |= sdp_media_set_lattr(stream_sdpmedia(v->strm), true,
- "framerate", "%d", v->cfg.fps);
+ "framerate", "%.2f", v->cfg.fps);
/* RFC 4585 */
err |= sdp_media_set_lattr(stream_sdpmedia(v->strm), true,
@@ -939,7 +947,7 @@ static int set_encoder_format(struct vtx *vtx, const char *src,
}
vtx->mute_frame = mem_deref(vtx->mute_frame);
- err = vidframe_alloc(&vtx->mute_frame, VIDENC_INTERNAL_FMT, size);
+ err = vidframe_alloc(&vtx->mute_frame, vtx->video->cfg.enc_fmt, size);
if (err)
return err;
@@ -957,8 +965,8 @@ static void tmr_handler(void *arg)
tmr_start(&v->tmr, TMR_INTERVAL * 1000, tmr_handler, v);
/* Estimate framerates */
- v->vtx.efps = v->vtx.frames / TMR_INTERVAL;
- v->vrx.efps = v->vrx.frames / TMR_INTERVAL;
+ v->vtx.efps = (double)v->vtx.frames / (double)TMR_INTERVAL;
+ v->vrx.efps = (double)v->vrx.frames / (double)TMR_INTERVAL;
v->vtx.frames = 0;
v->vrx.frames = 0;
@@ -980,7 +988,7 @@ int video_start(struct video *v, const char *peer)
return err;
}
- stream_set_srate(v->strm, SRATE, SRATE);
+ stream_set_srate(v->strm, VIDEO_SRATE, VIDEO_SRATE);
if (vidisp_find(baresip_vidispl(), NULL)) {
err = set_vidisp(&v->vrx);
@@ -1149,7 +1157,7 @@ int video_encoder_set(struct video *v, struct vidcodec *vc,
prm.fps = get_fps(v);
prm.max_fs = -1;
- info("Set video encoder: %s %s (%u bit/s, %u fps)\n",
+ info("Set video encoder: %s %s (%u bit/s, %.2f fps)\n",
vc->name, vc->variant, prm.bitrate, prm.fps);
vtx->enc = mem_deref(vtx->enc);
@@ -1304,6 +1312,54 @@ void video_sdp_attr_decode(struct video *v)
}
+static int vtx_debug(struct re_printf *pf, const struct vtx *vtx)
+{
+ int err = 0;
+
+ err |= re_hprintf(pf, " tx: encode: %s %s\n",
+ vtx->vc ? vtx->vc->name : "none",
+ vtx->frame ? vidfmt_name(vtx->frame->fmt) : "?");
+ err |= re_hprintf(pf, " source: %s %u x %u, fps=%.2f"
+ " frames=%llu\n",
+ vtx->vsrc ? vidsrc_get(vtx->vsrc)->name : "none",
+ vtx->vsrc_size.w,
+ vtx->vsrc_size.h, vtx->vsrc_prm.fps,
+ vtx->stats.src_frames);
+ err |= re_hprintf(pf, " skipc=%u sendq=%u\n",
+ vtx->skipc, list_count(&vtx->sendq));
+
+ if (vtx->ts_base) {
+ err |= re_hprintf(pf, " time = %.3f sec\n",
+ video_calc_seconds(vtx->ts_last - vtx->ts_base));
+ }
+ else {
+ err |= re_hprintf(pf, " time = (not started)\n");
+ }
+
+ return err;
+}
+
+
+static int vrx_debug(struct re_printf *pf, const struct vrx *vrx)
+{
+ int err = 0;
+
+ err |= re_hprintf(pf, " rx: decode: %s %s\n",
+ vrx->vc ? vrx->vc->name : "none",
+ vidfmt_name(vrx->fmt));
+ err |= re_hprintf(pf, " vidisp: %s %u x %u frames=%llu\n",
+ vrx->vidisp ? vidisp_get(vrx->vidisp)->name : "none",
+ vrx->size.w, vrx->size.h,
+ vrx->stats.disp_frames);
+ err |= re_hprintf(pf, " n_intra=%u, n_picup=%u\n",
+ vrx->n_intra, vrx->n_picup);
+ err |= re_hprintf(pf, " time = %.3f sec\n",
+ video_calc_seconds(vrx->ts_max - vrx->ts_min));
+
+ return err;
+}
+
+
int video_debug(struct re_printf *pf, const struct video *v)
{
const struct vtx *vtx;
@@ -1319,20 +1375,10 @@ int video_debug(struct re_printf *pf, const struct video *v)
err = re_hprintf(pf, "\n--- Video stream ---\n");
err |= re_hprintf(pf, " started: %s\n", v->started ? "yes" : "no");
- err |= re_hprintf(pf, " tx: %u x %u, fps=%d\n",
- vtx->vsrc_size.w,
- vtx->vsrc_size.h, vtx->vsrc_prm.fps);
- err |= re_hprintf(pf, " skipc=%u\n", vtx->skipc);
- err |= re_hprintf(pf, " time = %.3f sec\n",
- video_calc_seconds(vtx->ts_max - vtx->ts_min));
-
- err |= re_hprintf(pf, " rx: %u x %u\n", vrx->size.w, vrx->size.h);
- err |= re_hprintf(pf, " pt=%d\n", vrx->pt_rx);
-
- err |= re_hprintf(pf, " n_intra=%u, n_picup=%u\n",
- vrx->n_intra, vrx->n_picup);
- err |= re_hprintf(pf, " time = %.3f sec\n",
- video_calc_seconds(vrx->ts_max - vrx->ts_min));
+ err |= vtx_debug(pf, vtx);
+ err |= vrx_debug(pf, vrx);
+ if (err)
+ return err;
if (!list_isempty(baresip_vidfiltl())) {
err |= vtx_print_pipeline(pf, vtx);
@@ -1350,7 +1396,7 @@ int video_print(struct re_printf *pf, const struct video *v)
if (!v)
return 0;
- return re_hprintf(pf, " efps=%d/%d", v->vtx.efps, v->vrx.efps);
+ return re_hprintf(pf, " efps=%.1f/%.1f", v->vtx.efps, v->vrx.efps);
}
@@ -1384,38 +1430,3 @@ void video_set_devicename(struct video *v, const char *src, const char *disp)
str_ncpy(v->vtx.device, src, sizeof(v->vtx.device));
str_ncpy(v->vrx.device, disp, sizeof(v->vrx.device));
}
-
-
-/**
- * Calculate the RTP timestamp from Presentation Time Stamp (PTS)
- * or Decoding Time Stamp (DTS) and framerate.
- *
- * @note The calculated RTP Timestamp may wrap around.
- *
- * @param pts Presentation Time Stamp (PTS)
- * @param fps Framerate in [frames per second]
- *
- * @return RTP Timestamp
- */
-uint32_t video_calc_rtp_timestamp(int64_t pts, unsigned fps)
-{
- uint64_t rtp_ts;
-
- if (!fps)
- return 0;
-
- rtp_ts = ((uint64_t)SRATE * pts) / fps;
-
- return (uint32_t)rtp_ts;
-}
-
-
-double video_calc_seconds(uint32_t rtp_ts)
-{
- double timestamp;
-
- /* convert from RTP clockrate to seconds */
- timestamp = (double)rtp_ts / (double)SRATE;
-
- return timestamp;
-}
diff --git a/src/vidisp.c b/src/vidisp.c
index d267f58..2a2def6 100644
--- a/src/vidisp.c
+++ b/src/vidisp.c
@@ -126,6 +126,13 @@ int vidisp_display(struct vidisp_st *st, const char *title,
}
+/**
+ * Get the video display module from a video display state
+ *
+ * @param st Video display state
+ *
+ * @return Video display module
+ */
struct vidisp *vidisp_get(struct vidisp_st *st)
{
return st ? st->vd : NULL;
diff --git a/src/vidsrc.c b/src/vidsrc.c
index 2c8f9ff..03a039a 100644
--- a/src/vidsrc.c
+++ b/src/vidsrc.c
@@ -119,6 +119,13 @@ int vidsrc_alloc(struct vidsrc_st **stp, struct list *vidsrcl,
}
+/**
+ * Get the video source module from a video source state
+ *
+ * @param st Video source state
+ *
+ * @return Video source module
+ */
struct vidsrc *vidsrc_get(struct vidsrc_st *st)
{
return st ? st->vs : NULL;
diff --git a/src/vidutil.c b/src/vidutil.c
new file mode 100644
index 0000000..a6d0b61
--- /dev/null
+++ b/src/vidutil.c
@@ -0,0 +1,65 @@
+/**
+ * @file vidutil.c Video utility functions
+ *
+ * Copyright (C) 2017 Creytiv.com
+ */
+
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Calculate the RTP timestamp from Presentation Time Stamp (PTS)
+ * or Decoding Time Stamp (DTS) and framerate.
+ *
+ * @note The calculated RTP Timestamp may NOT wrap around.
+ *
+ * @param pts Presentation Time Stamp (PTS)
+ * @param fps Framerate in [frames per second]
+ *
+ * @return Extended RTP Timestamp
+ */
+uint64_t video_calc_rtp_timestamp(int64_t pts, double fps)
+{
+ uint64_t rtp_ts;
+
+ if (!fps)
+ return 0;
+
+ rtp_ts = ((uint64_t)VIDEO_SRATE * pts) / fps;
+
+ return rtp_ts;
+}
+
+
+/**
+ * Calculate the timestamp in seconds from the RTP timestamp.
+ *
+ * @param rtp_ts RTP Timestamp
+ *
+ * @return Timestamp in seconds
+ */
+double video_calc_seconds(uint64_t rtp_ts)
+{
+ double timestamp;
+
+ /* convert from RTP clockrate to seconds */
+ timestamp = (double)rtp_ts / (double)VIDEO_SRATE;
+
+ return timestamp;
+}
+
+
+/**
+ * Convert a video timestamp to seconds
+ *
+ * @param timestamp Timestamp in VIDEO_TIMEBASE units
+ *
+ * @return Timestamp in seconds
+ */
+double video_timestamp_to_seconds(uint64_t timestamp)
+{
+ return (double)timestamp / (double)VIDEO_TIMEBASE;
+}