diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/account.c | 3 | ||||
-rw-r--r-- | src/audio.c | 212 | ||||
-rw-r--r-- | src/call.c | 27 | ||||
-rw-r--r-- | src/conf.c | 18 | ||||
-rw-r--r-- | src/config.c | 78 | ||||
-rw-r--r-- | src/core.h | 75 | ||||
-rw-r--r-- | src/event.c | 10 | ||||
-rw-r--r-- | src/h264.c | 36 | ||||
-rw-r--r-- | src/log.c | 71 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/metric.c | 4 | ||||
-rw-r--r-- | src/reg.c | 5 | ||||
-rw-r--r-- | src/srcs.mk | 3 | ||||
-rw-r--r-- | src/stream.c | 11 | ||||
-rw-r--r-- | src/timer.c | 71 | ||||
-rw-r--r-- | src/timestamp.c | 65 | ||||
-rw-r--r-- | src/ua.c | 30 | ||||
-rw-r--r-- | src/video.c | 177 | ||||
-rw-r--r-- | src/vidisp.c | 7 | ||||
-rw-r--r-- | src/vidsrc.c | 7 | ||||
-rw-r--r-- | src/vidutil.c | 65 |
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; +} @@ -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; @@ -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"); @@ -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; } @@ -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 "???"; +} @@ -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; @@ -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; } @@ -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(®->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; +} + + @@ -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; +} |