summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/call.c2
-rw-r--r--src/video.c18
-rw-r--r--test/call.c51
-rw-r--r--test/main.c1
-rw-r--r--test/mock/mock_vidcodec.c200
-rw-r--r--test/mock/mock_vidisp.c96
-rw-r--r--test/mock/mock_vidsrc.c91
-rw-r--r--test/srcs.mk3
-rw-r--r--test/test.h27
9 files changed, 483 insertions, 6 deletions
diff --git a/src/call.c b/src/call.c
index 16df3ca..20b2ff1 100644
--- a/src/call.c
+++ b/src/call.c
@@ -589,6 +589,8 @@ int call_alloc(struct call **callp, const struct config *cfg, struct list *lst,
&& (list_head(account_vidcodecl(call->acc)) != NULL)
&& (NULL != vidsrc_find(NULL) || NULL != vidisp_find(NULL));
+ debug("call: use_video=%d\n", use_video);
+
/* Video stream */
if (use_video) {
err = video_alloc(&call->video, cfg,
diff --git a/src/video.c b/src/video.c
index 2f61d77..c13b6e9 100644
--- a/src/video.c
+++ b/src/video.c
@@ -943,10 +943,15 @@ int video_start(struct video *v, const char *peer)
stream_set_srate(v->strm, SRATE, SRATE);
- err = set_vidisp(&v->vrx);
- if (err) {
- warning("video: could not set vidisp '%s': %m\n",
- v->vrx.device, err);
+ if (vidisp_find(NULL)) {
+ err = set_vidisp(&v->vrx);
+ if (err) {
+ warning("video: could not set vidisp '%s': %m\n",
+ v->vrx.device, err);
+ }
+ }
+ else {
+ info("video: no video display\n");
}
size.w = v->cfg.width;
@@ -1075,6 +1080,11 @@ int video_encoder_set(struct video *v, struct vidcodec *vc,
vtx = &v->vtx;
+ if (!vc->encupdh) {
+ info("video: vidcodec '%s' has no encoder\n", vc->name);
+ return ENOENT;
+ }
+
if (vc != vtx->vc) {
struct videnc_param prm;
diff --git a/test/call.c b/test/call.c
index 75d8c9f..4744b8a 100644
--- a/test/call.c
+++ b/test/call.c
@@ -123,8 +123,8 @@ static void event_handler(struct ua *ua, enum ua_event ev,
int err = 0;
(void)prm;
-#if 0
- re_printf("[ %s ] event: %s (%s)\n",
+#if 1
+ info("test: [ %s ] event: %s (%s)\n",
ua_aor(ua), uag_event_str(ev), prm);
#endif
@@ -663,3 +663,50 @@ int test_call_dtmf(void)
return err;
}
+
+
+int test_call_video(void)
+{
+ struct fixture fix, *f = &fix;
+ struct vidsrc *vidsrc = NULL;
+ struct vidisp *vidisp = NULL;
+ int err = 0;
+
+ conf_config()->video.fps = 100;
+
+ fixture_init(f);
+
+ /* to enable video, we need one vidsrc and vidcodec */
+ mock_vidcodec_register();
+ err = mock_vidsrc_register(&vidsrc);
+ TEST_ERR(err);
+ err = mock_vidisp_register(&vidisp);
+ TEST_ERR(err);
+
+ f->behaviour = BEHAVIOUR_ANSWER;
+ f->estab_action = ACTION_NOTHING;
+
+ /* Make a call from A to B */
+ err = ua_connect(f->a.ua, 0, NULL, f->buri, NULL, VIDMODE_ON);
+ TEST_ERR(err);
+
+ /* run main-loop with timeout, wait for events */
+ err = re_main_timeout(10000);
+ TEST_ERR(err);
+ TEST_ERR(fix.err);
+
+ /* verify that video was enabled for this call */
+ ASSERT_EQ(1, fix.a.n_established);
+ ASSERT_EQ(1, fix.b.n_established);
+
+ ASSERT_TRUE(call_has_video(ua_call(f->a.ua)));
+ ASSERT_TRUE(call_has_video(ua_call(f->b.ua)));
+
+ out:
+ fixture_close(f);
+ mem_deref(vidisp);
+ mem_deref(vidsrc);
+ mock_vidcodec_unregister();
+
+ return err;
+}
diff --git a/test/main.c b/test/main.c
index 3a5dd77..487303e 100644
--- a/test/main.c
+++ b/test/main.c
@@ -28,6 +28,7 @@ static const struct test tests[] = {
TEST(test_call_multiple),
TEST(test_call_max),
TEST(test_call_dtmf),
+ TEST(test_call_video),
TEST(test_cmd),
TEST(test_cmd_long),
TEST(test_contact),
diff --git a/test/mock/mock_vidcodec.c b/test/mock/mock_vidcodec.c
new file mode 100644
index 0000000..c93f648
--- /dev/null
+++ b/test/mock/mock_vidcodec.c
@@ -0,0 +1,200 @@
+/**
+ * @file mock/mock_vidcodec.c Mock video codec
+ *
+ * Copyright (C) 2010 - 2016 Creytiv.com
+ */
+
+#include <string.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "../test.h"
+
+
+#define HDR_SIZE 12
+
+
+struct hdr {
+ enum vidfmt fmt;
+ unsigned width;
+ unsigned height;
+};
+
+struct videnc_state {
+ videnc_packet_h *pkth;
+ void *arg;
+};
+
+struct viddec_state {
+ struct vidframe *frame;
+};
+
+
+static int hdr_decode(struct hdr *hdr, struct mbuf *mb)
+{
+ if (mbuf_get_left(mb) < HDR_SIZE)
+ return EBADMSG;
+
+ hdr->fmt = ntohl(mbuf_read_u32(mb));
+ hdr->width = ntohl(mbuf_read_u32(mb));
+ hdr->height = ntohl(mbuf_read_u32(mb));
+
+ return 0;
+}
+
+
+static void decode_destructor(void *arg)
+{
+ struct viddec_state *vds = arg;
+
+ mem_deref(vds->frame);
+}
+
+
+static int mock_encode_update(struct videnc_state **vesp,
+ const struct vidcodec *vc,
+ struct videnc_param *prm, const char *fmtp,
+ videnc_packet_h *pkth, void *arg)
+{
+ struct videnc_state *ves;
+
+ if (!vesp || !vc || !prm || prm->pktsize < (HDR_SIZE + 1))
+ return EINVAL;
+
+ ves = *vesp;
+
+ if (!ves) {
+
+ ves = mem_zalloc(sizeof(*ves), NULL);
+ if (!ves)
+ return ENOMEM;
+
+ *vesp = ves;
+ }
+
+ ves->pkth = pkth;
+ ves->arg = arg;
+
+ return 0;
+}
+
+
+static int mock_encode(struct videnc_state *ves, bool update,
+ const struct vidframe *frame)
+{
+ struct mbuf *hdr;
+ uint8_t payload[2] = {0,0};
+ int err;
+
+ if (!ves || !frame)
+ return EINVAL;
+
+ hdr = mbuf_alloc(16);
+
+ err = mbuf_write_u32(hdr, htonl(frame->fmt));
+ err |= mbuf_write_u32(hdr, htonl(frame->size.w));
+ err |= mbuf_write_u32(hdr, htonl(frame->size.h));
+ if (err)
+ goto out;
+
+ err = ves->pkth(true, hdr->buf, hdr->end,
+ payload, sizeof(payload), ves->arg);
+ if (err)
+ goto out;
+
+ out:
+ mem_deref(hdr);
+
+ return err;
+}
+
+
+static int mock_decode_update(struct viddec_state **vdsp,
+ const struct vidcodec *vc, const char *fmtp)
+{
+ struct viddec_state *vds;
+ int err = 0;
+ (void)vc;
+ (void)fmtp;
+
+ if (!vdsp)
+ return EINVAL;
+
+ vds = *vdsp;
+
+ if (vds)
+ return 0;
+
+ vds = mem_zalloc(sizeof(*vds), decode_destructor);
+ if (!vds)
+ return ENOMEM;
+
+ if (err)
+ mem_deref(vds);
+ else
+ *vdsp = vds;
+
+ return err;
+}
+
+
+static int mock_decode(struct viddec_state *vds, struct vidframe *frame,
+ bool *intra, bool marker, uint16_t seq, struct mbuf *mb)
+{
+ struct vidsz size;
+ struct hdr hdr;
+ int err, i;
+
+ if (!vds || !frame || !intra || !mb)
+ return EINVAL;
+
+ *intra = false;
+
+ err = hdr_decode(&hdr, mb);
+ if (err) {
+ warning("mock_vidcodec: could not decode header (%m)\n", err);
+ return err;
+ }
+
+ size.w = hdr.width;
+ size.h = hdr.height;
+
+ if (!vds->frame) {
+ err = vidframe_alloc(&vds->frame, hdr.fmt, &size);
+ if (err)
+ goto out;
+ }
+
+ for (i=0; i<4; i++) {
+ frame->data[i] = vds->frame->data[i];
+ frame->linesize[i] = vds->frame->linesize[i];
+ }
+
+ frame->size.w = vds->frame->size.w;
+ frame->size.h = vds->frame->size.h;
+ frame->fmt = vds->frame->fmt;
+
+ out:
+ return err;
+}
+
+
+static struct vidcodec vc_dummy = {
+ .name = "H266",
+ .encupdh = mock_encode_update,
+ .ench = mock_encode,
+ .decupdh = mock_decode_update,
+ .dech = mock_decode,
+};
+
+
+void mock_vidcodec_register(void)
+{
+ vidcodec_register(&vc_dummy);
+}
+
+
+void mock_vidcodec_unregister(void)
+{
+ vidcodec_unregister(&vc_dummy);
+}
diff --git a/test/mock/mock_vidisp.c b/test/mock/mock_vidisp.c
new file mode 100644
index 0000000..da554b0
--- /dev/null
+++ b/test/mock/mock_vidisp.c
@@ -0,0 +1,96 @@
+/**
+ * @file mock/mock_vidisp.c Mock video display
+ *
+ * Copyright (C) 2010 - 2016 Creytiv.com
+ */
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "../test.h"
+
+
+#define MAX_WIDTH 65536
+#define MAX_HEIGHT 65536
+
+
+struct vidisp_st {
+ const struct vidisp *vd; /* inheritance */
+ unsigned n_frame;
+};
+
+
+static void disp_destructor(void *arg)
+{
+ struct vidisp_st *st = arg;
+ (void)st;
+}
+
+
+static int mock_disp_alloc(struct vidisp_st **stp, const struct vidisp *vd,
+ struct vidisp_prm *prm, const char *dev,
+ vidisp_resize_h *resizeh, void *arg)
+{
+ struct vidisp_st *st;
+ (void)prm;
+ (void)dev;
+ (void)resizeh;
+ (void)arg;
+
+ if (!stp || !vd)
+ return EINVAL;
+
+ st = mem_zalloc(sizeof(*st), disp_destructor);
+ if (!st)
+ return ENOMEM;
+
+ st->vd = vd;
+
+ *stp = st;
+
+ return 0;
+}
+
+
+static int mock_display(struct vidisp_st *st, const char *title,
+ const struct vidframe *frame)
+{
+ unsigned width, height;
+
+ if (!st || !frame)
+ return EINVAL;
+
+ width = frame->size.w;
+ height = frame->size.h;
+
+ if (!vidframe_isvalid(frame)) {
+ warning("mock_vidisp: got invalid frame\n");
+ return EPROTO;
+ }
+
+ /* verify that the video frame is good */
+ if (frame->fmt >= VID_FMT_N)
+ return EPROTO;
+ if (width == 0 || width > MAX_WIDTH)
+ return EPROTO;
+ if (height == 0 || height > MAX_HEIGHT)
+ return EPROTO;
+ if (frame->linesize[0] == 0)
+ return EPROTO;
+
+ ++st->n_frame;
+
+ if (st->n_frame >= 10) {
+ info("mock_vidisp: got %u frames -- stopping re_main\n",
+ st->n_frame);
+ re_cancel(); /* XXX use a callback handler instead */
+ }
+
+ return 0;
+}
+
+
+int mock_vidisp_register(struct vidisp **vidispp)
+{
+ return vidisp_register(vidispp, "mock-vidisp",
+ mock_disp_alloc, NULL, mock_display, NULL);
+}
diff --git a/test/mock/mock_vidsrc.c b/test/mock/mock_vidsrc.c
new file mode 100644
index 0000000..526ab16
--- /dev/null
+++ b/test/mock/mock_vidsrc.c
@@ -0,0 +1,91 @@
+/**
+ * @file mock/mock_vidsrc.c Mock video source
+ *
+ * Copyright (C) 2010 - 2016 Creytiv.com
+ */
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "../test.h"
+
+
+struct vidsrc_st {
+ const struct vidsrc *vs; /* inheritance */
+
+ struct vidframe *frame;
+ struct tmr tmr;
+ int fps;
+ vidsrc_frame_h *frameh;
+ void *arg;
+};
+
+
+static void tmr_handler(void *arg)
+{
+ struct vidsrc_st *st = arg;
+
+ tmr_start(&st->tmr, 1000/st->fps, tmr_handler, st);
+
+ if (st->frameh)
+ st->frameh(st->frame, st->arg);
+}
+
+
+static void vidsrc_destructor(void *arg)
+{
+ struct vidsrc_st *st = arg;
+
+ tmr_cancel(&st->tmr);
+ mem_deref(st->frame);
+}
+
+
+static int mock_vidsrc_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
+ struct media_ctx **ctx, struct vidsrc_prm *prm,
+ const struct vidsz *size, const char *fmt,
+ const char *dev, vidsrc_frame_h *frameh,
+ vidsrc_error_h *errorh, void *arg)
+{
+ struct vidsrc_st *st;
+ int err = 0;
+ (void)ctx;
+ (void)fmt;
+ (void)dev;
+ (void)errorh;
+
+ if (!stp || !prm || !size || !frameh)
+ return EINVAL;
+
+ st = mem_zalloc(sizeof(*st), vidsrc_destructor);
+ if (!st)
+ return ENOMEM;
+
+ st->vs = vs;
+ st->fps = prm->fps;
+ st->frameh = frameh;
+ st->arg = arg;
+
+ err = vidframe_alloc(&st->frame, VID_FMT_YUV420P, size);
+ if (err)
+ goto out;
+
+ tmr_start(&st->tmr, 0, tmr_handler, st);
+
+ info("mock_vidsrc: new instance with size %u x %u (%d fps)\n",
+ size->w, size->h, prm->fps);
+
+ out:
+ if (err)
+ mem_deref(st);
+ else
+ *stp = st;
+
+ return err;
+}
+
+
+int mock_vidsrc_register(struct vidsrc **vidsrcp)
+{
+ return vidsrc_register(vidsrcp, "mock-vidsrc",
+ mock_vidsrc_alloc, NULL);
+}
diff --git a/test/srcs.mk b/test/srcs.mk
index b992822..7960c58 100644
--- a/test/srcs.mk
+++ b/test/srcs.mk
@@ -34,6 +34,9 @@ TEST_SRCS += mock/cert.c
endif
TEST_SRCS += mock/mock_ausrc.c
+TEST_SRCS += mock/mock_vidsrc.c
+TEST_SRCS += mock/mock_vidcodec.c
+TEST_SRCS += mock/mock_vidisp.c
TEST_SRCS += test.c
diff --git a/test/test.h b/test/test.h
index bd41c82..0f6d203 100644
--- a/test/test.h
+++ b/test/test.h
@@ -92,6 +92,32 @@ struct ausrc;
int mock_ausrc_register(struct ausrc **ausrcp);
+/*
+ * Mock Video-source
+ */
+
+struct vidsrc;
+
+int mock_vidsrc_register(struct vidsrc **vidsrcp);
+
+
+/*
+ * Mock Video-codec
+ */
+
+void mock_vidcodec_register(void);
+void mock_vidcodec_unregister(void);
+
+
+/*
+ * Mock Video-display
+ */
+
+struct vidisp;
+
+int mock_vidisp_register(struct vidisp **vidispp);
+
+
/* test cases */
int test_cmd(void);
@@ -116,6 +142,7 @@ int test_call_rtp_timeout(void);
int test_call_multiple(void);
int test_call_max(void);
int test_call_dtmf(void);
+int test_call_video(void);
#ifdef __cplusplus