summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/account/account.c22
-rw-r--r--modules/amr/amr.c22
-rw-r--r--modules/auloop/auloop.c8
-rw-r--r--modules/av1/decode.c2
-rw-r--r--modules/av1/encode.c8
-rw-r--r--modules/avcapture/avcapture.m6
-rw-r--r--modules/avcodec/avcodec.h8
-rw-r--r--modules/avcodec/decode.c42
-rw-r--r--modules/avcodec/encode.c26
-rw-r--r--modules/avformat/avformat.c36
-rw-r--r--modules/b2bua/b2bua.c5
-rw-r--r--modules/bv32/bv32.c22
-rw-r--r--modules/cairo/cairo.c23
-rw-r--r--modules/codec2/codec2.c10
-rw-r--r--modules/ctrl_tcp/ctrl_tcp.c377
-rw-r--r--modules/ctrl_tcp/module.mk10
-rw-r--r--modules/ctrl_tcp/netstring/netstring.c164
-rw-r--r--modules/ctrl_tcp/netstring/netstring.h28
-rw-r--r--modules/ctrl_tcp/tcp_netstring.c221
-rw-r--r--modules/ctrl_tcp/tcp_netstring.h16
-rw-r--r--modules/dshow/dshow.cpp3
-rw-r--r--modules/fakevideo/fakevideo.c65
-rw-r--r--modules/g711/g711.c36
-rw-r--r--modules/g722/g722.c11
-rw-r--r--modules/g7221/decode.c3
-rw-r--r--modules/g7221/encode.c2
-rw-r--r--modules/g7221/g7221.h5
-rw-r--r--modules/g726/g726.c11
-rw-r--r--modules/gsm/gsm.c11
-rw-r--r--modules/gst1/gst.c1
-rw-r--r--modules/gst_video/encode.c4
-rw-r--r--modules/gst_video1/encode.c4
-rw-r--r--modules/h265/encode.c8
-rw-r--r--modules/l16/l16.c17
-rw-r--r--modules/menu/menu.c30
-rw-r--r--modules/mpa/decode.c8
-rw-r--r--modules/mpa/encode.c6
-rw-r--r--modules/mpa/mpa.h7
-rw-r--r--modules/mqtt/README.md19
-rw-r--r--modules/omx/module.c2
-rw-r--r--modules/omx/module.mk9
-rw-r--r--modules/omx/omx.c34
-rw-r--r--modules/omx/omx.h4
-rw-r--r--modules/opus/decode.c57
-rw-r--r--modules/opus/encode.c36
-rw-r--r--modules/opus/opus.h8
-rw-r--r--modules/rst/video.c6
-rw-r--r--modules/silk/silk.c15
-rw-r--r--modules/speex/speex.c12
-rw-r--r--modules/speex_aec/module.mk4
-rw-r--r--modules/speex_pp/module.mk4
-rw-r--r--modules/swscale/swscale.c1
-rw-r--r--modules/v4l/v4l.c11
-rw-r--r--modules/v4l2/v4l2.c37
-rw-r--r--modules/v4l2_codec/v4l2_codec.c19
-rw-r--r--modules/vidbridge/src.c11
-rw-r--r--modules/vidbridge/vidbridge.h4
-rw-r--r--modules/vidloop/vidloop.c229
-rw-r--r--modules/vp8/encode.c4
-rw-r--r--modules/vp9/encode.c6
-rw-r--r--modules/x11grab/x11grab.c11
61 files changed, 1606 insertions, 225 deletions
diff --git a/modules/account/account.c b/modules/account/account.c
index c972908..74c047f 100644
--- a/modules/account/account.c
+++ b/modules/account/account.c
@@ -20,7 +20,7 @@
* Examples:
\verbatim
"User 1 with password prompt" <sip:user@domain.com>
- "User 2 with stored password" <sip:user:pass@domain.com>
+ "User 2 with stored password" <sip:user@domain.com>;auth_pass=pass
"User 2 with ICE" <sip:user@1.2.3.4;transport=tcp>;medianat=ice
"User 3 with IPv6" <sip:user@[2001:df8:0:16:216:6fff:fe91:614c]:5070>
\endverbatim
@@ -39,12 +39,13 @@ static int account_write_template(const char *file)
if (!f)
return errno;
- login = pass = sys_username();
+ login = sys_username();
if (!login) {
login = "user";
- pass = "pass";
}
+ pass = "PASSWORD";
+
domain = net_domain(baresip_network());
if (!domain)
domain = "domain";
@@ -53,7 +54,7 @@ static int account_write_template(const char *file)
"#\n"
"# SIP accounts - one account per line\n"
"#\n"
- "# Displayname <sip:user:password@domain"
+ "# Displayname <sip:user@domain"
";uri-params>;addr-params\n"
"#\n"
"# uri-params:\n"
@@ -63,6 +64,7 @@ static int account_write_template(const char *file)
"# ;answermode={manual,early,auto}\n"
"# ;audio_codecs=speex/16000,pcma,...\n"
"# ;auth_user=username\n"
+ "# ;auth_pass=password\n"
"# ;mediaenc={srtp,srtp-mand,srtp-mandf"
",dtls_srtp,zrtp}\n"
"# ;medianat={stun,turn,ice}\n"
@@ -82,13 +84,15 @@ static int account_write_template(const char *file)
"#\n"
"# Examples:\n"
"#\n"
- "# <sip:user:secret@domain.com;transport=tcp>\n"
- "# <sip:user:secret@1.2.3.4;transport=tcp>\n"
- "# <sip:user:secret@"
+ "# <sip:user@domain.com;transport=tcp>"
+ ";auth_pass=secret\n"
+ "# <sip:user@1.2.3.4;transport=tcp>"
+ ";auth_pass=secret\n"
+ "# <sip:user@"
"[2001:df8:0:16:216:6fff:fe91:614c]:5070"
- ";transport=tcp>\n"
+ ";transport=tcp>;auth_pass=secret\n"
"#\n"
- "#<sip:%s:%s@%s>\n", login, pass, domain);
+ "#<sip:%s@%s>;auth_pass=%s\n", login, domain, pass);
if (r < 0)
err = ENOMEM;
diff --git a/modules/amr/amr.c b/modules/amr/amr.c
index 885a318..58343a1 100644
--- a/modules/amr/amr.c
+++ b/modules/amr/amr.c
@@ -16,6 +16,7 @@
#include <dec_if.h>
#endif
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include "amr.h"
@@ -205,7 +206,7 @@ static int decode_update(struct audec_state **adsp,
#ifdef AMR_WB
static int encode_wb(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
int n;
@@ -215,6 +216,9 @@ static int encode_wb(struct auenc_state *st, uint8_t *buf, size_t *len,
if (*len < NB_SERIAL_MAX)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
/* CMR value 15 indicates that no mode request is present */
buf[0] = 15 << 4;
@@ -228,7 +232,8 @@ static int encode_wb(struct auenc_state *st, uint8_t *buf, size_t *len,
}
-static int decode_wb(struct audec_state *st, int16_t *sampv, size_t *sampc,
+static int decode_wb(struct audec_state *st,
+ int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
if (*sampc < L_FRAME16k)
@@ -236,6 +241,9 @@ static int decode_wb(struct audec_state *st, int16_t *sampv, size_t *sampc,
if (len > NB_SERIAL_MAX)
return EINVAL;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
IF2D_IF_decode(st->dec, &buf[1], sampv, 0);
*sampc = L_FRAME16k;
@@ -247,7 +255,7 @@ static int decode_wb(struct audec_state *st, int16_t *sampv, size_t *sampc,
#ifdef AMR_NB
static int encode_nb(struct auenc_state *st, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc)
+ size_t *len, int fmt, const void *sampv, size_t sampc)
{
int r;
@@ -256,6 +264,9 @@ static int encode_nb(struct auenc_state *st, uint8_t *buf,
if (*len < NB_SERIAL_MAX)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
/* CMR value 15 indicates that no mode request is present */
buf[0] = 15 << 4;
@@ -269,7 +280,7 @@ static int encode_nb(struct auenc_state *st, uint8_t *buf,
}
-static int decode_nb(struct audec_state *st, int16_t *sampv,
+static int decode_nb(struct audec_state *st, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
if (!st || !sampv || !sampc || !buf)
@@ -281,6 +292,9 @@ static int decode_nb(struct audec_state *st, int16_t *sampv,
if (*sampc < L_FRAME16k)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
Decoder_Interface_Decode(st->dec, &buf[1], sampv, 0);
*sampc = FRAMESIZE_NB;
diff --git a/modules/auloop/auloop.c b/modules/auloop/auloop.c
index 8324a88..c1da518 100644
--- a/modules/auloop/auloop.c
+++ b/modules/auloop/auloop.c
@@ -120,12 +120,14 @@ static int codec_read(struct audio_loop *al, int16_t *sampv, size_t sampc)
aubuf_read_samp(al->ab, al->sampv, al->sampc);
- err = al->ac->ench(al->enc, x, &xlen, al->sampv, al->sampc);
+ err = al->ac->ench(al->enc, x, &xlen,
+ AUFMT_S16LE, al->sampv, al->sampc);
if (err)
goto out;
if (al->ac->dech) {
- err = al->ac->dech(al->dec, sampv, &sampc, x, xlen);
+ err = al->ac->dech(al->dec, AUFMT_S16LE, sampv, &sampc,
+ x, xlen);
if (err)
goto out;
}
@@ -186,7 +188,7 @@ static void error_handler(int err, const char *str, void *arg)
static void start_codec(struct audio_loop *al, const char *name)
{
- struct auenc_param prm = {PTIME};
+ struct auenc_param prm = {PTIME, 0};
int err;
al->ac = aucodec_find(baresip_aucodecl(), name,
diff --git a/modules/av1/decode.c b/modules/av1/decode.c
index 21ccc75..4987842 100644
--- a/modules/av1/decode.c
+++ b/modules/av1/decode.c
@@ -258,7 +258,7 @@ int av1_decode(struct viddec_state *vds, struct vidframe *frame,
}
res = aom_codec_decode(&vds->ctx, vds->mb->buf,
- (unsigned int)vds->mb->end, NULL, 1);
+ (unsigned int)vds->mb->end, NULL);
if (res) {
debug("av1: decode error: %s\n", aom_codec_err_to_string(res));
err = EPROTO;
diff --git a/modules/av1/encode.c b/modules/av1/encode.c
index 9e24bcc..d090a86 100644
--- a/modules/av1/encode.c
+++ b/modules/av1/encode.c
@@ -23,7 +23,7 @@ struct videnc_state {
aom_codec_ctx_t ctx;
struct vidsz size;
aom_codec_pts_t pts;
- unsigned fps;
+ double fps;
unsigned bitrate;
unsigned pktsize;
bool ctxup;
@@ -137,7 +137,7 @@ static inline void hdr_encode(uint8_t hdr[HDR_SIZE], bool noref, bool start,
}
-static inline int packetize(bool marker, uint32_t rtp_ts,
+static inline int packetize(bool marker, uint64_t rtp_ts,
const uint8_t *buf, size_t len,
size_t maxlen, bool noref, uint8_t partid,
uint16_t picid, videnc_packet_h *pkth, void *arg)
@@ -210,7 +210,7 @@ int av1_encode(struct videnc_state *ves, bool update,
}
res = aom_codec_encode(&ves->ctx, img, ves->pts++, 1,
- flags, AOM_DL_REALTIME);
+ flags);
if (res) {
warning("av1: enc error: %s\n", aom_codec_err_to_string(res));
return ENOMEM;
@@ -222,7 +222,7 @@ int av1_encode(struct videnc_state *ves, bool update,
bool keyframe = false, marker = true;
const aom_codec_cx_pkt_t *pkt;
uint8_t partid = 0;
- uint32_t ts;
+ uint64_t ts;
pkt = aom_codec_get_cx_data(&ves->ctx, &iter);
if (!pkt)
diff --git a/modules/avcapture/avcapture.m b/modules/avcapture/avcapture.m
index f276c96..7420cfe 100644
--- a/modules/avcapture/avcapture.m
+++ b/modules/avcapture/avcapture.m
@@ -234,7 +234,9 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)conn
{
const CVImageBufferRef b = CMSampleBufferGetImageBuffer(sampleBuffer);
+ CMTime ts = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);
struct vidframe vf;
+ uint64_t timestamp;
(void)captureOutput;
(void)conn;
@@ -246,8 +248,10 @@ didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
vidframe_set_pixbuf(&vf, b);
+ timestamp = CMTimeGetSeconds(ts) * VIDEO_TIMEBASE;
+
if (vidframe_isvalid(&vf))
- vsrc->frameh(&vf, vsrc->arg);
+ vsrc->frameh(&vf, timestamp, vsrc->arg);
CVPixelBufferUnlockBaseAddress(b, 0);
}
diff --git a/modules/avcodec/avcodec.h b/modules/avcodec/avcodec.h
index f3a2b70..3511145 100644
--- a/modules/avcodec/avcodec.h
+++ b/modules/avcodec/avcodec.h
@@ -16,6 +16,14 @@
#endif
+#if LIBAVUTIL_VERSION_MAJOR < 52
+#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
+#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
+#define AV_PIX_FMT_NV12 PIX_FMT_NV12
+#define AV_PIX_FMT_YUV444P PIX_FMT_YUV444P
+#endif
+
+
extern const uint8_t h264_level_idc;
extern AVCodec *avcodec_h264enc;
extern AVCodec *avcodec_h264dec;
diff --git a/modules/avcodec/decode.c b/modules/avcodec/decode.c
index 77e6e77..759535c 100644
--- a/modules/avcodec/decode.c
+++ b/modules/avcodec/decode.c
@@ -16,13 +16,6 @@
#include "avcodec.h"
-#if LIBAVUTIL_VERSION_MAJOR < 52
-#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
-#define AV_PIX_FMT_YUVJ420P PIX_FMT_YUVJ420P
-#define AV_PIX_FMT_NV12 PIX_FMT_NV12
-#endif
-
-
enum {
DECODE_MAXSZ = 524288,
};
@@ -37,6 +30,7 @@ struct viddec_state {
size_t frag_start;
bool frag;
uint16_t frag_seq;
+ double fps;
struct {
unsigned n_key;
@@ -192,7 +186,9 @@ static int ffdecode(struct viddec_state *st, struct vidframe *frame)
ret = avcodec_send_packet(st->ctx, &avpkt);
if (ret < 0) {
- warning("avcodec_send_packet error ret=%d\n", ret);
+ warning("avcodec: avcodec_send_packet error,"
+ " packet=%zu bytes, ret=%d (%s)\n",
+ st->mb->end, ret, av_err2str(ret));
err = EBADMSG;
goto out;
}
@@ -235,6 +231,8 @@ static int ffdecode(struct viddec_state *st, struct vidframe *frame)
if (got_picture) {
+ double fps;
+
#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(5<<8)+0)
switch (st->pict->format) {
@@ -247,6 +245,10 @@ static int ffdecode(struct viddec_state *st, struct vidframe *frame)
frame->fmt = VID_FMT_NV12;
break;
+ case AV_PIX_FMT_YUV444P:
+ frame->fmt = VID_FMT_YUV444P;
+ break;
+
default:
warning("avcodec: decode: bad pixel format"
" (%i) (%s)\n",
@@ -264,6 +266,18 @@ static int ffdecode(struct viddec_state *st, struct vidframe *frame)
}
frame->size.w = st->ctx->width;
frame->size.h = st->ctx->height;
+
+#if LIBAVCODEC_VERSION_INT > ((56<<16)+(1<<8)+0)
+ /* get the framerate of the decoded bitstream */
+ fps = av_q2d(st->ctx->framerate);
+ if (st->fps != fps) {
+ st->fps = fps;
+ debug("avcodec: current decoder framerate"
+ " is %.2f fps\n", fps);
+ }
+#else
+ (void)fps;
+#endif
}
out:
@@ -285,10 +299,11 @@ int decode_h264(struct viddec_state *st, struct vidframe *frame,
return err;
#if 0
- re_printf("avcodec: decode: %s %s type=%2d \n",
+ re_printf("avcodec: decode: %s %s type=%2d %s \n",
marker ? "[M]" : " ",
h264_is_keyframe(h264_hdr.type) ? "<KEY>" : " ",
- h264_hdr.type);
+ h264_hdr.type,
+ h264_nalunit_name(h264_hdr.type));
#endif
if (h264_hdr.f) {
@@ -329,8 +344,8 @@ int decode_h264(struct viddec_state *st, struct vidframe *frame,
if (fu.s) {
if (st->frag) {
- debug("avcodec: lost fragments;"
- " ignoring NAL\n");
+ debug("avcodec: start: lost fragments;"
+ " ignoring previous NAL\n");
fragment_rewind(st);
++st->stats.n_lost;
}
@@ -349,7 +364,8 @@ int decode_h264(struct viddec_state *st, struct vidframe *frame,
}
else {
if (!st->frag) {
- debug("avcodec: ignoring fragment\n");
+ debug("avcodec: ignoring fragment"
+ " (nal=%u)\n", fu.type);
++st->stats.n_lost;
return 0;
}
diff --git a/modules/avcodec/encode.c b/modules/avcodec/encode.c
index d0d5d83..ea543d8 100644
--- a/modules/avcodec/encode.c
+++ b/modules/avcodec/encode.c
@@ -20,9 +20,8 @@
#include "avcodec.h"
-#if LIBAVUTIL_VERSION_MAJOR < 52
-#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
-#define AV_PIX_FMT_NV12 PIX_FMT_NV12
+#ifndef AV_INPUT_BUFFER_MIN_SIZE
+#define AV_INPUT_BUFFER_MIN_SIZE FF_MIN_BUFFER_SIZE
#endif
@@ -341,7 +340,7 @@ static void param_handler(const struct pl *name, const struct pl *val,
}
-static int general_packetize(uint32_t rtp_ts, struct mbuf *mb, size_t pktsize,
+static int general_packetize(uint64_t rtp_ts, struct mbuf *mb, size_t pktsize,
videnc_packet_h *pkth, void *arg)
{
int err = 0;
@@ -366,7 +365,7 @@ static int general_packetize(uint32_t rtp_ts, struct mbuf *mb, size_t pktsize,
static int h263_packetize(struct videnc_state *st,
- uint32_t rtp_ts, struct mbuf *mb,
+ uint64_t rtp_ts, struct mbuf *mb,
videnc_packet_h *pkth, void *arg)
{
struct h263_strm h263_strm;
@@ -513,7 +512,7 @@ int encode_update(struct videnc_state **vesp, const struct vidcodec *vc,
goto out;
}
- st->mb = mbuf_alloc(FF_MIN_BUFFER_SIZE * 20);
+ st->mb = mbuf_alloc(AV_INPUT_BUFFER_MIN_SIZE * 20);
st->mb_frag = mbuf_alloc(1024);
if (!st->mb || !st->mb_frag) {
err = ENOMEM;
@@ -542,7 +541,7 @@ int encode_update(struct videnc_state **vesp, const struct vidcodec *vc,
fmt_param_apply(&sdp_fmtp, param_handler, st);
}
- debug("avcodec: video encoder %s: %d fps, %d bit/s, pktsize=%u\n",
+ debug("avcodec: video encoder %s: %.2f fps, %d bit/s, pktsize=%u\n",
vc->name, prm->fps, prm->bitrate, prm->pktsize);
out:
@@ -564,7 +563,7 @@ int encode_x264(struct videnc_state *st, bool update,
int i_nal;
int i, err, ret;
int csp, pln;
- uint32_t ts;
+ uint64_t ts;
if (!st || !frame)
return EINVAL;
@@ -581,6 +580,11 @@ int encode_x264(struct videnc_state *st, bool update,
pln = 2;
break;
+ case VID_FMT_YUV444P:
+ csp = X264_CSP_I444;
+ pln = 3;
+ break;
+
default:
warning("avcodec: pixel format not supported (%s)\n",
vidfmt_name(frame->fmt));
@@ -660,7 +664,7 @@ int encode(struct videnc_state *st, bool update, const struct vidframe *frame)
{
int i, err, ret;
int pix_fmt;
- uint32_t ts;
+ uint64_t ts;
if (!st || !frame)
return EINVAL;
@@ -675,6 +679,10 @@ int encode(struct videnc_state *st, bool update, const struct vidframe *frame)
pix_fmt = AV_PIX_FMT_NV12;
break;
+ case VID_FMT_YUV444P:
+ pix_fmt = AV_PIX_FMT_YUV444P;
+ break;
+
default:
warning("avcodec: pixel format not supported (%s)\n",
vidfmt_name(frame->fmt));
diff --git a/modules/avformat/avformat.c b/modules/avformat/avformat.c
index 68ef088..af20082 100644
--- a/modules/avformat/avformat.c
+++ b/modules/avformat/avformat.c
@@ -66,7 +66,6 @@ struct vidsrc_st {
vidsrc_frame_h *frameh;
void *arg;
int sindex;
- int fps;
};
@@ -101,6 +100,8 @@ static void handle_packet(struct vidsrc_st *st, AVPacket *pkt)
struct vidframe vf;
struct vidsz sz;
unsigned i;
+ int64_t pts;
+ uint64_t timestamp;
if (st->codec) {
int got_pict, ret;
@@ -148,6 +149,12 @@ static void handle_packet(struct vidsrc_st *st, AVPacket *pkt)
return;
}
+ pts = av_frame_get_best_effort_timestamp(frame);
+ const AVRational time_base = st->time_base;
+
+ /* convert timestamp */
+ timestamp = pts * VIDEO_TIMEBASE * time_base.num / time_base.den;
+
#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(5<<8)+0)
switch (frame->format) {
@@ -173,7 +180,7 @@ static void handle_packet(struct vidsrc_st *st, AVPacket *pkt)
vf.linesize[i] = frame->linesize[i];
}
- st->frameh(&vf, st->arg);
+ st->frameh(&vf, timestamp, st->arg);
out:
if (frame) {
@@ -244,7 +251,7 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
bool found_stream = false;
uint32_t i;
int ret, err = 0;
- int input_fps = 0;
+ double input_fps = 0;
(void)mctx;
(void)errorh;
@@ -262,7 +269,6 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
st->sz = *size;
st->frameh = frameh;
st->arg = arg;
- st->fps = prm->fps;
/*
* avformat_open_input() was added in lavf 53.2.0 according to
@@ -283,7 +289,7 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
/* Params */
memset(&prms, 0, sizeof(prms));
- prms.time_base = (AVRational){1, prm->fps};
+ prms.time_base = av_d2q(prm->fps, INT_MAX);
prms.channels = 1;
prms.width = size->w;
prms.height = size->h;
@@ -314,13 +320,12 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
}
#if 0
- dump_format(st->ic, 0, dev, 0);
+ av_dump_format(st->ic, 0, dev, 0);
#endif
for (i=0; i<st->ic->nb_streams; i++) {
const struct AVStream *strm = st->ic->streams[i];
AVCodecContext *ctx;
- double dfps;
#if LIBAVFORMAT_VERSION_INT >= ((57<<16) + (33<<8) + 100)
@@ -355,14 +360,17 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
st->sindex = strm->index;
st->time_base = strm->time_base;
- dfps = av_q2d(strm->avg_frame_rate);
- input_fps = (int)dfps;
- if (st->fps != input_fps) {
- info("avformat: updating %i fps from config to native "
- "input material fps %i\n", st->fps, input_fps);
- st->fps = input_fps;
+ input_fps = av_q2d(strm->avg_frame_rate);
+ if (prm->fps != input_fps) {
+ info("avformat: updating %.2f fps from config"
+ " to native "
+ "input material fps %.2f\n",
+ prm->fps, input_fps);
+
+ prm->fps = input_fps;
+
#if LIBAVFORMAT_VERSION_INT < ((52<<16) + (110<<8) + 0)
- prms.time_base = (AVRational){1, st->fps};
+ prms.time_base = av_d2q(input_fps, INT_MAX);
#endif
}
diff --git a/modules/b2bua/b2bua.c b/modules/b2bua/b2bua.c
index 7386a29..5e2bd1a 100644
--- a/modules/b2bua/b2bua.c
+++ b/modules/b2bua/b2bua.c
@@ -211,10 +211,13 @@ static int module_init(void)
if (err)
return err;
- err = uag_event_register(ua_event_handler, 0);
+ err = uag_event_register(ua_event_handler, NULL);
if (err)
return err;
+ /* The inbound UA will handle all non-matching requests */
+ ua_set_catchall(ua_in, true);
+
debug("b2bua: module loaded\n");
return 0;
diff --git a/modules/bv32/bv32.c b/modules/bv32/bv32.c
index d3dd45c..a23241e 100644
--- a/modules/bv32/bv32.c
+++ b/modules/bv32/bv32.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010 Creytiv.com
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <bv32/bv32.h>
#include <bv32/bitpack.h>
@@ -100,17 +101,21 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
size_t i, nframe;
+ short *p = (short *)sampv;
nframe = sampc / NSAMP;
if (*len < nframe * CODED_OCTETS)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
for (i=0; i<nframe; i++) {
- BV32_Encode(&st->bsc, &st->cs, (short *)&sampv[i*NSAMP]);
+ BV32_Encode(&st->bsc, &st->cs, &p[i*NSAMP]);
BV32_BitPack((void *)&buf[i*CODED_OCTETS], &st->bsc);
}
@@ -120,19 +125,23 @@ static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
}
-static int decode(struct audec_state *st, int16_t *sampv,
+static int decode(struct audec_state *st, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
size_t i, nframe;
+ short *p = sampv;
nframe = len / CODED_OCTETS;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
if (*sampc < NSAMP*nframe)
return ENOMEM;
for (i=0; i<nframe; i++) {
BV32_BitUnPack((void *)&buf[i*CODED_OCTETS], &st->bsd);
- BV32_Decode(&st->bsd, &st->ds, (short *)&sampv[i*NSAMP]);
+ BV32_Decode(&st->bsd, &st->ds, &p[i*NSAMP]);
}
*sampc = NSAMP * nframe;
@@ -141,8 +150,11 @@ static int decode(struct audec_state *st, int16_t *sampv,
}
-static int plc(struct audec_state *st, int16_t *sampv, size_t *sampc)
+static int plc(struct audec_state *st, int fmt, void *sampv, size_t *sampc)
{
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
BV32_PLC(&st->ds, sampv);
*sampc = NSAMP;
diff --git a/modules/cairo/cairo.c b/modules/cairo/cairo.c
index 2af2a12..2422d6b 100644
--- a/modules/cairo/cairo.c
+++ b/modules/cairo/cairo.c
@@ -129,7 +129,7 @@ static void draw_logo(struct vidsrc_st *st)
}
-static void process(struct vidsrc_st *st)
+static void process(struct vidsrc_st *st, uint64_t timestamp)
{
struct vidframe f;
unsigned xoffs = 2, yoffs = 24;
@@ -138,9 +138,12 @@ static void process(struct vidsrc_st *st)
draw_text(st, xoffs, yoffs + FONT_SIZE, "%H", fmt_gmtime, NULL);
- draw_text(st, xoffs, yoffs + FONT_SIZE*2, "%u x %u @ %d fps",
+ draw_text(st, xoffs, yoffs + FONT_SIZE*2, "%u x %u @ %.2f fps",
st->size.w, st->size.h, st->prm.fps);
+ draw_text(st, xoffs, yoffs + FONT_SIZE*3, "Time: %.3f sec",
+ timestamp / (double)VIDEO_TIMEBASE);
+
draw_logo(st);
st->step += 0.02 / st->prm.fps;
@@ -148,29 +151,33 @@ static void process(struct vidsrc_st *st)
vidframe_init_buf(&f, VID_FMT_RGB32, &st->size,
cairo_image_surface_get_data(st->surface));
- st->frameh(&f, st->arg);
+ st->frameh(&f, timestamp, st->arg);
}
static void *read_thread(void *arg)
{
struct vidsrc_st *st = arg;
- uint64_t ts = 0;
+ uint64_t ts = 0, ts_start;
while (st->run) {
uint64_t now;
+ uint64_t timestamp;
sys_msleep(2);
now = tmr_jiffies();
- if (!ts)
- ts = now;
+ if (!ts) {
+ ts = ts_start = now;
+ }
if (ts > now)
continue;
- process(st);
+ timestamp = (ts - ts_start) * VIDEO_TIMEBASE / 1000;
+
+ process(st, timestamp);
ts += 1000/st->prm.fps;
}
@@ -227,7 +234,7 @@ static int load_logo(struct vidsrc_st *st, const char *filename)
cairo_set_source_surface(st->cr_logo, logo, 0, 0);
cairo_paint(st->cr_logo);
- info("cairo: scaling logo '%s' from %d x %d to %f x %f\n",
+ info("cairo: scaling logo '%s' from %d x %d to %.1f x %.1f\n",
filename,
cairo_image_surface_get_width(logo),
cairo_image_surface_get_height(logo),
diff --git a/modules/codec2/codec2.c b/modules/codec2/codec2.c
index b6911dc..44e8e43 100644
--- a/modules/codec2/codec2.c
+++ b/modules/codec2/codec2.c
@@ -123,7 +123,7 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *aes, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc)
+ size_t *len, int fmt, const void *sampv, size_t sampc)
{
if (!buf || !len || !sampv)
return EINVAL;
@@ -133,6 +133,9 @@ static int encode(struct auenc_state *aes, uint8_t *buf,
if (sampc != (size_t)codec2_samples_per_frame(aes->c2))
return EPROTO;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
codec2_encode(aes->c2, buf, (short *)sampv);
*len = codec2_bits_per_frame(aes->c2)/8;
@@ -141,7 +144,7 @@ static int encode(struct auenc_state *aes, uint8_t *buf,
}
-static int decode(struct audec_state *ads, int16_t *sampv,
+static int decode(struct audec_state *ads, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
if (!sampv || !sampc || !buf)
@@ -152,6 +155,9 @@ static int decode(struct audec_state *ads, int16_t *sampv,
if (len < (size_t)codec2_bits_per_frame(ads->c2)/8)
return EPROTO;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
codec2_decode(ads->c2, sampv, buf);
*sampc = codec2_samples_per_frame(ads->c2);
diff --git a/modules/ctrl_tcp/ctrl_tcp.c b/modules/ctrl_tcp/ctrl_tcp.c
new file mode 100644
index 0000000..713f9f4
--- /dev/null
+++ b/modules/ctrl_tcp/ctrl_tcp.c
@@ -0,0 +1,377 @@
+/**
+ * @file ctrl_tcp.c TCP control interface using JSON payload
+ *
+ * Copyright (C) 2018 46 Labs LLC
+ */
+
+#include <re.h>
+#include <baresip.h>
+
+#include "tcp_netstring.h"
+
+
+/**
+ * @defgroup ctrl_tcp ctrl_tcp
+ *
+ * Communication channel to control and monitor Baresip via JSON messages.
+ *
+ * It receives commands to be executed, sends back command responses and
+ * notifies about events.
+ *
+ * Command message parameters:
+ *
+ * - command : Command to be executed.
+ * - params : Command parameters.
+ * - token : Optional. Included in the response if present.
+ *
+ * Command message example:
+ *
+ \verbatim
+ {
+ "command" : "dial",
+ "params" : "sip:alice@atlanta.com",
+ "token" : "qwerasdf"
+ }
+ \endverbatim
+ *
+ *
+ * Response message parameters:
+ *
+ * - response : true. Identifies the message type.
+ * - ok: : true/false. Indicates whether the command execution succeeded.
+ * - data : Baresip response to the related command execution.
+ * - token : Present if it was included in the related command request.
+ *
+ * Response message example:
+ *
+ \verbatim
+ {
+ "response" : true,
+ "ok" : true,
+ "data" : "",
+ "token" : "qwerasdf"
+ }
+ \endverbatim
+ *
+ *
+ * Event message parameters:
+ *
+ * - event : true. Identifies the message type.
+ * - class : Event class.
+ * - type : Event ID.
+ * - param : Specific event information.
+ *
+ * Apart from the above, events may contain aditional parameters.
+ *
+ * Event message example:
+ *
+ \verbatim
+ {
+ "event" : "true",
+ "class" : "call",
+ "type" : "CALL_CLOSED",
+ "param" : "Connection reset by peer",
+ "accountaor" : "sip:alice@atlanta.com",
+ "direction" : "incoming",
+ "peeruri" : "sip:bob@biloxy.com",
+ "id" : "73a12546589651f8"
+ }
+ \endverbatim
+ *
+ *
+ * Sample config:
+ *
+ \verbatim
+ ctrl_tcp_listen 0.0.0.0:4444 # IP-address and port to listen on
+ \endverbatim
+ */
+
+
+enum {CTRL_PORT = 4444};
+
+struct ctrl_st {
+ struct tcp_sock *ts;
+ struct tcp_conn *tc;
+ struct netstring *ns;
+};
+
+static struct ctrl_st *ctrl = NULL; /* allow only one instance */
+
+static int print_handler(const char *p, size_t size, void *arg)
+{
+ struct mbuf *mb = arg;
+
+ return mbuf_write_mem(mb, (uint8_t *)p, size);
+}
+
+
+static int encode_response(int cmd_error, struct mbuf *resp, const char *token)
+{
+ struct re_printf pf = {print_handler, resp};
+ struct odict *od = NULL;
+ char *buf = NULL;
+ char m[256];
+ int err;
+
+ /* Empty response. */
+ if (resp->pos == NETSTRING_HEADER_SIZE)
+ {
+ buf = mem_alloc(1, NULL);
+ buf[0] = '\0';
+ }
+ else
+ {
+ resp->pos = NETSTRING_HEADER_SIZE;
+ err = mbuf_strdup(resp, &buf,
+ resp->end - NETSTRING_HEADER_SIZE);
+ if (err)
+ return err;
+ }
+
+ err = odict_alloc(&od, 8);
+ if (err)
+ return err;
+
+ err |= odict_entry_add(od, "response", ODICT_BOOL, true);
+ err |= odict_entry_add(od, "ok", ODICT_BOOL, (bool)!cmd_error);
+
+ if (cmd_error && str_len(buf) == 0)
+ err |= odict_entry_add(od, "data", ODICT_STRING,
+ str_error(cmd_error, m, sizeof(m)));
+ else
+ err |= odict_entry_add(od, "data", ODICT_STRING, buf);
+
+ if (token)
+ err |= odict_entry_add(od, "token", ODICT_STRING, token);
+
+ if (err)
+ goto out;
+
+ mbuf_reset(resp);
+ mbuf_init(resp);
+ resp->pos = NETSTRING_HEADER_SIZE;
+
+ err = json_encode_odict(&pf, od);
+ if (err)
+ warning("ctrl_tcp: failed to encode response JSON (%m)\n",
+ err);
+
+ out:
+ mem_deref(buf);
+ mem_deref(od);
+
+ return err;
+}
+
+
+static bool command_handler(struct mbuf *mb, void *arg)
+{
+ struct ctrl_st *st = arg;
+ struct mbuf *resp = mbuf_alloc(2048);
+ struct re_printf pf = {print_handler, resp};
+ struct odict *od = NULL;
+ const struct odict_entry *oe_cmd, *oe_prm, *oe_tok;
+ char buf[256];
+ int err;
+
+ err = json_decode_odict(&od, 32, (const char*)mb->buf, mb->end, 16);
+ if (err) {
+ warning("ctrl_tcp: failed to decode JSON (%m)\n", err);
+ goto out;
+ }
+
+ oe_cmd = odict_lookup(od, "command");
+ oe_prm = odict_lookup(od, "params");
+ oe_tok = odict_lookup(od, "token");
+ if (!oe_cmd) {
+ warning("ctrl_tcp: missing json entries\n");
+ goto out;
+ }
+
+ debug("ctrl_tcp: handle_command: cmd='%s', params:'%s', token='%s'\n",
+ oe_cmd ? oe_cmd->u.str : "",
+ oe_prm ? oe_prm->u.str : "",
+ oe_tok ? oe_tok->u.str : "");
+
+ re_snprintf(buf, sizeof(buf), "%s%s%s",
+ oe_cmd->u.str,
+ oe_prm ? " " : "",
+ oe_prm ? oe_prm->u.str : "");
+
+ resp->pos = NETSTRING_HEADER_SIZE;
+
+ /* Relay message to long commands */
+ err = cmd_process_long(baresip_commands(),
+ buf,
+ str_len(buf),
+ &pf, NULL);
+ if (err) {
+ warning("ctrl_tcp: error processing command (%m)\n", err);
+ }
+
+ err = encode_response(err, resp, oe_tok ? oe_tok->u.str : NULL);
+ if (err) {
+ warning("ctrl_tcp: failed to encode response (%m)\n", err);
+ goto out;
+ }
+
+ resp->pos = NETSTRING_HEADER_SIZE;
+ err = tcp_send(st->tc, resp);
+ if (err) {
+ warning("ctrl_tcp: failed to send the message (%m)\n", err);
+ }
+
+ out:
+ mem_deref(resp);
+ mem_deref(od);
+
+ return true; /* always handled */
+}
+
+
+static void tcp_close_handler(int err, void *arg)
+{
+ struct ctrl_st *st = arg;
+
+ (void)err;
+
+ st->tc = mem_deref(st->tc);
+}
+
+
+static void tcp_conn_handler(const struct sa *peer, void *arg)
+{
+ struct ctrl_st *st = arg;
+
+ (void)peer;
+
+ /* only one connection allowed */
+ st->tc = mem_deref(st->tc);
+ st->ns = mem_deref(st->ns);
+
+ (void)tcp_accept(&st->tc, st->ts, NULL, NULL, tcp_close_handler, st);
+ (void)netstring_insert(&st->ns, st->tc, 0, command_handler, st);
+}
+
+
+/*
+ * Relay UA events
+ */
+static void ua_event_handler(struct ua *ua, enum ua_event ev,
+ struct call *call, const char *prm, void *arg)
+{
+ struct ctrl_st *st = arg;
+ struct mbuf *buf = mbuf_alloc(1024);
+ struct re_printf pf = {print_handler, buf};
+ struct odict *od = NULL;
+ int err;
+
+ buf->pos = NETSTRING_HEADER_SIZE;
+
+ err = odict_alloc(&od, 8);
+ if (err)
+ return;
+
+ err = odict_entry_add(od, "event", ODICT_BOOL, true);
+ err |= event_encode_dict(od, ua, ev, call, prm);
+ if (err)
+ goto out;
+
+ err = json_encode_odict(&pf, od);
+ if (err) {
+ warning("ctrl_tcp: failed to encode json (%m)\n", err);
+ goto out;
+ }
+
+ if (st->tc) {
+ buf->pos = NETSTRING_HEADER_SIZE;
+ err = tcp_send(st->tc, buf);
+ if (err) {
+ warning("ctrl_tcp: failed to send the message (%m)\n",
+ err);
+ }
+ }
+
+ out:
+ mem_deref(buf);
+ mem_deref(od);
+}
+
+
+static void ctrl_destructor(void *arg)
+{
+ struct ctrl_st *st = arg;
+
+ mem_deref(st->tc);
+ mem_deref(st->ts);
+ mem_deref(st->ns);
+}
+
+
+static int ctrl_alloc(struct ctrl_st **stp, const struct sa *laddr)
+{
+ struct ctrl_st *st;
+ int err;
+
+ if (!stp)
+ return EINVAL;
+
+ st = mem_zalloc(sizeof(*st), ctrl_destructor);
+ if (!st)
+ return ENOMEM;
+
+ err = tcp_listen(&st->ts, laddr, tcp_conn_handler, st);
+ if (err) {
+ warning("ctrl_tcp: failed to listen on TCP %J (%m)\n",
+ laddr, err);
+ goto out;
+ }
+
+ debug("ctrl_tcp: TCP socket listening on %J\n", laddr);
+
+ out:
+ if (err)
+ mem_deref(st);
+ else
+ *stp = st;
+
+ return err;
+}
+
+
+static int ctrl_init(void)
+{
+ struct sa laddr;
+ int err;
+
+ if (conf_get_sa(conf_cur(), "ctrl_tcp_listen", &laddr)) {
+ sa_set_str(&laddr, "0.0.0.0", CTRL_PORT);
+ }
+
+ err = ctrl_alloc(&ctrl, &laddr);
+ if (err)
+ return err;
+
+ err = uag_event_register(ua_event_handler, ctrl);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+static int ctrl_close(void)
+{
+ uag_event_unregister(ua_event_handler);
+ ctrl = mem_deref(ctrl);
+
+ return 0;
+}
+
+
+const struct mod_export DECL_EXPORTS(ctrl_tcp) = {
+ "ctrl_tcp",
+ "application",
+ ctrl_init,
+ ctrl_close
+};
diff --git a/modules/ctrl_tcp/module.mk b/modules/ctrl_tcp/module.mk
new file mode 100644
index 0000000..cf6f0f3
--- /dev/null
+++ b/modules/ctrl_tcp/module.mk
@@ -0,0 +1,10 @@
+#
+# module.mk
+#
+# Copyright (C) 2018 46 Labs LLC
+#
+
+MOD := ctrl_tcp
+$(MOD)_SRCS += ctrl_tcp.c tcp_netstring.c ./netstring/netstring.c
+
+include mk/mod.mk
diff --git a/modules/ctrl_tcp/netstring/netstring.c b/modules/ctrl_tcp/netstring/netstring.c
new file mode 100644
index 0000000..0309872
--- /dev/null
+++ b/modules/ctrl_tcp/netstring/netstring.c
@@ -0,0 +1,164 @@
+/* Streaming API for netstrings. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <re.h>
+#include "netstring.h"
+
+
+const char* netstring_error_str(netstring_error err)
+{
+ switch (err) {
+ case NETSTRING_ERROR_TOO_LONG:
+ return "NETSTRING_ERROR_TOO_LONG";
+ case NETSTRING_ERROR_NO_COLON:
+ return "NETSTRING_ERROR_NO_COLON";
+ case NETSTRING_ERROR_TOO_SHORT:
+ return "NETSTRING_ERROR_TOO_SHORT";
+ case NETSTRING_ERROR_NO_COMMA:
+ return "NETSTRING_ERROR_NO_COMMA";
+ case NETSTRING_ERROR_LEADING_ZERO:
+ return "NETSTRING_ERROR_LEADING_ZERO";
+ case NETSTRING_ERROR_NO_LENGTH:
+ return "NETSTRING_ERROR_NO_LENGTH";
+ default:
+ return "NETSTRING_ERROR_UNKNOWN";
+ }
+}
+
+
+/**
+ * Reads a netstring from a `buffer` of length `buffer_length`. Writes
+ * to `netstring_start` a pointer to the beginning of the string in
+ * the buffer, and to `netstring_length` the length of the
+ * string. Does not allocate any memory. If it reads successfully,
+ * then it returns 0. If there is an error, then the return value will
+ * be negative. The error values are:
+
+ * NETSTRING_ERROR_TOO_LONG More than 999999999 bytes in a field
+ * NETSTRING_ERROR_NO_COLON No colon was found after the number
+ * NETSTRING_ERROR_TOO_SHORT Number of bytes greater than buffer length
+ * NETSTRING_ERROR_NO_COMMA No comma was found at the end
+ * NETSTRING_ERROR_LEADING_ZERO Leading zeros are not allowed
+ * NETSTRING_ERROR_NO_LENGTH Length not given at start of netstring
+
+ * If you're sending messages with more than 999999999 bytes -- about
+ * 2 GB -- then you probably should not be doing so in the form of a
+ * single netstring. This restriction is in place partially to protect
+ * from malicious or erroneous input, and partly to be compatible with
+ * D. J. Bernstein's reference implementation.
+
+ * Example:
+ * if (netstring_read("3:foo,", 6, &str, &len) < 0) explode_and_die();
+ */
+int netstring_read(char *buffer, size_t buffer_length,
+ char **netstring_start, size_t *netstring_length)
+{
+ size_t i;
+ size_t len = 0;
+
+ /* Write default values for outputs */
+ *netstring_start = NULL; *netstring_length = 0;
+
+ /* Make sure buffer is big enough. Minimum size is 3. */
+ if (buffer_length < 3)
+ return NETSTRING_ERROR_TOO_SHORT;
+
+ /* No leading zeros allowed! */
+ if (buffer[0] == '0' && isdigit(buffer[1]))
+ return NETSTRING_ERROR_LEADING_ZERO;
+
+ /* The netstring must start with a number */
+ if (!isdigit(buffer[0]))
+ return NETSTRING_ERROR_NO_LENGTH;
+
+ /* Read the number of bytes */
+ for (i = 0; i < buffer_length && isdigit(buffer[i]); i++) {
+
+ /* Error if more than 9 digits */
+ if (i >= 9)
+ return NETSTRING_ERROR_TOO_LONG;
+
+ /* Accumulate each digit, assuming ASCII. */
+ len = len*10 + (buffer[i] - '0');
+ }
+
+ /**
+ * Check buffer length. The buffer must be longer than the sum of:
+ * - the number we've read.
+ * - the length of the string itself.
+ * - the colon.
+ * - the comma.
+ */
+ if (i + len + 1 >= buffer_length)
+ return NETSTRING_ERROR_TOO_SHORT;
+
+ /* Read the colon */
+ if (buffer[i++] != ':')
+ return NETSTRING_ERROR_NO_COLON;
+
+ /* Test for the trailing comma, and set the return values */
+ if (buffer[i + len] != ',')
+ return NETSTRING_ERROR_NO_COMMA;
+
+ *netstring_start = &buffer[i]; *netstring_length = len;
+
+ return 0;
+}
+
+/**
+ * Return the number of digits represented in the given number.
+ * We are assuming that the input is not bigger than NETSTRING_MAX_SIZE.
+ */
+size_t netstring_num_len(size_t num)
+{
+ char num_str[32];
+
+ re_snprintf(num_str, sizeof(num_str), "%zu", num);
+
+ return strlen(num_str);
+}
+
+/**
+ * Return the length, in ASCII characters, of a netstring containing
+ * `data_length` bytes.
+ */
+size_t netstring_buffer_size(size_t data_length)
+{
+ if (data_length == 0)
+ return 3;
+
+ return netstring_num_len(data_length) + data_length + 2;
+}
+
+/*
+ * Allocate and create a netstring containing the first `len` bytes of `data`.
+ * This must be manually freed by the client.
+ * If `len` is 0 then no data will be read from `data`, and it may be NULL.
+ */
+size_t netstring_encode_new(char **netstring, char *data, size_t len)
+{
+ char *ns;
+ size_t num_len = 1;
+
+ if (len == 0) {
+ ns = malloc(3);
+ ns[0] = '0';
+ ns[1] = ':';
+ ns[2] = ',';
+ }
+ else {
+ num_len = netstring_num_len(len);
+ ns = malloc(num_len + len + 2);
+ sprintf(ns, "%lu:", (unsigned long)len);
+ memcpy(ns + num_len + 1, data, len);
+ ns[num_len + len + 1] = ',';
+ }
+
+ *netstring = ns;
+
+ return num_len + len + 2;
+}
diff --git a/modules/ctrl_tcp/netstring/netstring.h b/modules/ctrl_tcp/netstring/netstring.h
new file mode 100644
index 0000000..a084428
--- /dev/null
+++ b/modules/ctrl_tcp/netstring/netstring.h
@@ -0,0 +1,28 @@
+#ifndef __NETSTRING_STREAM_H
+#define __NETSTRING_STREAM_H
+
+#include <string.h>
+
+const char* netstring_error_str(int err);
+
+int netstring_read(char *buffer, size_t buffer_length,
+ char **netstring_start, size_t *netstring_length);
+
+size_t netstring_num_len(size_t num);
+size_t netstring_buffer_size(size_t data_length);
+
+size_t netstring_encode_new(char **netstring, char *data, size_t len);
+
+#define NETSTRING_MAX_SIZE 999999999
+
+/* Errors that can occur during netstring parsing */
+typedef enum {
+ NETSTRING_ERROR_TOO_LONG = -100,
+ NETSTRING_ERROR_NO_COLON,
+ NETSTRING_ERROR_TOO_SHORT,
+ NETSTRING_ERROR_NO_COMMA,
+ NETSTRING_ERROR_LEADING_ZERO,
+ NETSTRING_ERROR_NO_LENGTH
+} netstring_error;
+
+#endif
diff --git a/modules/ctrl_tcp/tcp_netstring.c b/modules/ctrl_tcp/tcp_netstring.c
new file mode 100644
index 0000000..2ad4742
--- /dev/null
+++ b/modules/ctrl_tcp/tcp_netstring.c
@@ -0,0 +1,221 @@
+/**
+ * @file tcp_netstring.c TCP netstring framing
+ *
+ * Copyright (C) 2018 46 Labs LLC
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include <re_types.h>
+#include <re_fmt.h>
+#include <re_mem.h>
+#include <re_mbuf.h>
+#include <re_tcp.h>
+#include <re_net.h>
+
+#include "tcp_netstring.h"
+#include "netstring/netstring.h"
+
+
+#define DEBUG_MODULE "tcp_netstring"
+#define DEBUG_LEVEL 5
+#include <re_dbg.h>
+
+
+struct netstring {
+ struct tcp_conn *tc;
+ struct tcp_helper *th;
+ struct mbuf *mb;
+ netstring_frame_h *frameh;
+ void *arg;
+
+ uint64_t n_tx;
+ uint64_t n_rx;
+};
+
+
+/* responsible for adding the netstring header
+ - assumes that the sent MBUF contains a complete packet
+ */
+static bool netstring_send_handler(int *err, struct mbuf *mb, void *arg)
+{
+ struct netstring *netstring = arg;
+ size_t num_len;
+ char num_str[32];
+
+ if (mb->pos < NETSTRING_HEADER_SIZE) {
+ DEBUG_WARNING("send: not enough space for netstring header\n");
+ *err = ENOMEM;
+ return true;
+ }
+
+ if (mbuf_get_left(mb) > NETSTRING_MAX_SIZE) {
+ DEBUG_WARNING("send: buffer exceeds max size\n");
+ *err = EMSGSIZE;
+ return true;
+ }
+
+ /* Build the netstring. */
+ if (mbuf_get_left(mb) == 0) {
+ mb->buf[0] = '0';
+ mb->buf[1] = ':';
+ mb->buf[2] = ',';
+
+ mb->end += 3;
+
+ return false;
+ }
+
+ re_snprintf(num_str, sizeof(num_str), "%zu", mbuf_get_left(mb));
+ num_len = strlen(num_str);
+
+ mb->pos = NETSTRING_HEADER_SIZE - (num_len + 1);
+ mbuf_write_mem(mb, (uint8_t*) num_str, num_len);
+ mb->pos = NETSTRING_HEADER_SIZE - (num_len + 1);
+ mb->buf[mb->pos + num_len] = ':';
+ mb->buf[mb->end] = ',';
+
+ mb->end += 1;
+
+ ++netstring->n_tx;
+
+ return false;
+}
+
+
+static bool netstring_recv_handler(int *errp, struct mbuf *mbx, bool *estab,
+ void *arg)
+{
+ struct netstring *netstring = arg;
+ int err = 0;
+ size_t pos = 0;
+ (void)estab;
+
+ /* handle re-assembly */
+ if (!netstring->mb) {
+ netstring->mb = mbuf_alloc(1024);
+ if (!netstring->mb) {
+ *errp = ENOMEM;
+ return true;
+ }
+ }
+
+ pos = netstring->mb->pos;
+
+ netstring->mb->pos = netstring->mb->end;
+
+ err = mbuf_write_mem(netstring->mb, mbuf_buf(mbx),
+ mbuf_get_left(mbx));
+ if (err)
+ goto out;
+
+ netstring->mb->pos = pos;
+
+ /* extract all NETSTRING-frames in the TCP-stream */
+ for (;;) {
+
+ size_t len, end;
+ struct mbuf mb;
+
+ if (mbuf_get_left(netstring->mb) < (3))
+ break;
+
+ err = netstring_read((char*)netstring->mb->buf,
+ netstring->mb->end,
+ (char**)&mb.buf, &len);
+ if (err) {
+
+ if (err == NETSTRING_ERROR_TOO_SHORT) {
+ DEBUG_INFO("receive: %s\n",
+ netstring_error_str(err));
+ }
+
+ else {
+ DEBUG_WARNING("receive: %s\n",
+ netstring_error_str(err));
+ netstring->mb = mem_deref(netstring->mb);
+ }
+
+ return false;
+ }
+
+ pos = netstring->mb->pos;
+ end = netstring->mb->end;
+
+ netstring->mb->end = pos + len;
+
+ ++netstring->n_rx;
+
+ netstring->frameh(&mb, netstring->arg);
+
+ netstring->mb->pos = pos + netstring_buffer_size(len);
+ netstring->mb->end = end;
+
+ if (netstring->mb->pos >= netstring->mb->end) {
+ netstring->mb = mem_deref(netstring->mb);
+ break;
+ }
+
+ continue;
+ }
+
+ out:
+ if (err)
+ *errp = err;
+
+ return true; /* always handled */
+}
+
+
+static void destructor(void *arg)
+{
+ struct netstring *netstring = arg;
+
+ mem_deref(netstring->th);
+ mem_deref(netstring->tc);
+ mem_deref(netstring->mb);
+}
+
+
+int netstring_insert(struct netstring **netstringp, struct tcp_conn *tc,
+ int layer, netstring_frame_h *frameh, void *arg)
+{
+ struct netstring *netstring;
+ int err;
+
+ if (!netstringp || !tc || !frameh)
+ return EINVAL;
+
+ netstring = mem_zalloc(sizeof(*netstring), destructor);
+ if (!netstring)
+ return ENOMEM;
+
+ netstring->tc = mem_ref(tc);
+ err = tcp_register_helper(&netstring->th, tc, layer, NULL,
+ netstring_send_handler,
+ netstring_recv_handler, netstring);
+ if (err)
+ goto out;
+
+ netstring->frameh = frameh;
+ netstring->arg = arg;
+
+ out:
+ if (err)
+ mem_deref(netstring);
+ else
+ *netstringp = netstring;
+
+ return err;
+}
+
+
+int netstring_debug(struct re_printf *pf, const struct netstring *netstring)
+{
+ if (!netstring)
+ return 0;
+
+ return re_hprintf(pf, "tx=%llu, rx=%llu",
+ netstring->n_tx, netstring->n_rx);
+}
diff --git a/modules/ctrl_tcp/tcp_netstring.h b/modules/ctrl_tcp/tcp_netstring.h
new file mode 100644
index 0000000..8195217
--- /dev/null
+++ b/modules/ctrl_tcp/tcp_netstring.h
@@ -0,0 +1,16 @@
+/**
+ * @file tcp_netstring.h TCP netstring framing
+ *
+ * Copyright (C) 2018 46 Labs LLC
+ */
+
+enum {NETSTRING_HEADER_SIZE = 10};
+
+struct netstring;
+
+typedef bool (netstring_frame_h)(struct mbuf *mb, void *arg);
+
+
+int netstring_insert(struct netstring **netstringp, struct tcp_conn *tc,
+ int layer, netstring_frame_h *frameh, void *arg);
+int netstring_debug(struct re_printf *pf, const struct netstring *netstring);
diff --git a/modules/dshow/dshow.cpp b/modules/dshow/dshow.cpp
index d081f69..46aef3e 100644
--- a/modules/dshow/dshow.cpp
+++ b/modules/dshow/dshow.cpp
@@ -99,12 +99,13 @@ public:
STDMETHOD(BufferCB) (double sample_time, BYTE *buf, long buf_len)
{
struct vidframe vidframe;
+ uint64_t timestamp = sample_time * VIDEO_TIMEBASE;
/* XXX: should be VID_FMT_BGR24 */
vidframe_init_buf(&vidframe, VID_FMT_RGB32, &src->size, buf);
if (src->frameh)
- src->frameh(&vidframe, src->arg);
+ src->frameh(&vidframe, timestamp, src->arg);
return S_OK;
}
diff --git a/modules/fakevideo/fakevideo.c b/modules/fakevideo/fakevideo.c
index e0552d6..dcbd0e5 100644
--- a/modules/fakevideo/fakevideo.c
+++ b/modules/fakevideo/fakevideo.c
@@ -31,9 +31,14 @@
struct vidsrc_st {
const struct vidsrc *vs; /* inheritance */
struct vidframe *frame;
+#ifdef HAVE_PTHREAD
pthread_t thread;
bool run;
- int fps;
+#else
+ struct tmr tmr;
+#endif
+ uint64_t ts;
+ double fps;
vidsrc_frame_h *frameh;
void *arg;
};
@@ -47,35 +52,63 @@ static struct vidsrc *vidsrc;
static struct vidisp *vidisp;
+static void process_frame(struct vidsrc_st *st)
+{
+ st->ts += (VIDEO_TIMEBASE / st->fps);
+
+ st->frameh(st->frame, st->ts, st->arg);
+}
+
+
+#ifdef HAVE_PTHREAD
static void *read_thread(void *arg)
{
struct vidsrc_st *st = arg;
- uint64_t ts = tmr_jiffies();
+
+ st->ts = tmr_jiffies_usec();
while (st->run) {
- if (tmr_jiffies() < ts) {
+ if (tmr_jiffies_usec() < st->ts) {
sys_msleep(4);
continue;
}
- st->frameh(st->frame, st->arg);
-
- ts += (1000/st->fps);
+ process_frame(st);
}
return NULL;
}
+#else
+static void tmr_handler(void *arg)
+{
+ struct vidsrc_st *st = arg;
+ const uint64_t now = tmr_jiffies_usec();
+
+ tmr_start(&st->tmr, 4, tmr_handler, st);
+
+ if (!st->ts)
+ st->ts = now;
+
+ if (now >= st->ts) {
+ process_frame(st);
+ }
+}
+#endif
static void src_destructor(void *arg)
{
struct vidsrc_st *st = arg;
+#ifdef HAVE_PTHREAD
if (st->run) {
st->run = false;
pthread_join(st->thread, NULL);
}
+#else
+ tmr_cancel(&st->tmr);
+#endif
mem_deref(st->frame);
}
@@ -95,6 +128,7 @@ static int src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
vidsrc_error_h *errorh, void *arg)
{
struct vidsrc_st *st;
+ unsigned x;
int err;
(void)ctx;
@@ -118,12 +152,31 @@ static int src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
if (err)
goto out;
+ /* Pattern of three vertical bars in RGB */
+ for (x=0; x<size->w; x++) {
+
+ uint8_t r=0, g=0, b=0;
+
+ if (x < size->w/3)
+ r = 255;
+ else if (x < size->w*2/3)
+ g = 255;
+ else
+ b = 255;
+
+ vidframe_draw_vline(st->frame, x, 0, size->h, r, g, b);
+ }
+
+#ifdef HAVE_PTHREAD
st->run = true;
err = pthread_create(&st->thread, NULL, read_thread, st);
if (err) {
st->run = false;
goto out;
}
+#else
+ tmr_start(&st->tmr, 1, tmr_handler, st);
+#endif
out:
if (err)
diff --git a/modules/g711/g711.c b/modules/g711/g711.c
index 7c01b61..e72f117 100644
--- a/modules/g711/g711.c
+++ b/modules/g711/g711.c
@@ -17,8 +17,10 @@
static int pcmu_encode(struct auenc_state *aes, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc)
+ size_t *len, int fmt, const void *sampv, size_t sampc)
{
+ const int16_t *p = sampv;
+
(void)aes;
if (!buf || !len || !sampv)
@@ -27,18 +29,23 @@ static int pcmu_encode(struct auenc_state *aes, uint8_t *buf,
if (*len < sampc)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*len = sampc;
while (sampc--)
- *buf++ = g711_pcm2ulaw(*sampv++);
+ *buf++ = g711_pcm2ulaw(*p++);
return 0;
}
-static int pcmu_decode(struct audec_state *ads, int16_t *sampv,
+static int pcmu_decode(struct audec_state *ads, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
+ int16_t *p = sampv;
+
(void)ads;
if (!sampv || !sampc || !buf)
@@ -47,18 +54,23 @@ static int pcmu_decode(struct audec_state *ads, int16_t *sampv,
if (*sampc < len)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*sampc = len;
while (len--)
- *sampv++ = g711_ulaw2pcm(*buf++);
+ *p++ = g711_ulaw2pcm(*buf++);
return 0;
}
static int pcma_encode(struct auenc_state *aes, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc)
+ size_t *len, int fmt, const void *sampv, size_t sampc)
{
+ const int16_t *p = sampv;
+
(void)aes;
if (!buf || !len || !sampv)
@@ -67,18 +79,23 @@ static int pcma_encode(struct auenc_state *aes, uint8_t *buf,
if (*len < sampc)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*len = sampc;
while (sampc--)
- *buf++ = g711_pcm2alaw(*sampv++);
+ *buf++ = g711_pcm2alaw(*p++);
return 0;
}
-static int pcma_decode(struct audec_state *ads, int16_t *sampv,
+static int pcma_decode(struct audec_state *ads, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
+ int16_t *p = sampv;
+
(void)ads;
if (!sampv || !sampc || !buf)
@@ -87,10 +104,13 @@ static int pcma_decode(struct audec_state *ads, int16_t *sampv,
if (*sampc < len)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*sampc = len;
while (len--)
- *sampv++ = g711_alaw2pcm(*buf++);
+ *p++ = g711_alaw2pcm(*buf++);
return 0;
}
diff --git a/modules/g722/g722.c b/modules/g722/g722.c
index 16d1f98..dd2a943 100644
--- a/modules/g722/g722.c
+++ b/modules/g722/g722.c
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
#include <re.h>
+#include <rem_au.h>
#include <baresip.h>
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES 1
#include <spandsp.h>
@@ -125,10 +126,13 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
int n;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
n = g722_encode(&st->enc, buf, sampv, (int)sampc);
if (n <= 0) {
return EPROTO;
@@ -143,7 +147,7 @@ static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
}
-static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
+static int decode(struct audec_state *st, int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
int n;
@@ -151,6 +155,9 @@ static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
if (!st || !sampv || !buf)
return EINVAL;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
n = g722_decode(&st->dec, sampv, buf, (int)len);
if (n < 0)
return EPROTO;
diff --git a/modules/g7221/decode.c b/modules/g7221/decode.c
index 0f7155f..298a8ae 100644
--- a/modules/g7221/decode.c
+++ b/modules/g7221/decode.c
@@ -48,7 +48,8 @@ int g7221_decode_update(struct audec_state **adsp, const struct aucodec *ac,
}
-int g7221_decode(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+int g7221_decode(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
size_t framec;
diff --git a/modules/g7221/encode.c b/modules/g7221/encode.c
index 8345f5f..8dec82f 100644
--- a/modules/g7221/encode.c
+++ b/modules/g7221/encode.c
@@ -50,7 +50,7 @@ int g7221_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
int g7221_encode(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
size_t framec;
diff --git a/modules/g7221/g7221.h b/modules/g7221/g7221.h
index 635fc01..2c16d4c 100644
--- a/modules/g7221/g7221.h
+++ b/modules/g7221/g7221.h
@@ -13,13 +13,14 @@ struct g7221_aucodec {
int g7221_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
struct auenc_param *prm, const char *fmtp);
int g7221_encode(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc);
+ int fmt, const void *sampv, size_t sampc);
/* Decode */
int g7221_decode_update(struct audec_state **adsp, const struct aucodec *ac,
const char *fmtp);
-int g7221_decode(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+int g7221_decode(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len);
diff --git a/modules/g726/g726.c b/modules/g726/g726.c
index fd4e462..8334b84 100644
--- a/modules/g726/g726.c
+++ b/modules/g726/g726.c
@@ -5,6 +5,7 @@
*/
#include <re.h>
+#include <rem_au.h>
#include <baresip.h>
#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES 1
#include <spandsp.h>
@@ -119,11 +120,14 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *st, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc)
+ size_t *len, int fmt, const void *sampv, size_t sampc)
{
if (!buf || !len || !sampv)
return EINVAL;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
if (*len < MAX_PACKET)
return ENOMEM;
@@ -133,12 +137,15 @@ static int encode(struct auenc_state *st, uint8_t *buf,
}
-static int decode(struct audec_state *st, int16_t *sampv,
+static int decode(struct audec_state *st, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
if (!sampv || !sampc || !buf)
return EINVAL;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*sampc = g726_decode(&st->st, sampv, buf, (int)len);
return 0;
diff --git a/modules/gsm/gsm.c b/modules/gsm/gsm.c
index be225d8..da7fba7 100644
--- a/modules/gsm/gsm.c
+++ b/modules/gsm/gsm.c
@@ -5,6 +5,7 @@
*/
#include <gsm.h> /* please report if you have problems finding this file */
#include <re.h>
+#include <rem_au.h>
#include <baresip.h>
@@ -113,13 +114,16 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
if (sampc != FRAME_SIZE)
return EPROTO;
if (*len < sizeof(gsm_frame))
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
gsm_encode(st->enc, (gsm_signal *)sampv, buf);
*len = sizeof(gsm_frame);
@@ -128,7 +132,7 @@ static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
}
-static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
+static int decode(struct audec_state *st, int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
int ret;
@@ -138,6 +142,9 @@ static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
if (len < sizeof(gsm_frame))
return EBADMSG;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
ret = gsm_decode(st->dec, (gsm_byte *)buf, (gsm_signal *)sampv);
if (ret)
return EPROTO;
diff --git a/modules/gst1/gst.c b/modules/gst1/gst.c
index 380334a..a500f4c 100644
--- a/modules/gst1/gst.c
+++ b/modules/gst1/gst.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010 - 2015 Creytiv.com
*/
#define _DEFAULT_SOURCE 1
+#define _POSIX_C_SOURCE 199309L
#include <stdlib.h>
#include <string.h>
#include <time.h>
diff --git a/modules/gst_video/encode.c b/modules/gst_video/encode.c
index b6dfe8a..6377785 100644
--- a/modules/gst_video/encode.c
+++ b/modules/gst_video/encode.c
@@ -169,14 +169,14 @@ static void internal_appsink_new_buffer(GstElement *sink,
if (buffer) {
GstClockTime ts;
- uint32_t rtp_ts;
+ uint64_t rtp_ts;
guint8 *data = GST_BUFFER_DATA(buffer);
guint size = GST_BUFFER_SIZE(buffer);
ts = GST_BUFFER_TIMESTAMP(buffer);
- rtp_ts = (uint32_t)((90000ULL*ts) / 1000000000UL );
+ rtp_ts = (uint64_t)((90000ULL*ts) / 1000000000UL );
h264_packetize(rtp_ts, data, size, st->pktsize,
st->pkth, st->pkth_arg);
diff --git a/modules/gst_video1/encode.c b/modules/gst_video1/encode.c
index d0a3d44..0c3a088 100644
--- a/modules/gst_video1/encode.c
+++ b/modules/gst_video1/encode.c
@@ -123,7 +123,7 @@ static GstFlowReturn appsink_new_sample_cb(GstAppSink *sink,
if (sample) {
GstClockTime ts;
- uint32_t rtp_ts;
+ uint64_t rtp_ts;
buffer = gst_sample_get_buffer(sample);
gst_buffer_map( buffer, &info, (GstMapFlags)(GST_MAP_READ) );
@@ -139,7 +139,7 @@ static GstFlowReturn appsink_new_sample_cb(GstAppSink *sink,
}
else {
/* convert from nanoseconds to RTP clock */
- rtp_ts = (uint32_t)((90000ULL * ts) / 1000000000UL);
+ rtp_ts = (uint64_t)((90000ULL * ts) / 1000000000UL);
}
h264_packetize(rtp_ts, data, size, st->encoder.pktsize,
diff --git a/modules/h265/encode.c b/modules/h265/encode.c
index f4835a3..62b16e0 100644
--- a/modules/h265/encode.c
+++ b/modules/h265/encode.c
@@ -17,7 +17,7 @@ struct videnc_state {
x265_param *param;
x265_encoder *x265;
int64_t pts;
- unsigned fps;
+ double fps;
unsigned bitrate;
unsigned pktsize;
videnc_packet_h *pkth;
@@ -36,7 +36,7 @@ static void destructor(void *arg)
}
-static int set_params(struct videnc_state *st, unsigned fps, unsigned bitrate)
+static int set_params(struct videnc_state *st, double fps, unsigned bitrate)
{
st->param = x265_param_alloc();
if (!st->param) {
@@ -140,7 +140,7 @@ static int open_encoder(struct videnc_state *st, const struct vidsz *size)
static inline int packetize(bool marker, const uint8_t *buf, size_t len,
- size_t maxlen, uint32_t rtp_ts,
+ size_t maxlen, uint64_t rtp_ts,
videnc_packet_h *pkth, void *arg)
{
int err = 0;
@@ -195,7 +195,7 @@ int h265_encode(struct videnc_state *st, bool update,
uint32_t i, nalc = 0;
int colorspace;
int n, err = 0;
- uint32_t ts;
+ uint64_t ts;
if (!st || !frame)
return EINVAL;
diff --git a/modules/l16/l16.c b/modules/l16/l16.c
index 204a8f5..3f324c9 100644
--- a/modules/l16/l16.c
+++ b/modules/l16/l16.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010 - 2015 Creytiv.com
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
@@ -18,9 +19,10 @@ enum {NR_CODECS = 8};
static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
int16_t *p = (void *)buf;
+ const int16_t *sampv16 = sampv;
(void)st;
if (!buf || !len || !sampv)
@@ -29,19 +31,23 @@ static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
if (*len < sampc*2)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*len = sampc*2;
while (sampc--)
- *p++ = htons(*sampv++);
+ *p++ = htons(*sampv16++);
return 0;
}
-static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
+static int decode(struct audec_state *st, int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
int16_t *p = (void *)buf;
+ int16_t *sampv16 = sampv;
(void)st;
if (!buf || !len || !sampv)
@@ -50,11 +56,14 @@ static int decode(struct audec_state *st, int16_t *sampv, size_t *sampc,
if (*sampc < len/2)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*sampc = len/2;
len /= 2;
while (len--)
- *sampv++ = ntohs(*p++);
+ *sampv16++ = ntohs(*p++);
return 0;
}
diff --git a/modules/menu/menu.c b/modules/menu/menu.c
index c7f1646..aab9661 100644
--- a/modules/menu/menu.c
+++ b/modules/menu/menu.c
@@ -774,6 +774,27 @@ static int set_current_call(struct re_printf *pf, void *arg)
}
+static int set_audio_bitrate(struct re_printf *pf, void *arg)
+{
+ struct cmd_arg *carg = arg;
+ struct call *call;
+ uint32_t bitrate = atoi(carg->prm);
+ int err;
+
+ call = ua_call(uag_cur());
+ if (call) {
+ err = re_hprintf(pf, "setting audio bitrate: %u bps\n",
+ bitrate);
+ audio_set_bitrate(call_audio(call), bitrate);
+ }
+ else {
+ err = re_hprintf(pf, "call not found\n");
+ }
+
+ return err;
+}
+
+
static const struct cmd callcmdv[] = {
{"reinvite", 'I', 0, "Send re-INVITE", call_reinvite },
{"resume", 'X', 0, "Call resume", cmd_call_resume },
@@ -784,6 +805,7 @@ static const struct cmd callcmdv[] = {
{"hold", 'x', 0, "Call hold", cmd_call_hold },
{"", 'H', 0, "Hold previous call", hold_prev_call },
{"", 'L', 0, "Resume previous call",hold_prev_call },
+{"aubitrate", 0, CMD_PRM, "Set audio bitrate", set_audio_bitrate },
#ifdef USE_VIDEO
{"video_cycle", 'E', 0, "Cycle video encoder", call_videoenc_cycle },
@@ -1108,7 +1130,13 @@ static int module_init(void)
start_ticks = tmr_jiffies();
tmr_init(&tmr_alert);
- statmode = STATMODE_CALL;
+ if (0 == conf_get(conf_cur(), "statmode_default", &val) &&
+ 0 == pl_strcasecmp(&val, "off")) {
+ statmode = STATMODE_OFF;
+ }
+ else {
+ statmode = STATMODE_CALL;
+ }
err = cmd_register(baresip_commands(), cmdv, ARRAY_SIZE(cmdv));
err |= cmd_register(baresip_commands(), dialcmdv,
diff --git a/modules/mpa/decode.c b/modules/mpa/decode.c
index 4e2a720..b7aaf41 100644
--- a/modules/mpa/decode.c
+++ b/modules/mpa/decode.c
@@ -5,6 +5,7 @@
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <mpg123.h>
#include <speex/speex_resampler.h>
@@ -110,7 +111,8 @@ int mpa_decode_update(struct audec_state **adsp, const struct aucodec *ac,
}
-int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+int mpa_decode_frm(struct audec_state *ads,
+ int fmt, void *sampv_void, size_t *sampc,
const uint8_t *buf, size_t len)
{
int result, channels, encoding, i;
@@ -118,6 +120,7 @@ int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
size_t n;
spx_uint32_t intermediate_len;
spx_uint32_t out_len;
+ int16_t *sampv = sampv_void;
#ifdef DEBUG
debug("MPA dec start %d %ld\n",len, *sampc);
@@ -132,6 +135,9 @@ int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
return EPROTO;
}
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
n = 0;
result = mpg123_decode(ads->dec, buf+4, len-4,
(unsigned char*)ads->intermediate_buffer,
diff --git a/modules/mpa/encode.c b/modules/mpa/encode.c
index d13bc0a..8c8968a 100644
--- a/modules/mpa/encode.c
+++ b/modules/mpa/encode.c
@@ -5,6 +5,7 @@
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <twolame.h>
#include <string.h>
@@ -136,7 +137,7 @@ out:
int mpa_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
int n;
spx_uint32_t intermediate_len,in_len;
@@ -144,6 +145,9 @@ int mpa_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
if (!aes || !buf || !len || !sampv)
return EINVAL;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
if (aes->resampler) {
in_len = (uint32_t)sampc/2;
intermediate_len = sizeof(aes->intermediate_buffer)
diff --git a/modules/mpa/mpa.h b/modules/mpa/mpa.h
index 0db2528..170cc3c 100644
--- a/modules/mpa/mpa.h
+++ b/modules/mpa/mpa.h
@@ -24,14 +24,15 @@ struct mpa_param {
int mpa_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
struct auenc_param *prm, const char *fmtp);
int mpa_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc);
+ int fmt, const void *sampv, size_t sampc);
/* Decode */
int mpa_decode_update(struct audec_state **adsp, const struct aucodec *ac,
const char *fmtp);
-int mpa_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
- const uint8_t *buf, size_t len);
+int mpa_decode_frm(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
+ const uint8_t *buf, size_t len);
/* SDP */
void mpa_decode_fmtp(struct mpa_param *prm, const char *fmtp);
diff --git a/modules/mqtt/README.md b/modules/mqtt/README.md
index 6a86b84..ace3c36 100644
--- a/modules/mqtt/README.md
+++ b/modules/mqtt/README.md
@@ -6,7 +6,7 @@ This module implements an MQTT (Message Queue Telemetry Transport) client
for publishing and subscribing to topics.
-The module is using libmosquitto
+The module is using libmosquitto. All messages are encoded in JSON format.
Starting the MQTT broker:
@@ -19,7 +19,7 @@ $ /usr/local/sbin/mosquitto -v
Subscribing to all topics:
```
-$ mosquitto_sub -t /baresip/+
+$ mosquitto_sub -v -t /baresip/#
```
@@ -43,17 +43,16 @@ $ mosquitto_pub -t /baresip/xxx -m foo=42
## Examples
```
-/baresip/event sip:aeh@iptel.org,REGISTERING
-/baresip/event sip:aeh@iptel.org,REGISTER_OK
-/baresip/event sip:aeh@iptel.org,SHUTDOWN
+/baresip/event {"type":"REGISTERING","class":"register","accountaor":"sip:aeh@iptel.org"}
+/baresip/event {"type":"REGISTER_OK","class":"register","accountaor":"sip:aeh@iptel.org","param":"200 OK"}
+/baresip/event {"type":"SHUTDOWN","class":"application","accountaor":"sip:aeh@iptel.org"}
```
```
mosquitto_pub -t /baresip/command -m "/dial music"
-/baresip/command /dial music
-/baresip/command_resp (null)
-/baresip/event sip:aeh@iptel.org,CALL_ESTABLISHED
-/baresip/event sip:aeh@iptel.org,CALL_CLOSED
+/baresip/command {"command":"dial","params":"music","token":"123"}
+/baresip/command_resp/123 (null)
+/baresip/event {"type":"CALL_ESTABLISHED","class":"call","accountaor":"sip:aeh@iptel.org","direction":"outgoing","peeruri":"sip:music@iptel.org","id":"4d758140c42c5d55","param":"sip:music@iptel.org"}
+/baresip/event {"type":"CALL_CLOSED","class":"call","accountaor":"sip:aeh@iptel.org","direction":"outgoing","peeruri":"sip:music@iptel.org","id":"4d758140c42c5d55","param":"Connection reset by user"}
```
-
diff --git a/modules/omx/module.c b/modules/omx/module.c
index a5b6fa8..1580f75 100644
--- a/modules/omx/module.c
+++ b/modules/omx/module.c
@@ -38,7 +38,7 @@ static void destructor(void *arg)
}
-int omx_vidisp_alloc(struct vidisp_st **vp, const struct vidisp* vd,
+int omx_vidisp_alloc(struct vidisp_st **vp, const struct vidisp *vd,
struct vidisp_prm *prm, const char *dev,
vidisp_resize_h *resizeh, void *arg)
{
diff --git a/modules/omx/module.mk b/modules/omx/module.mk
index 958a1a5..c7a796d 100644
--- a/modules/omx/module.mk
+++ b/modules/omx/module.mk
@@ -9,10 +9,11 @@ $(MOD)_SRCS += omx.c module.c
ifneq ($(USE_OMX_RPI),)
$(MOD)_CFLAGS := -DRASPBERRY_PI -DOMX_SKIP64BIT \
- -I/usr/local/include/interface/vmcs_host/linux/ \
- -I /usr/local/include/interface/vcos/pthreads/ \
- -I /opt/vc/include -I /opt/vc/include/interface/vmcs_host/linux \
- -I /opt/vc/include/interface/vcos/pthreads
+ -isystem /usr/local/include/interface/vmcs_host/linux/ \
+ -isystem /usr/local/include/interface/vcos/pthreads/ \
+ -isystem /opt/vc/include \
+ -isystem /opt/vc/include/interface/vmcs_host/linux \
+ -isystem /opt/vc/include/interface/vcos/pthreads
$(MOD)_LFLAGS += -lvcos -lbcm_host -lopenmaxil -L /opt/vc/lib
endif
diff --git a/modules/omx/omx.c b/modules/omx/omx.c
index 6b08d19..8a03822 100644
--- a/modules/omx/omx.c
+++ b/modules/omx/omx.c
@@ -5,6 +5,8 @@
* Copyright (C) 2016 - 2017 Jonathan Sieber
*/
+#define _POSIX_C_SOURCE 199309L
+
#include "omx.h"
#include <re.h>
@@ -19,6 +21,11 @@
#include <time.h>
#include <sys/time.h>
+#ifdef RASPBERRY_PI
+#include <bcm_host.h>
+#endif
+
+
/**
* @defgroup omx omx
*
@@ -109,9 +116,10 @@ static struct OMX_CALLBACKTYPE callbacks = {
};
-int omx_init(struct omx_state* st)
+int omx_init(struct omx_state *st)
{
OMX_ERRORTYPE err;
+
#ifdef RASPBERRY_PI
bcm_host_init();
#endif
@@ -128,11 +136,11 @@ int omx_init(struct omx_state* st)
#endif
if (!st->video_render || err != 0) {
- warning("Failed to create OMX video_render component\n");
+ warning("omx: Failed to create OMX video_render component\n");
return ENOENT;
}
else {
- info("created video_render component\n");
+ info("omx: created video_render component\n");
return 0;
}
}
@@ -153,8 +161,11 @@ static void block_until_state_changed(OMX_HANDLETYPE hComponent,
}
-void omx_deinit(struct omx_state* st)
+void omx_deinit(struct omx_state *st)
{
+ if (!st)
+ return;
+
info("omx_deinit");
OMX_SendCommand(st->video_render,
OMX_CommandStateSet, OMX_StateIdle, NULL);
@@ -167,13 +178,15 @@ void omx_deinit(struct omx_state* st)
}
-void omx_display_disable(struct omx_state* st)
+void omx_display_disable(struct omx_state *st)
{
- (void)st;
-
- #ifdef RASPBERRY_PI
+#ifdef RASPBERRY_PI
OMX_ERRORTYPE err;
OMX_CONFIG_DISPLAYREGIONTYPE config;
+
+ if (!st)
+ return;
+
memset(&config, 0, sizeof(OMX_CONFIG_DISPLAYREGIONTYPE));
config.nSize = sizeof(OMX_CONFIG_DISPLAYREGIONTYPE);
config.nVersion.nVersion = OMX_VERSION;
@@ -187,8 +200,9 @@ void omx_display_disable(struct omx_state* st)
if (err != 0) {
warning("omx_display_disable command failed");
}
-
- #endif
+#else
+ (void)st;
+#endif
}
diff --git a/modules/omx/omx.h b/modules/omx/omx.h
index 13d8928..6691d95 100644
--- a/modules/omx/omx.h
+++ b/modules/omx/omx.h
@@ -41,6 +41,6 @@ int omx_display_input_buffer(struct omx_state* st,
void** pbuf, uint32_t* plen);
int omx_display_flush_buffer(struct omx_state* st);
-int omx_display_enable(struct omx_state* st,
+int omx_display_enable(struct omx_state *st,
int width, int height, int stride);
-void omx_display_disable(struct omx_state* st);
+void omx_display_disable(struct omx_state *st);
diff --git a/modules/opus/decode.c b/modules/opus/decode.c
index f2d67b1..a4b8721 100644
--- a/modules/opus/decode.c
+++ b/modules/opus/decode.c
@@ -5,6 +5,7 @@
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <opus/opus.h>
#include "opus.h"
@@ -63,7 +64,8 @@ int opus_decode_update(struct audec_state **adsp, const struct aucodec *ac,
}
-int opus_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+int opus_decode_frm(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len)
{
int n;
@@ -71,11 +73,29 @@ int opus_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
if (!ads || !sampv || !sampc || !buf)
return EINVAL;
- n = opus_decode(ads->dec, buf, (opus_int32)len,
- sampv, (int)(*sampc/ads->ch), 0);
- if (n < 0) {
- warning("opus: decode error: %s\n", opus_strerror(n));
- return EPROTO;
+ switch (fmt) {
+
+ case AUFMT_S16LE:
+ n = opus_decode(ads->dec, buf, (opus_int32)len,
+ sampv, (int)(*sampc/ads->ch), 0);
+ if (n < 0) {
+ warning("opus: decode error: %s\n", opus_strerror(n));
+ return EPROTO;
+ }
+ break;
+
+ case AUFMT_FLOAT:
+ n = opus_decode_float(ads->dec, buf, (opus_int32)len,
+ sampv, (int)(*sampc/ads->ch), 0);
+ if (n < 0) {
+ warning("opus: float decode error: %s\n",
+ opus_strerror(n));
+ return EPROTO;
+ }
+ break;
+
+ default:
+ return ENOTSUP;
}
*sampc = n * ads->ch;
@@ -84,16 +104,33 @@ int opus_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
}
-int opus_decode_pkloss(struct audec_state *ads, int16_t *sampv, size_t *sampc)
+int opus_decode_pkloss(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc)
{
int n;
if (!ads || !sampv || !sampc)
return EINVAL;
- n = opus_decode(ads->dec, NULL, 0, sampv, (int)(*sampc/ads->ch), 0);
- if (n < 0)
- return EPROTO;
+ switch (fmt) {
+
+ case AUFMT_S16LE:
+ n = opus_decode(ads->dec, NULL, 0,
+ sampv, (int)(*sampc/ads->ch), 0);
+ if (n < 0)
+ return EPROTO;
+ break;
+
+ case AUFMT_FLOAT:
+ n = opus_decode_float(ads->dec, NULL, 0,
+ sampv, (int)(*sampc/ads->ch), 0);
+ if (n < 0)
+ return EPROTO;
+ break;
+
+ default:
+ return ENOTSUP;
+ }
*sampc = n * ads->ch;
diff --git a/modules/opus/encode.c b/modules/opus/encode.c
index 7ee1ca2..7baf4f8 100644
--- a/modules/opus/encode.c
+++ b/modules/opus/encode.c
@@ -5,6 +5,7 @@
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <opus/opus.h>
#include "opus.h"
@@ -134,6 +135,10 @@ int opus_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
fch = prm.stereo ? OPUS_AUTO : 1;
vbr = prm.cbr ? 0 : 1;
+ /* override local bitrate */
+ if (param && param->bitrate)
+ prm.bitrate = param->bitrate;
+
(void)opus_encoder_ctl(aes->enc,
OPUS_SET_MAX_BANDWIDTH(srate2bw(prm.srate)));
(void)opus_encoder_ctl(aes->enc, OPUS_SET_BITRATE(prm.bitrate));
@@ -167,18 +172,37 @@ int opus_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
int opus_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
opus_int32 n;
if (!aes || !buf || !len || !sampv)
return EINVAL;
- n = opus_encode(aes->enc, sampv, (int)(sampc/aes->ch),
- buf, (opus_int32)(*len));
- if (n < 0) {
- warning("opus: encode error: %s\n", opus_strerror((int)n));
- return EPROTO;
+ switch (fmt) {
+
+ case AUFMT_S16LE:
+ n = opus_encode(aes->enc, sampv, (int)(sampc/aes->ch),
+ buf, (opus_int32)(*len));
+ if (n < 0) {
+ warning("opus: encode error: %s\n",
+ opus_strerror((int)n));
+ return EPROTO;
+ }
+ break;
+
+ case AUFMT_FLOAT:
+ n = opus_encode_float(aes->enc, sampv, (int)(sampc/aes->ch),
+ buf, (opus_int32)(*len));
+ if (n < 0) {
+ warning("opus: float encode error: %s\n",
+ opus_strerror((int)n));
+ return EPROTO;
+ }
+ break;
+
+ default:
+ return ENOTSUP;
}
*len = n;
diff --git a/modules/opus/opus.h b/modules/opus/opus.h
index d521652..70fa0e3 100644
--- a/modules/opus/opus.h
+++ b/modules/opus/opus.h
@@ -19,15 +19,17 @@ struct opus_param {
int opus_encode_update(struct auenc_state **aesp, const struct aucodec *ac,
struct auenc_param *prm, const char *fmtp);
int opus_encode_frm(struct auenc_state *aes, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc);
+ int fmt, const void *sampv, size_t sampc);
/* Decode */
int opus_decode_update(struct audec_state **adsp, const struct aucodec *ac,
const char *fmtp);
-int opus_decode_frm(struct audec_state *ads, int16_t *sampv, size_t *sampc,
+int opus_decode_frm(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
const uint8_t *buf, size_t len);
-int opus_decode_pkloss(struct audec_state *st, int16_t *sampv, size_t *sampc);
+int opus_decode_pkloss(struct audec_state *st,
+ int fmt, void *sampv, size_t *sampc);
/* SDP */
diff --git a/modules/rst/video.c b/modules/rst/video.c
index bf59daf..c12ca0a 100644
--- a/modules/rst/video.c
+++ b/modules/rst/video.c
@@ -62,6 +62,8 @@ static void *video_thread(void *arg)
while (st->run) {
+ uint64_t timestamp;
+
sys_msleep(4);
now = tmr_jiffies();
@@ -69,8 +71,10 @@ static void *video_thread(void *arg)
if (ts > now)
continue;
+ timestamp = ts * VIDEO_TIMEBASE / 1000;
+
pthread_mutex_lock(&st->mutex);
- st->frameh(st->frame, st->arg);
+ st->frameh(st->frame, timestamp, st->arg);
pthread_mutex_unlock(&st->mutex);
ts += 1000/st->prm.fps;
diff --git a/modules/silk/silk.c b/modules/silk/silk.c
index dee296c..5bd9be5 100644
--- a/modules/silk/silk.c
+++ b/modules/silk/silk.c
@@ -4,6 +4,7 @@
* Copyright (C) 2010 - 2015 Creytiv.com
*/
#include <re.h>
+#include <rem.h>
#include <baresip.h>
#include <silk/SKP_Silk_SDK_API.h>
@@ -155,13 +156,15 @@ static int decode_update(struct audec_state **adsp,
static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv, size_t sampc)
{
int ret;
int16_t nBytesOut;
if (*len < MAX_BYTES_PER_FRAME)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
nBytesOut = *len;
ret = SKP_Silk_SDK_Encode(st->enc,
@@ -180,12 +183,15 @@ static int encode(struct auenc_state *st, uint8_t *buf, size_t *len,
}
-static int decode(struct audec_state *st, int16_t *sampv,
+static int decode(struct audec_state *st, int fmt, void *sampv,
size_t *sampc, const uint8_t *buf, size_t len)
{
int16_t nsamp = *sampc;
int ret;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
ret = SKP_Silk_SDK_Decode(st->dec,
&st->decControl,
0,
@@ -203,11 +209,14 @@ static int decode(struct audec_state *st, int16_t *sampv,
}
-static int plc(struct audec_state *st, int16_t *sampv, size_t *sampc)
+static int plc(struct audec_state *st, int fmt, void *sampv, size_t *sampc)
{
int16_t nsamp = *sampc;
int ret;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
ret = SKP_Silk_SDK_Decode(st->dec,
&st->decControl,
1,
diff --git a/modules/speex/speex.c b/modules/speex/speex.c
index 33b52e2..66a7ff4 100644
--- a/modules/speex/speex.c
+++ b/modules/speex/speex.c
@@ -465,19 +465,19 @@ static struct aucodec speexv[] = {
/* Stereo Speex */
{LE_INIT, 0, "speex", 32000, 32000, 2, speex_fmtp_wb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
{LE_INIT, 0, "speex", 16000, 16000, 2, speex_fmtp_wb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
{LE_INIT, 0, "speex", 8000, 8000, 2, speex_fmtp_nb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
/* Standard Speex */
{LE_INIT, 0, "speex", 32000, 32000, 1, speex_fmtp_wb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
{LE_INIT, 0, "speex", 16000, 16000, 1, speex_fmtp_wb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
{LE_INIT, 0, "speex", 8000, 8000, 1, speex_fmtp_nb,
- encode_update, encode, decode_update, decode, pkloss, 0, 0},
+ encode_update, encode, decode_update, decode, pkloss, 0, 0, 0, 0},
};
diff --git a/modules/speex_aec/module.mk b/modules/speex_aec/module.mk
index 9e29696..caa88a6 100644
--- a/modules/speex_aec/module.mk
+++ b/modules/speex_aec/module.mk
@@ -6,10 +6,6 @@
MOD := speex_aec
$(MOD)_SRCS += speex_aec.c
-ifneq ($(HAVE_SPEEXDSP),)
$(MOD)_LFLAGS += "-lspeexdsp"
-else
-$(MOD)_LFLAGS += "-lspeex"
-endif
include mk/mod.mk
diff --git a/modules/speex_pp/module.mk b/modules/speex_pp/module.mk
index fad5f88..adcaac2 100644
--- a/modules/speex_pp/module.mk
+++ b/modules/speex_pp/module.mk
@@ -6,10 +6,6 @@
MOD := speex_pp
$(MOD)_SRCS += speex_pp.c
-ifneq ($(HAVE_SPEEXDSP),)
$(MOD)_LFLAGS += "-lspeexdsp"
-else
-$(MOD)_LFLAGS += "-lspeex"
-endif
include mk/mod.mk
diff --git a/modules/swscale/swscale.c b/modules/swscale/swscale.c
index 5cd8905..a33a3ae 100644
--- a/modules/swscale/swscale.c
+++ b/modules/swscale/swscale.c
@@ -26,6 +26,7 @@ static enum AVPixelFormat vidfmt_to_avpixfmt(enum vidfmt fmt)
switch (fmt) {
case VID_FMT_YUV420P: return AV_PIX_FMT_YUV420P;
+ case VID_FMT_YUV444P: return AV_PIX_FMT_YUV444P;
case VID_FMT_NV12: return AV_PIX_FMT_NV12;
case VID_FMT_NV21: return AV_PIX_FMT_NV21;
default: return AV_PIX_FMT_NONE;
diff --git a/modules/v4l/v4l.c b/modules/v4l/v4l.c
index a171021..9f65cf6 100644
--- a/modules/v4l/v4l.c
+++ b/modules/v4l/v4l.c
@@ -117,13 +117,14 @@ static int v4l_get_win(int fd, int width, int height)
}
-static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf)
+static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf,
+ uint64_t timestamp)
{
struct vidframe frame;
vidframe_init_buf(&frame, st->fmt, &st->size, buf);
- st->frameh(&frame, st->arg);
+ st->frameh(&frame, timestamp, st->arg);
}
@@ -133,6 +134,7 @@ static void *read_thread(void *arg)
while (st->run) {
ssize_t n;
+ uint64_t timestamp;
n = read(st->fd, st->mb->buf, st->mb->size);
if ((ssize_t)st->mb->size != n) {
@@ -141,7 +143,10 @@ static void *read_thread(void *arg)
continue;
}
- call_frame_handler(st, st->mb->buf);
+ /* XXX: review this */
+ timestamp = tmr_jiffies() * 1000;
+
+ call_frame_handler(st, st->mb->buf, timestamp);
}
return NULL;
diff --git a/modules/v4l2/v4l2.c b/modules/v4l2/v4l2.c
index 983ad53..228ec10 100644
--- a/modules/v4l2/v4l2.c
+++ b/modules/v4l2/v4l2.c
@@ -106,6 +106,28 @@ static void print_video_input(const struct vidsrc_st *st)
}
+static void print_framerate(const struct vidsrc_st *st)
+{
+ struct v4l2_streamparm streamparm;
+ struct v4l2_fract tpf;
+ double fps;
+
+ memset(&streamparm, 0, sizeof(streamparm));
+
+ streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (v4l2_ioctl(st->fd, VIDIOC_G_PARM, &streamparm) != 0) {
+ warning("v4l2: VIDIOC_G_PARM error (%m)\n", errno);
+ return;
+ }
+
+ tpf = streamparm.parm.capture.timeperframe;
+ fps = (double)tpf.denominator / (double)tpf.numerator;
+
+ info("v4l2: current framerate is %.2f fps\n", fps);
+}
+
+
static int xioctl(int fd, unsigned long int request, void *arg)
{
int r;
@@ -331,19 +353,22 @@ static int start_capturing(struct vidsrc_st *st)
}
-static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf)
+static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf,
+ uint64_t timestamp)
{
struct vidframe frame;
vidframe_init_buf(&frame, match_fmt(st->pixfmt), &st->sz, buf);
- st->frameh(&frame, st->arg);
+ st->frameh(&frame, timestamp, st->arg);
}
static int read_frame(struct vidsrc_st *st)
{
struct v4l2_buffer buf;
+ struct timeval ts;
+ uint64_t timestamp;
memset(&buf, 0, sizeof(buf));
@@ -371,7 +396,11 @@ static int read_frame(struct vidsrc_st *st)
warning("v4l2: index >= n_buffers\n");
}
- call_frame_handler(st, st->buffers[buf.index].start);
+ ts = buf.timestamp;
+ timestamp = 1000000U * ts.tv_sec + ts.tv_usec;
+ timestamp = timestamp * VIDEO_TIMEBASE / 1000000U;
+
+ call_frame_handler(st, st->buffers[buf.index].start, timestamp);
if (-1 == xioctl (st->fd, VIDIOC_QBUF, &buf)) {
warning("v4l2: VIDIOC_QBUF\n");
@@ -470,6 +499,8 @@ static int alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
print_video_input(st);
+ print_framerate(st);
+
err = start_capturing(st);
if (err)
goto out;
diff --git a/modules/v4l2_codec/v4l2_codec.c b/modules/v4l2_codec/v4l2_codec.c
index 814a477..d15e7ac 100644
--- a/modules/v4l2_codec/v4l2_codec.c
+++ b/modules/v4l2_codec/v4l2_codec.c
@@ -277,7 +277,7 @@ static void enc_destructor(void *arg)
}
-static void encoders_read(uint32_t rtp_ts, const uint8_t *buf, size_t sz)
+static void encoders_read(uint64_t rtp_ts, const uint8_t *buf, size_t sz)
{
struct le *le;
int err;
@@ -301,7 +301,7 @@ static void read_handler(int flags, void *arg)
struct v4l2_buffer buf;
bool keyframe = false;
struct timeval ts;
- uint32_t rtp_ts;
+ uint64_t rtp_ts;
int err;
if (flags & FD_EXCEPT) {
@@ -349,10 +349,11 @@ static void read_handler(int flags, void *arg)
rtp_ts = (90000ULL * (1000000*ts.tv_sec + ts.tv_usec)) / 1000000;
#if 0
- debug("v4l2_codec: %s frame captured at %ldsec, %ldusec (%zu bytes)\n",
+ debug("v4l2_codec: %s frame captured at %ldsec, %ldusec"
+ " (%zu bytes) rtp_ts=%llu\n",
keyframe ? "KEY" : " ",
buf.timestamp.tv_sec, buf.timestamp.tv_usec,
- (size_t)buf.bytesused);
+ (size_t)buf.bytesused, rtp_ts);
#endif
/* pass the frame to the encoders */
@@ -429,7 +430,7 @@ static int encode_update(struct videnc_state **vesp, const struct vidcodec *vc,
list_append(&v4l2.encoderl, &st->le, st);
- info("v4l2_codec: video encoder %s: %d fps, %d bit/s, pktsize=%u\n",
+ info("v4l2_codec: video encoder %s: %.2f fps, %d bit/s, pktsize=%u\n",
vc->name, prm->fps, prm->bitrate, prm->pktsize);
if (err)
@@ -448,6 +449,14 @@ static int encode_packet(struct videnc_state *st, bool update,
(void)st;
(void)update;
(void)frame;
+
+ /*
+ * XXX: add support for KEY frame requests
+ */
+ if (update) {
+ info("v4l2_codec: peer requested a KEY frame (ignored)\n");
+ }
+
return 0;
}
diff --git a/modules/vidbridge/src.c b/modules/vidbridge/src.c
index 5e7d08a..2ead7cc 100644
--- a/modules/vidbridge/src.c
+++ b/modules/vidbridge/src.c
@@ -30,11 +30,10 @@ int vidbridge_src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
struct vidsrc_st *st;
int err;
(void)ctx;
- (void)prm;
(void)fmt;
(void)errorh;
- if (!stp || !size || !frameh)
+ if (!stp || !prm || !size || !frameh)
return EINVAL;
st = mem_zalloc(sizeof(*st), destructor);
@@ -44,6 +43,7 @@ int vidbridge_src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
st->vs = vs;
st->frameh = frameh;
st->arg = arg;
+ st->fps = prm->fps;
err = str_dup(&st->device, dev);
if (err)
@@ -82,12 +82,15 @@ struct vidsrc_st *vidbridge_src_find(const char *device)
}
-void vidbridge_src_input(const struct vidsrc_st *st,
+void vidbridge_src_input(struct vidsrc_st *st,
const struct vidframe *frame)
{
if (!st || !frame)
return;
+ /* XXX: Read from vidisp input */
+ st->timestamp += VIDEO_TIMEBASE / st->fps;
+
if (st->frameh)
- st->frameh((struct vidframe *)frame, st->arg);
+ st->frameh((struct vidframe *)frame, st->timestamp, st->arg);
}
diff --git a/modules/vidbridge/vidbridge.h b/modules/vidbridge/vidbridge.h
index 0fbf68e..74b2e24 100644
--- a/modules/vidbridge/vidbridge.h
+++ b/modules/vidbridge/vidbridge.h
@@ -10,6 +10,8 @@ struct vidsrc_st {
struct le le;
struct vidisp_st *vidisp;
+ uint64_t timestamp;
+ double fps;
char *device;
vidsrc_frame_h *frameh;
void *arg;
@@ -43,5 +45,5 @@ int vidbridge_src_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
const char *dev, vidsrc_frame_h *frameh,
vidsrc_error_h *errorh, void *arg);
struct vidsrc_st *vidbridge_src_find(const char *device);
-void vidbridge_src_input(const struct vidsrc_st *st,
+void vidbridge_src_input(struct vidsrc_st *st,
const struct vidframe *frame);
diff --git a/modules/vidloop/vidloop.c b/modules/vidloop/vidloop.c
index d99fa49..ca7979b 100644
--- a/modules/vidloop/vidloop.c
+++ b/modules/vidloop/vidloop.c
@@ -32,12 +32,6 @@
*/
-/** Internal pixel-format */
-#ifndef VIDLOOP_INTERNAL_FMT
-#define VIDLOOP_INTERNAL_FMT (VID_FMT_YUV420P)
-#endif
-
-
/** Video Statistics */
struct vstat {
uint64_t tsamp;
@@ -58,13 +52,31 @@ struct video_loop {
struct viddec_state *dec;
struct vidisp_st *vidisp;
struct vidsrc_st *vsrc;
+ struct vidsrc_prm srcprm;
struct list filtencl;
struct list filtdecl;
struct vstat stat;
struct tmr tmr_bw;
+ struct vidsz src_size;
+ struct vidsz disp_size;
+ enum vidfmt src_fmt;
+ uint64_t ts_start; /* usec */
+ uint64_t ts_last; /* usec */
uint16_t seq;
bool need_conv;
+ bool started;
int err;
+
+ struct {
+ uint64_t src_frames;
+ uint64_t enc_bytes;
+ uint64_t enc_packets;
+ uint64_t disp_frames;
+ } stats;
+
+ bool timestamp_set;
+ uint64_t timestamp_base; /* lowest timestamp */
+ uint64_t timestamp_last; /* most recent timestamp */
};
@@ -108,21 +120,27 @@ static int display(struct video_loop *vl, struct vidframe *frame)
warning("vidloop: error in video-filters (%m)\n", err);
}
+ /* save the displayed frame info */
+ vl->disp_size = frame->size;
+ ++vl->stats.disp_frames;
+
/* display frame */
err = vidisp_display(vl->vidisp, "Video Loop", frame);
if (err == ENODEV) {
info("vidloop: video-display was closed\n");
vl->vidisp = mem_deref(vl->vidisp);
vl->err = err;
+ goto out;
}
+ out:
mem_deref(frame_filt);
return err;
}
-static int packet_handler(bool marker, uint32_t rtp_ts,
+static int packet_handler(bool marker, uint64_t rtp_ts,
const uint8_t *hdr, size_t hdr_len,
const uint8_t *pld, size_t pld_len,
void *arg)
@@ -134,6 +152,9 @@ static int packet_handler(bool marker, uint32_t rtp_ts,
int err = 0;
(void)rtp_ts;
+ ++vl->stats.enc_packets;
+ vl->stats.enc_bytes += (hdr_len + pld_len);
+
mb = mbuf_alloc(hdr_len + pld_len);
if (!mb)
return ENOMEM;
@@ -172,26 +193,65 @@ static int packet_handler(bool marker, uint32_t rtp_ts,
}
-static void vidsrc_frame_handler(struct vidframe *frame, void *arg)
+static double stream_duration(const struct video_loop *vl)
+{
+ uint64_t dur;
+
+ if (vl->timestamp_set)
+ dur = vl->timestamp_last - vl->timestamp_base;
+ else
+ dur = 0;
+
+ return video_timestamp_to_seconds(dur);
+}
+
+
+static void vidsrc_frame_handler(struct vidframe *frame, uint64_t timestamp,
+ void *arg)
{
struct video_loop *vl = arg;
struct vidframe *f2 = NULL;
struct le *le;
+ const uint64_t now = tmr_jiffies_usec();
int err = 0;
+ /* save the timing info */
+ if (!gvl->ts_start)
+ gvl->ts_start = now;
+ gvl->ts_last = now;
+
+ /* save the video frame info */
+ vl->src_size = frame->size;
+ vl->src_fmt = frame->fmt;
+ ++vl->stats.src_frames;
+
+ /* Timestamp logic */
+ if (vl->timestamp_set) {
+ if (timestamp <= vl->timestamp_base) {
+ info("vidloop: timestamp wrapped -- reset base\n");
+ vl->timestamp_base = timestamp;
+ }
+ vl->timestamp_last = timestamp;
+ }
+ else {
+ vl->timestamp_base = timestamp;
+ vl->timestamp_last = timestamp;
+ vl->timestamp_set = true;
+ }
+
++vl->stat.frames;
- if (frame->fmt != VIDLOOP_INTERNAL_FMT) {
+ if (frame->fmt != (enum vidfmt)vl->cfg.enc_fmt) {
if (!vl->need_conv) {
info("vidloop: NOTE: pixel-format conversion"
" needed: %s --> %s\n",
vidfmt_name(frame->fmt),
- vidfmt_name(VIDLOOP_INTERNAL_FMT));
+ vidfmt_name(vl->cfg.enc_fmt));
vl->need_conv = true;
}
- if (vidframe_alloc(&f2, VIDLOOP_INTERNAL_FMT, &frame->size))
+ if (vidframe_alloc(&f2, vl->cfg.enc_fmt, &frame->size))
return;
vidconv(f2, frame, 0);
@@ -209,21 +269,147 @@ static void vidsrc_frame_handler(struct vidframe *frame, void *arg)
}
if (vl->vc_enc && vl->enc) {
- (void)vl->vc_enc->ench(vl->enc, false, frame);
+ err = vl->vc_enc->ench(vl->enc, false, frame);
+ if (err) {
+ warning("vidloop: encoder error (%m)\n", err);
+ goto out;
+ }
}
else {
vl->stat.bytes += vidframe_size(frame->fmt, &frame->size);
(void)display(vl, frame);
}
+ out:
mem_deref(f2);
}
+static int print_stats(struct re_printf *pf, const struct video_loop *vl)
+{
+ const struct config_video *cfg = &vl->cfg;
+ double real_dur = .0;
+ int err = 0;
+
+ if (vl->ts_start) {
+ real_dur = stream_duration(vl);
+ }
+
+ err |= re_hprintf(pf, "~~~~~ Videoloop summary: ~~~~~\n");
+
+ /* Source */
+ if (vl->vsrc) {
+ struct vidsrc *vs = vidsrc_get(vl->vsrc);
+ double avg_fps = .0;
+
+ if (vl->stats.src_frames >= 2)
+ avg_fps = (vl->stats.src_frames-1) / real_dur;
+
+ err |= re_hprintf(pf,
+ "* Source\n"
+ " module %s\n"
+ " resolution %u x %u (actual %u x %u)\n"
+ " pixformat %s\n"
+ " frames %llu\n"
+ " framerate %.2f fps (avg %.2f fps)\n"
+ " duration %.3f sec\n"
+ "\n"
+ ,
+ vs->name,
+ cfg->width, cfg->height,
+ vl->src_size.w, vl->src_size.h,
+ vidfmt_name(vl->src_fmt),
+ vl->stats.src_frames,
+ vl->srcprm.fps, avg_fps,
+ real_dur);
+ }
+
+ /* Video conversion */
+ if (vl->need_conv) {
+ err |= re_hprintf(pf,
+ "* Vidconv\n"
+ " pixformat %s\n"
+ "\n"
+ ,
+ vidfmt_name(cfg->enc_fmt));
+ }
+
+ /* Filters */
+ if (!list_isempty(baresip_vidfiltl())) {
+ struct le *le;
+
+ err |= re_hprintf(pf,
+ "* Filters (%u):",
+ list_count(baresip_vidfiltl()));
+
+ for (le = list_head(baresip_vidfiltl()); le; le = le->next) {
+ struct vidfilt *vf = le->data;
+ err |= re_hprintf(pf, " %s", vf->name);
+ }
+ err |= re_hprintf(pf, "\n\n");
+ }
+
+ /* Encoder */
+ if (vl->vc_enc) {
+ double avg_bitrate;
+ double avg_pktrate;
+
+ avg_bitrate = 8.0 * (double)vl->stats.enc_bytes / real_dur;
+ avg_pktrate = (double)vl->stats.enc_packets / real_dur;
+
+ err |= re_hprintf(pf,
+ "* Encoder\n"
+ " module %s\n"
+ " bitrate %u bit/s (avg %.1f bit/s)\n"
+ " packets %llu (avg %.1f pkt/s)\n"
+ "\n"
+ ,
+ vl->vc_enc->name,
+ cfg->bitrate, avg_bitrate,
+ vl->stats.enc_packets, avg_pktrate);
+ }
+
+ /* Decoder */
+ if (vl->vc_dec) {
+ err |= re_hprintf(pf,
+ "* Decoder\n"
+ " module %s\n"
+ " key-frames %zu\n"
+ "\n"
+ ,
+ vl->vc_dec->name,
+ vl->stat.n_intra);
+ }
+
+ /* Display */
+ if (vl->vidisp) {
+ struct vidisp *vd = vidisp_get(vl->vidisp);
+
+ err |= re_hprintf(pf,
+ "* Display\n"
+ " module %s\n"
+ " resolution %u x %u\n"
+ " fullscreen %s\n"
+ " frames %llu\n"
+ "\n"
+ ,
+ vd->name,
+ vl->disp_size.w, vl->disp_size.h,
+ cfg->fullscreen ? "Yes" : "No",
+ vl->stats.disp_frames);
+ }
+
+ return err;
+}
+
+
static void vidloop_destructor(void *arg)
{
struct video_loop *vl = arg;
+ if (vl->started)
+ re_printf("%H\n", print_stats, vl);
+
tmr_cancel(&vl->tmr_bw);
mem_deref(vl->vsrc);
mem_deref(vl->enc);
@@ -253,7 +439,7 @@ static int enable_codec(struct video_loop *vl, const char *name)
return ENOENT;
}
- info("vidloop: enabled encoder %s (%u fps, %u bit/s)\n",
+ info("vidloop: enabled encoder %s (%.2f fps, %u bit/s)\n",
vl->vc_enc->name, prm.fps, prm.bitrate);
vl->vc_dec = vidcodec_find_decoder(vidcodecl, name);
@@ -287,10 +473,12 @@ static void print_status(struct video_loop *vl)
{
(void)re_fprintf(stdout,
"\rstatus:"
- " [%s] [%s] intra=%zu "
+ " %.3f sec [%s] [%s] fmt=%s intra=%zu "
" EFPS=%.1f %u kbit/s \r",
+ stream_duration(vl),
vl->vc_enc ? vl->vc_enc->name : "",
vl->vc_dec ? vl->vc_dec->name : "",
+ vidfmt_name(vl->cfg.enc_fmt),
vl->stat.n_intra,
vl->stat.efps, vl->stat.bitrate);
fflush(stdout);
@@ -326,7 +514,7 @@ static void timeout_bw(void *arg)
return;
}
- tmr_start(&vl->tmr_bw, 2000, timeout_bw, vl);
+ tmr_start(&vl->tmr_bw, 500, timeout_bw, vl);
calc_bitrate(vl);
print_status(vl);
@@ -335,19 +523,18 @@ static void timeout_bw(void *arg)
static int vsrc_reopen(struct video_loop *vl, const struct vidsz *sz)
{
- struct vidsrc_prm prm;
int err;
- info("vidloop: %s,%s: open video source: %u x %u at %u fps\n",
+ info("vidloop: %s,%s: open video source: %u x %u at %.2f fps\n",
vl->cfg.src_mod, vl->cfg.src_dev,
sz->w, sz->h, vl->cfg.fps);
- prm.orient = VIDORIENT_PORTRAIT;
- prm.fps = vl->cfg.fps;
+ vl->srcprm.orient = VIDORIENT_PORTRAIT;
+ vl->srcprm.fps = vl->cfg.fps;
vl->vsrc = mem_deref(vl->vsrc);
err = vidsrc_alloc(&vl->vsrc, baresip_vidsrcl(),
- vl->cfg.src_mod, NULL, &prm, sz,
+ vl->cfg.src_mod, NULL, &vl->srcprm, sz,
NULL, vl->cfg.src_dev, vidsrc_frame_handler,
NULL, vl);
if (err) {
@@ -462,6 +649,8 @@ static int vidloop_start(struct re_printf *pf, void *arg)
return err;
}
+ gvl->started = true;
+
return err;
}
diff --git a/modules/vp8/encode.c b/modules/vp8/encode.c
index 83f136b..6707ead 100644
--- a/modules/vp8/encode.c
+++ b/modules/vp8/encode.c
@@ -157,7 +157,7 @@ static inline void hdr_encode(uint8_t hdr[HDR_SIZE], bool noref, bool start,
static inline int packetize(bool marker, const uint8_t *buf, size_t len,
size_t maxlen, bool noref, uint8_t partid,
- uint16_t picid, uint32_t rtp_ts,
+ uint16_t picid, uint64_t rtp_ts,
videnc_packet_h *pkth, void *arg)
{
uint8_t hdr[HDR_SIZE];
@@ -236,7 +236,7 @@ int vp8_encode(struct videnc_state *ves, bool update,
bool keyframe = false, marker = true;
const vpx_codec_cx_pkt_t *pkt;
uint8_t partid = 0;
- uint32_t ts;
+ uint64_t ts;
pkt = vpx_codec_get_cx_data(&ves->ctx, &iter);
if (!pkt)
diff --git a/modules/vp9/encode.c b/modules/vp9/encode.c
index 9de4d73..2a98026 100644
--- a/modules/vp9/encode.c
+++ b/modules/vp9/encode.c
@@ -172,7 +172,7 @@ static inline void hdr_encode(uint8_t hdr[HDR_SIZE], bool start, bool end,
static int send_packet(struct videnc_state *ves, bool marker,
const uint8_t *hdr, size_t hdr_len,
const uint8_t *pld, size_t pld_len,
- uint32_t rtp_ts)
+ uint64_t rtp_ts)
{
ves->n_bytes += (hdr_len + pld_len);
@@ -184,7 +184,7 @@ static int send_packet(struct videnc_state *ves, bool marker,
static inline int packetize(struct videnc_state *ves,
bool marker, const uint8_t *buf, size_t len,
size_t maxlen, uint16_t picid,
- uint32_t rtp_ts)
+ uint64_t rtp_ts)
{
uint8_t hdr[HDR_SIZE];
bool start = true;
@@ -280,7 +280,7 @@ int vp9_encode(struct videnc_state *ves, bool update,
for (;;) {
bool marker = true;
const vpx_codec_cx_pkt_t *pkt;
- uint32_t ts;
+ uint64_t ts;
pkt = vpx_codec_get_cx_data(&ves->ctx, &iter);
if (!pkt)
diff --git a/modules/x11grab/x11grab.c b/modules/x11grab/x11grab.c
index d3aa287..36f37c1 100644
--- a/modules/x11grab/x11grab.c
+++ b/modules/x11grab/x11grab.c
@@ -100,13 +100,14 @@ static inline uint8_t *x11grab_read(struct vidsrc_st *st)
}
-static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf)
+static void call_frame_handler(struct vidsrc_st *st, uint8_t *buf,
+ uint64_t timestamp)
{
struct vidframe frame;
vidframe_init_buf(&frame, st->pixfmt, &st->size, buf);
- st->frameh(&frame, st->arg);
+ st->frameh(&frame, timestamp, st->arg);
}
@@ -118,6 +119,8 @@ static void *read_thread(void *arg)
while (st->run) {
+ uint64_t timestamp;
+
if (tmr_jiffies() < ts) {
sys_msleep(4);
continue;
@@ -127,9 +130,11 @@ static void *read_thread(void *arg)
if (!buf)
continue;
+ timestamp = ts * VIDEO_TIMEBASE / 1000;
+
ts += (1000/st->fps);
- call_frame_handler(st, buf);
+ call_frame_handler(st, buf, timestamp);
}
return NULL;