summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2018-04-30 12:56:52 +0200
committerJonas Smedegaard <dr@jones.dk>2018-04-30 12:56:52 +0200
commitf24295049f4d58e72b05dacc943d4387fd66cbcb (patch)
tree985816714d70de11b68fab44231110cdc162300d
parentb7869a262cbca2241c70549af9c877529706c15f (diff)
parenta7fd4a25c8a1e0f292d4922f9261e1756e444a28 (diff)
New upstream version 0.5.9
-rw-r--r--Makefile9
-rw-r--r--README.md6
-rw-r--r--docs/COPYING6
-rw-r--r--docs/ChangeLog178
-rw-r--r--docs/examples/accounts6
-rw-r--r--include/baresip.h85
-rw-r--r--mk/Doxyfile2
-rw-r--r--mk/modules.mk10
-rw-r--r--mk/win32/baresip.sln9
-rw-r--r--mk/win32/baresip.vcxproj19
-rw-r--r--mk/win32/baresip.vcxproj.filters5
-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
-rw-r--r--rpm/baresip.spec2
-rw-r--r--src/account.c3
-rw-r--r--src/audio.c212
-rw-r--r--src/call.c27
-rw-r--r--src/conf.c18
-rw-r--r--src/config.c78
-rw-r--r--src/core.h75
-rw-r--r--src/event.c10
-rw-r--r--src/h264.c36
-rw-r--r--src/log.c71
-rw-r--r--src/main.c4
-rw-r--r--src/metric.c4
-rw-r--r--src/reg.c5
-rw-r--r--src/srcs.mk3
-rw-r--r--src/stream.c11
-rw-r--r--src/timer.c71
-rw-r--r--src/timestamp.c65
-rw-r--r--src/ua.c30
-rw-r--r--src/video.c177
-rw-r--r--src/vidisp.c7
-rw-r--r--src/vidsrc.c7
-rw-r--r--src/vidutil.c65
-rw-r--r--test/account.c6
-rw-r--r--test/call.c69
-rw-r--r--test/event.c55
-rw-r--r--test/main.c2
-rw-r--r--test/mock/mock_aucodec.c12
-rw-r--r--test/mock/mock_menc.c126
-rw-r--r--test/mock/mock_vidcodec.c4
-rw-r--r--test/mock/mock_vidsrc.c9
-rw-r--r--test/sip/domain.c3
-rw-r--r--test/sip/sipsrv.c2
-rw-r--r--test/sip/sipsrv.h7
-rw-r--r--test/sip/user.c13
-rw-r--r--test/srcs.mk2
-rw-r--r--test/test.h10
-rw-r--r--test/ua.c18
-rw-r--r--test/video.c4
110 files changed, 2968 insertions, 521 deletions
diff --git a/Makefile b/Makefile
index f5b4c25..31e2f4a 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@
USE_VIDEO := 1
PROJECT := baresip
-VERSION := 0.5.7
+VERSION := 0.5.9
DESCR := "Baresip is a modular SIP User-Agent with audio and video support"
# Verbose and silent build modes
@@ -66,10 +66,13 @@ ifeq ($(OS),win32)
STATIC := yes
endif
-ifeq ($(OS),freebsd)
ifneq ($(SYSROOT),)
+ifeq ($(OS),freebsd)
CFLAGS += -I$(SYSROOT)/local/include
endif
+ifeq ($(OS),openbsd)
+CFLAGS += -isystem $(SYSROOT)/local/include
+endif
endif
@@ -106,6 +109,8 @@ LIBDIR := $(PREFIX)/lib
MOD_PATH := $(LIBDIR)/$(PROJECT)/modules
SHARE_PATH := $(PREFIX)/share/$(PROJECT)
CFLAGS += -DPREFIX=\"$(PREFIX)\"
+CFLAGS += -DMOD_PATH=\"$(MOD_PATH)\"
+CFLAGS += -DSHARE_PATH=\"$(SHARE_PATH)\"
all: sanity $(MOD_BINS) $(BIN)
diff --git a/README.md b/README.md
index 8edddee..df0e4e9 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ baresip README
Baresip is a portable and modular SIP User-Agent with audio and video support.
-Copyright (c) 2010 - 2017 Creytiv.com
+Copyright (c) 2010 - 2018 Creytiv.com
Distributed under BSD license
@@ -130,6 +130,7 @@ Distributed under BSD license
- Command-line console over UDP/TCP
- Command line interface (CLI)
- Simple configuration files
+ - MQTT (Message Queue Telemetry Transport) module
## Building
@@ -194,7 +195,7 @@ The baresip project is using the BSD license.
## Contributing
-Patches can sent via Github
+Patches can be sent via Github
[Pull-Requests](https://github.com/creytiv/baresip/pulls) or to the RE devel
[mailing-list](http://lists.creytiv.com/mailman/listinfo/re-devel).
@@ -229,6 +230,7 @@ codec2 Codec2 low bit rate speech codec
cons UDP/TCP console UI driver
contact Contacts module
coreaudio Apple Coreaudio driver
+ctrl_tcp TCP control interface using JSON payload
debug_cmd Debug commands
directfb DirectFB video display module
dshow Windows DirectShow video source
diff --git a/docs/COPYING b/docs/COPYING
index 938d6cc..7bcab4f 100644
--- a/docs/COPYING
+++ b/docs/COPYING
@@ -1,6 +1,6 @@
-Copyright (c) 2010 - 2017, Alfred E. Heggestad
-Copyright (c) 2010 - 2017, Richard Aas
-Copyright (c) 2010 - 2017, Creytiv.com
+Copyright (c) 2010 - 2018, Alfred E. Heggestad
+Copyright (c) 2010 - 2018, Richard Aas
+Copyright (c) 2010 - 2018, Creytiv.com
All rights reserved.
diff --git a/docs/ChangeLog b/docs/ChangeLog
index d79818e..c598849 100644
--- a/docs/ChangeLog
+++ b/docs/ChangeLog
@@ -1,3 +1,181 @@
+2018-04-21 Alfred E. Heggestad <alfred.heggestad@gmail.com>
+
+ * Version 0.5.9
+
+ * GIT URL: https://github.com/alfredh/baresip.git
+ * GIT tag: v0.5.9
+ * NOTE: Requires libre v0.5.7 or later
+ Requires librem v0.5.2 or later
+
+ * build:
+ - Updated MSVS project to VS15 and added several files
+ to project settings (thanks Encamy)
+
+ * config:
+
+ video_fps 29.97 # float
+
+ * baresip-core:
+ - conf: add conf_get_float
+ - timer: add tmr_jiffies_usec
+ - timestamp: new file for timestamp helpers
+ - ua: add catchall flag to struct ua
+ - ua: add ua_set_catchall
+ - ua: uag_find: return match if catchall flag is set
+ - vidcodec: change rtp_ts from 32-bit to 64-bit
+ - videnc: change framerate to double float
+ - video: change framerate to double float
+ - vidsrc: add frame timestamp
+ - vidsrc: change framerate to double float
+
+ * selftest:
+ - mediaenc: add testcase for media encryption
+
+ * Modules:
+
+ * avcapture: add support for video frame timestamp
+
+ * avcodec: fix compiling with old ffmpeg versions
+ print framerate of decoded bitstream
+
+ * avformat: add support for video frame timestamp
+
+ * b2bua: add handling of all inbound SIP requests
+
+ * cairo: add support for video frame timestamp
+
+ * ctrl_tcp: Fix #369. documentation typo (#372)
+ Fix #370. wrong assignent (#371)
+ (thanks José Luis Millán)
+
+ * dshow: add support for video frame timestamp
+
+ * fakevideo: add support for video frame timestamp
+ add support for timer polling (no pthreads)
+
+ * menu: added "statmode_default" config variable (#359)
+ (thanks Juha Heinanen)
+
+ * rst: add support for video frame timestamp
+
+ * swscale: add YUV444P pixel format
+
+ * v4l: add support for video frame timestamp
+
+ * v4l2: add support for video frame timestamp
+ show actual framerate
+
+ * vidbridge: add support for video frame timestamp
+
+ * vidloop: add videoloop summary
+
+ * x11grab: add support for video frame timestamp
+
+
+2018-02-11 Alfred E. Heggestad <alfred.heggestad@gmail.com>
+
+ * Version 0.5.8
+
+ * GIT URL: https://github.com/alfredh/baresip.git
+ * GIT tag: v0.5.8
+ * NOTE: Requires libre v0.5.7 or later
+ Requires librem v0.5.2 or later
+
+ * new commands:
+
+ - /aubitrate 64000 -- Set audio bitrate
+
+ * new modules:
+
+ - ctrl_tcp TCP control interface using JSON payload
+ (thanks José Luis Millán)
+
+ * config:
+
+ auenc_format s16 # s16, float, ..
+ audec_format s16 # s16, float, ..
+
+ videnc_format yuv420p # yuv420p, yuv444p, ..
+
+ * baresip-core:
+ - account: password in SIP uri is now deprecated
+ - aucodec: add encoder/decoder audio sample format (#352)
+ - aucodec: add bitrate to encoder param
+ - audio: add function to set encoder bitrate
+ - audio: sample format for audio encoder/decoder
+ - call: add call_id accessor
+ - call: fix memory leak in case sipsess_connect() fails
+ - config: add configurable video pixel format
+ - config: set exact installation pathes at build time (#354)
+ (thanks Guillaume Rousse)
+ - event: fix memory leak
+ - event: add call-id to JSON dict
+ - log: rename log_enable_stderr to log_enable_stdout
+ - metric: fix calculation of average bitrate
+ - reg: add display-name to SIP register
+ - stream: print a message when incoming RTP stream is established
+ - timer: add tmr_jiffies_usec
+ - video: save and show pixel format of incoming video
+ - vidutil: new file for video utility functions
+
+ * selftest:
+ - event: add testcase for events
+ - sip: make 'struct user' opaque
+ - ua: update password using ;auth_pass=XXX parameter
+
+ * Modules:
+
+ * account: update template with auth_pass parameter
+
+ * amr: update aucodec API with audio sample format
+
+ * avcodec: Return EPROTO when encountering missing fragments in
+ H264 stream, to trigger intra-frame request (#339)
+ (thanks Jonathan Sieber)
+ use AV_INPUT_BUFFER_MIN_SIZE (ref #351)
+ add support for YUV444P pixel format
+
+ * avformat: use av_dump_format()
+
+ * bv32: update aucodec API with audio sample format
+
+ * codec2: update aucodec API with audio sample format
+
+ * ctrl_tcp: new module for TCP control interface using JSON payload
+ (thanks José Luis Millán)
+
+ * g711: update aucodec API with audio sample format
+
+ * g722: update aucodec API with audio sample format
+
+ * g7221: update aucodec API with audio sample format
+
+ * g726: update aucodec API with audio sample format
+
+ * gsm: update aucodec API with audio sample format
+
+ * gst1: define _POSIX_C_SOURCE to make nanosleep visible
+
+ * l16: update aucodec API with audio sample format
+
+ * mpa: update aucodec API with audio sample format
+
+ * mqtt: update README with correct JSON syntax (ref #356)
+
+ * omx: fix compilation for Raspbian
+
+ * opus: update aucodec API with audio sample format
+ add support for FLOAT sample format
+
+ * silk: update aucodec API with audio sample format
+
+ * speex: deprecate, disable as autodetected module
+
+ * speex_aec: always link to libspeexdsp
+
+ * speex_pp: always link to libspeexdsp
+
+
2017-12-25 Alfred E. Heggestad <alfred.heggestad@gmail.com>
* Version 0.5.7
diff --git a/docs/examples/accounts b/docs/examples/accounts
index 2b4a39c..ca4f2a8 100644
--- a/docs/examples/accounts
+++ b/docs/examples/accounts
@@ -40,19 +40,19 @@
#
# Use SIP Outbound over TCP, with ICE for Media NAT Traversal, and DTLS-SRTP for encryption
#
-<sip:user:pass@example.com>;sipnat=outbound;outbound="sip:example.com;transport=tcp";medianat=ice;mediaenc=dtls_srtp
+<sip:user@example.com>;sipnat=outbound;outbound="sip:example.com;transport=tcp";medianat=ice;mediaenc=dtls_srtp;auth_pass=pass
#
# Use ICE for Media NAT Traversal, using a specific STUN-server
#
-<sip:user:pass@example.com>;medianat=ice;stunserver="stun:username:password@stunserver.org"
+<sip:user@example.com>;medianat=ice;stunserver="stun:username:password@stunserver.org";auth_pass=pass
#
# Force audio-codec 'opus' and video-codec 'vp8'
#
-<sip:user:pass@example.com>;audio_codecs=opus/48000/2;video_codecs=vp8
+<sip:user@example.com>;audio_codecs=opus/48000/2;video_codecs=vp8;auth_pass=pass
# ... more examples can be added here ...
diff --git a/include/baresip.h b/include/baresip.h
index 746a95e..57369ef 100644
--- a/include/baresip.h
+++ b/include/baresip.h
@@ -13,7 +13,7 @@ extern "C" {
/** Defines the Baresip version string */
-#define BARESIP_VERSION "0.5.7"
+#define BARESIP_VERSION "0.5.9"
#ifndef NET_MAX_NS
@@ -21,6 +21,12 @@ extern "C" {
#endif
+/*
+ * Clock-rate for video timestamp
+ */
+#define VIDEO_TIMEBASE 1000000U
+
+
/* forward declarations */
struct sa;
struct sdp_media;
@@ -113,6 +119,7 @@ void call_set_handlers(struct call *call, call_event_h *eh,
uint16_t call_scode(const struct call *call);
uint32_t call_duration(const struct call *call);
uint32_t call_setup_duration(const struct call *call);
+const char *call_id(const struct call *call);
const char *call_peeruri(const struct call *call);
const char *call_peername(const struct call *call);
const char *call_localuri(const struct call *call);
@@ -205,6 +212,8 @@ struct config_audio {
bool level; /**< Enable audio level indication */
int src_fmt; /**< Audio source sample format */
int play_fmt; /**< Audio playback sample format */
+ int enc_fmt; /**< Audio encoder sample format */
+ int dec_fmt; /**< Audio decoder sample format */
};
#ifdef USE_VIDEO
@@ -216,8 +225,9 @@ struct config_video {
char disp_dev[128]; /**< Video display device */
unsigned width, height; /**< Video resolution */
uint32_t bitrate; /**< Encoder bitrate in [bit/s] */
- uint32_t fps; /**< Video framerate */
+ double fps; /**< Video framerate */
bool fullscreen; /**< Enable fullscreen display */
+ int enc_fmt; /**< Encoder pixelfmt (enum vidfmt) */
};
#endif
@@ -486,7 +496,7 @@ void log_register_handler(struct log *logh);
void log_unregister_handler(struct log *logh);
void log_enable_debug(bool enable);
void log_enable_info(bool enable);
-void log_enable_stderr(bool enable);
+void log_enable_stdout(bool enable);
void vlog(enum log_level level, const char *fmt, va_list ap);
void loglv(enum log_level level, const char *fmt, ...);
void debug(const char *fmt, ...);
@@ -636,6 +646,7 @@ struct list *ua_calls(const struct ua *ua);
enum presence_status ua_presence_status(const struct ua *ua);
void ua_presence_status_set(struct ua *ua, const enum presence_status status);
void ua_set_media_af(struct ua *ua, int af_media);
+void ua_set_catchall(struct ua *ua, bool enabled);
/* One instance */
@@ -756,10 +767,18 @@ struct vidsrc_st;
/** Video Source parameters */
struct vidsrc_prm {
int orient; /**< Wanted picture orientation (enum vidorient) */
- int fps; /**< Wanted framerate */
+ double fps; /**< Wanted framerate */
};
-typedef void (vidsrc_frame_h)(struct vidframe *frame, void *arg);
+/**
+ * Provides video frames to the core
+ *
+ * @param frame Video frame
+ * @param timestamp Frame timestamp in VIDEO_TIMEBASE units
+ * @param arg Handler argument
+ */
+typedef void (vidsrc_frame_h)(struct vidframe *frame, uint64_t timestamp,
+ void *arg);
typedef void (vidsrc_error_h)(int err, void *arg);
typedef int (vidsrc_alloc_h)(struct vidsrc_st **vsp, const struct vidsrc *vs,
@@ -772,6 +791,14 @@ typedef int (vidsrc_alloc_h)(struct vidsrc_st **vsp, const struct vidsrc *vs,
typedef void (vidsrc_update_h)(struct vidsrc_st *st, struct vidsrc_prm *prm,
const char *dev);
+/** Defines a video source */
+struct vidsrc {
+ struct le le;
+ const char *name;
+ vidsrc_alloc_h *alloch;
+ vidsrc_update_h *updateh;
+};
+
int vidsrc_register(struct vidsrc **vp, struct list *vidsrcl, const char *name,
vidsrc_alloc_h *alloch, vidsrc_update_h *updateh);
const struct vidsrc *vidsrc_find(const struct list *vidsrcl, const char *name);
@@ -780,6 +807,7 @@ int vidsrc_alloc(struct vidsrc_st **stp, struct list *vidsrcl,
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 *vidsrc_get(struct vidsrc_st *st);
/*
@@ -807,6 +835,16 @@ typedef int (vidisp_disp_h)(struct vidisp_st *st, const char *title,
const struct vidframe *frame);
typedef void (vidisp_hide_h)(struct vidisp_st *st);
+/** Defines a Video display */
+struct vidisp {
+ struct le le;
+ const char *name;
+ vidisp_alloc_h *alloch;
+ vidisp_update_h *updateh;
+ vidisp_disp_h *disph;
+ vidisp_hide_h *hideh;
+};
+
int vidisp_register(struct vidisp **vp, struct list *vidispl, const char *name,
vidisp_alloc_h *alloch, vidisp_update_h *updateh,
vidisp_disp_h *disph, vidisp_hide_h *hideh);
@@ -817,6 +855,7 @@ int vidisp_alloc(struct vidisp_st **stp, struct list *vidispl,
int vidisp_display(struct vidisp_st *st, const char *title,
const struct vidframe *frame);
const struct vidisp *vidisp_find(const struct list *vidispl, const char *name);
+struct vidisp *vidisp_get(struct vidisp_st *st);
/*
@@ -826,6 +865,7 @@ const struct vidisp *vidisp_find(const struct list *vidispl, const char *name);
/** Audio Codec parameters */
struct auenc_param {
uint32_t ptime; /**< Packet time in [ms] */
+ uint32_t bitrate;/**< Wanted bitrate in [bit/s] */
};
struct auenc_state;
@@ -835,15 +875,17 @@ struct aucodec;
typedef int (auenc_update_h)(struct auenc_state **aesp,
const struct aucodec *ac,
struct auenc_param *prm, const char *fmtp);
-typedef int (auenc_encode_h)(struct auenc_state *aes, uint8_t *buf,
- size_t *len, const int16_t *sampv, size_t sampc);
+typedef int (auenc_encode_h)(struct auenc_state *aes,
+ uint8_t *buf, size_t *len,
+ int fmt, const void *sampv, size_t sampc);
typedef int (audec_update_h)(struct audec_state **adsp,
const struct aucodec *ac, const char *fmtp);
-typedef int (audec_decode_h)(struct audec_state *ads, int16_t *sampv,
- size_t *sampc, const uint8_t *buf, size_t len);
+typedef int (audec_decode_h)(struct audec_state *ads,
+ int fmt, void *sampv, size_t *sampc,
+ const uint8_t *buf, size_t len);
typedef int (audec_plc_h)(struct audec_state *ads,
- int16_t *sampv, size_t *sampc);
+ int fmt, void *sampv, size_t *sampc);
struct aucodec {
struct le le;
@@ -877,7 +919,7 @@ const struct aucodec *aucodec_find(const struct list *aucodecl,
struct videnc_param {
unsigned bitrate; /**< Encoder bitrate in [bit/s] */
unsigned pktsize; /**< RTP packetsize in [bytes] */
- unsigned fps; /**< Video framerate */
+ double fps; /**< Video framerate (max) */
uint32_t max_fs;
};
@@ -885,7 +927,7 @@ struct videnc_state;
struct viddec_state;
struct vidcodec;
-typedef int (videnc_packet_h)(bool marker, uint32_t rtp_ts,
+typedef int (videnc_packet_h)(bool marker, uint64_t rtp_ts,
const uint8_t *hdr, size_t hdr_len,
const uint8_t *pld, size_t pld_len,
void *arg);
@@ -986,6 +1028,8 @@ void audio_encoder_cycle(struct audio *audio);
int audio_level_get(const struct audio *au, double *level);
int audio_debug(struct re_printf *pf, const struct audio *a);
struct stream *audio_strm(const struct audio *a);
+int audio_set_bitrate(struct audio *au, uint32_t bitrate);
+bool audio_rxaubuf_started(struct audio *au);
/*
@@ -1003,9 +1047,10 @@ int video_set_source(struct video *v, const char *name, const char *dev);
void video_set_devicename(struct video *v, const char *src, const char *disp);
void video_encoder_cycle(struct video *video);
int video_debug(struct re_printf *pf, const struct video *v);
-uint32_t video_calc_rtp_timestamp(int64_t pts, unsigned fps);
-double video_calc_seconds(uint32_t rtp_ts);
+uint64_t video_calc_rtp_timestamp(int64_t pts, double fps);
+double video_calc_seconds(uint64_t rtp_ts);
struct stream *video_strm(const struct video *v);
+double video_timestamp_to_seconds(uint64_t timestamp);
/*
@@ -1135,12 +1180,13 @@ int h264_fu_hdr_decode(struct h264_fu *fu, struct mbuf *mb);
const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end);
-int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
+int h264_packetize(uint64_t rtp_ts, const uint8_t *buf, size_t len,
size_t pktsize, videnc_packet_h *pkth, void *arg);
int h264_nal_send(bool first, bool last,
- bool marker, uint32_t ihdr, uint32_t rtp_ts,
+ bool marker, uint32_t ihdr, uint64_t rtp_ts,
const uint8_t *buf, size_t size, size_t maxsz,
videnc_packet_h *pkth, void *arg);
+const char *h264_nalunit_name(int type);
static inline bool h264_is_keyframe(int type)
{
return type == H264_NAL_SPS;
@@ -1180,6 +1226,13 @@ int event_encode_dict(struct odict *od, struct ua *ua, enum ua_event ev,
/*
+ * Timer
+ */
+
+uint64_t tmr_jiffies_usec(void);
+
+
+/*
* Baresip instance
*/
diff --git a/mk/Doxyfile b/mk/Doxyfile
index 3606286..1697721 100644
--- a/mk/Doxyfile
+++ b/mk/Doxyfile
@@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = baresip
-PROJECT_NUMBER = 0.5.7
+PROJECT_NUMBER = 0.5.9
OUTPUT_DIRECTORY = ../baresip-dox
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
diff --git a/mk/modules.mk b/mk/modules.mk
index 9211dfd..a479e6a 100644
--- a/mk/modules.mk
+++ b/mk/modules.mk
@@ -171,11 +171,6 @@ USE_MPA := $(shell [ -f $(SYSROOT)/include/twolame.h ] || \
[ -f $(SYSROOT_ALT)/include/twolame.h ] && echo "yes")
endif
endif
-USE_SPEEX := $(shell [ -f $(SYSROOT)/include/speex.h ] || \
- [ -f $(SYSROOT)/include/speex/speex.h ] || \
- [ -f $(SYSROOT)/local/include/speex.h ] || \
- [ -f $(SYSROOT)/local/include/speex/speex.h ] || \
- [ -f $(SYSROOT_ALT)/include/speex/speex.h ] && echo "yes")
USE_SPEEX_AEC := $(shell [ -f $(SYSROOT)/include/speex/speex_echo.h ] || \
[ -f $(SYSROOT)/local/include/speex/speex_echo.h ] || \
[ -f $(SYSROOT_ALT)/include/speex/speex_echo.h ] && echo "yes")
@@ -275,6 +270,7 @@ MODULES += menu contact vumeter mwi account natpmp httpd
MODULES += srtp
MODULES += uuid
MODULES += debug_cmd
+MODULES += ctrl_tcp
ifneq ($(HAVE_LIBMQTT),)
MODULES += mqtt
@@ -285,10 +281,8 @@ MODULES += aubridge aufile
endif
ifneq ($(USE_VIDEO),)
MODULES += vidloop selfview vidbridge
-ifneq ($(HAVE_PTHREAD),)
MODULES += fakevideo
endif
-endif
ifneq ($(USE_ALSA),)
@@ -308,10 +302,10 @@ MODULES += avcodec
ifneq ($(USE_AVFORMAT),)
MODULES += avformat
endif
+endif
ifneq ($(USE_AVAHI),)
MODULES += avahi
endif
-endif
ifneq ($(USE_BV32),)
MODULES += bv32
endif
diff --git a/mk/win32/baresip.sln b/mk/win32/baresip.sln
index 7c791e8..a448d34 100644
--- a/mk/win32/baresip.sln
+++ b/mk/win32/baresip.sln
@@ -1,6 +1,8 @@
ďťż
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual C++ Express 2010
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.10
+MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "baresip-win32", "baresip.vcxproj", "{4B89C2D8-FB32-4D7C-9019-752A5664781C}"
ProjectSection(ProjectDependencies) = postProject
{3E767371-A72B-4F5C-A695-8F844B0889C5} = {3E767371-A72B-4F5C-A695-8F844B0889C5}
@@ -36,4 +38,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {8F3E56DF-4B18-4499-B228-37DC5DC474F9}
+ EndGlobalSection
EndGlobal
diff --git a/mk/win32/baresip.vcxproj b/mk/win32/baresip.vcxproj
index c321b5f..c561e77 100644
--- a/mk/win32/baresip.vcxproj
+++ b/mk/win32/baresip.vcxproj
@@ -1,5 +1,5 @@
ďťż<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -46,11 +46,14 @@
<IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\$(Platform)\$(Configuration)\tmp\mk\win32\</IntDir>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
</PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <CodeAnalysisRuleSet>BasicDesignGuidelineRules.ruleset</CodeAnalysisRuleSet>
+ </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>include;..\..\include;..\..\..\re\include;..\..\..\rem\include;..\..\..\misc;..\..\..\dirent\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;STATIC;HAVE_IO_H;HAVE_SELECT;USE_VIDEO;_CRT_SECURE_NO_DEPRECATE;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;STATIC;HAVE_IO_H;HAVE_SELECT;USE_VIDEO;_CRT_SECURE_NO_DEPRECATE;FD_SETSIZE=1024;SHARE_PATH="/usr/share/baresip";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@@ -61,6 +64,7 @@
<CompileAs>CompileAsC</CompileAs>
<DisableSpecificWarnings>4142;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<ObjectFileName>$(IntDir)%(RelativeDir)%(Filename).obj</ObjectFileName>
+ <AdditionalOptions>%(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalOptions>winmm.lib ..\..\..\re\$(Platform)\$(Configuration)\bin\re-win32.lib ..\..\..\rem\$(Platform)\$(Configuration)\bin\rem-win32.lib %(AdditionalOptions)</AdditionalOptions>
@@ -70,13 +74,13 @@
<ProgramDatabaseFile>$(OutDir)baresip-win32.pdb</ProgramDatabaseFile>
<SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<AdditionalIncludeDirectories>include;..\..\include;..\..\..\re\include;..\..\..\rem\include;..\..\..\misc;..\..\..\dirent\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <PreprocessorDefinitions>WIN32;STATIC;HAVE_IO_H;HAVE_SELECT;USE_VIDEO;_CRT_SECURE_NO_DEPRECATE;FD_SETSIZE=1024;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>WIN32;STATIC;HAVE_IO_H;HAVE_SELECT;USE_VIDEO;_CRT_SECURE_NO_DEPRECATE;FD_SETSIZE=1024;SHARE_PATH="/usr/share/baresip";%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<PrecompiledHeader>
</PrecompiledHeader>
@@ -94,7 +98,7 @@
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<TargetMachine>MachineX86</TargetMachine>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>Iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -197,6 +201,11 @@
<ClCompile Include="..\..\src\vidisp.c" />
<ClCompile Include="..\..\src\vidsrc.c" />
<ClCompile Include="static.c" />
+ <ClCompile Include="..\..\src\rtpext.c" />
+ <ClCompile Include="..\..\src\timestamp.c" />
+ <ClCompile Include="..\..\src\aulevel.c" />
+ <ClCompile Include="..\..\src\vidutil.c" />
+ <ClCompile Include="..\..\src\event.c" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
diff --git a/mk/win32/baresip.vcxproj.filters b/mk/win32/baresip.vcxproj.filters
index 5098a2b..26999f5 100644
--- a/mk/win32/baresip.vcxproj.filters
+++ b/mk/win32/baresip.vcxproj.filters
@@ -362,5 +362,10 @@
<ClCompile Include="..\..\modules\winwave\winwave.c">
<Filter>modules\winwave</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\rtpext.c" />
+ <ClCompile Include="..\..\src\timestamp.c" />
+ <ClCompile Include="..\..\src\aulevel.c" />
+ <ClCompile Include="..\..\src\vidutil.c" />
+ <ClCompile Include="..\..\src\event.c" />
</ItemGroup>
</Project> \ No newline at end of file
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;
diff --git a/rpm/baresip.spec b/rpm/baresip.spec
index de6170f..27d1088 100644
--- a/rpm/baresip.spec
+++ b/rpm/baresip.spec
@@ -1,5 +1,5 @@
%define name baresip
-%define ver 0.5.7
+%define ver 0.5.9
%define rel 1
Summary: Modular SIP useragent
diff --git a/src/account.c b/src/account.c
index 2a99e58..d7ab9c0 100644
--- a/src/account.c
+++ b/src/account.c
@@ -388,6 +388,9 @@ int account_alloc(struct account **accp, const char *sipaddr)
/* optional password prompt */
if (pl_isset(&acc->laddr.uri.password)) {
+ warning("account: username:password is now deprecated"
+ " please use ;auth_pass=xxx instead\n");
+
err = re_sdprintf(&acc->auth_pass, "%H",
uri_password_unescape,
&acc->laddr.uri.password);
diff --git a/src/audio.c b/src/audio.c
index 17eb5f6..b2b3cca 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -81,23 +81,24 @@ struct autx {
struct auenc_state *enc; /**< Audio encoder state (optional) */
struct aubuf *aubuf; /**< Packetize outgoing stream */
size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */
- volatile bool aubuf_started;
+ volatile bool aubuf_started; /**< Aubuf was started flag */
struct auresamp resamp; /**< Optional resampler for DSP */
struct list filtl; /**< Audio filters in encoding order */
struct mbuf *mb; /**< Buffer for outgoing RTP packets */
char device[64]; /**< Audio source device name */
- int16_t *sampv; /**< Sample buffer */
+ void *sampv; /**< Sample buffer */
int16_t *sampv_rs; /**< Sample buffer for resampler */
uint32_t ptime; /**< Packet time for sending */
uint64_t ts_ext; /**< Ext. Timestamp for outgoing RTP */
- uint32_t ts_base;
+ uint32_t ts_base; /**< First timestamp sent */
uint32_t ts_tel; /**< Timestamp for Telephony Events */
size_t psize; /**< Packet size for sending */
bool marker; /**< Marker bit for outgoing RTP */
bool muted; /**< Audio source is muted */
int cur_key; /**< Currently transmitted event */
- enum aufmt src_fmt;
- bool need_conv;
+ enum aufmt src_fmt; /**< Sample format for audio source */
+ enum aufmt enc_fmt; /**< Sample format for encoder */
+ bool need_conv; /**< Sample format conversion needed */
struct {
uint64_t aubuf_overrun;
@@ -137,24 +138,25 @@ struct aurx {
struct audec_state *dec; /**< Audio decoder state (optional) */
struct aubuf *aubuf; /**< Incoming audio buffer */
size_t aubuf_maxsz; /**< Maximum aubuf size in [bytes] */
- volatile bool aubuf_started;
+ volatile bool aubuf_started; /**< Aubuf was started flag */
struct auresamp resamp; /**< Optional resampler for DSP */
struct list filtl; /**< Audio filters in decoding order */
char device[64]; /**< Audio player device name */
- int16_t *sampv; /**< Sample buffer */
+ void *sampv; /**< Sample buffer */
int16_t *sampv_rs; /**< Sample buffer for resampler */
uint32_t ptime; /**< Packet time for receiving */
int pt; /**< Payload type for incoming RTP */
double level_last;
bool level_set;
- enum aufmt play_fmt;
- bool need_conv;
- struct timestamp_recv ts_recv;
- uint64_t n_discard;
+ enum aufmt play_fmt; /**< Sample format for audio playback*/
+ enum aufmt dec_fmt; /**< Sample format for decoder */
+ bool need_conv; /**< Sample format conversion needed */
+ struct timestamp_recv ts_recv;/**< Receive timestamp state */
struct {
uint64_t aubuf_overrun;
uint64_t aubuf_underrun;
+ uint64_t n_discard;
} stats;
};
@@ -309,7 +311,7 @@ static inline double calc_ptime(size_t nsamp, uint32_t srate, uint8_t channels)
/**
- * Get the DSP samplerate for an audio-codec (exception for G.722 and MPA)
+ * Get the DSP samplerate for an audio-codec
*/
static inline uint32_t get_srate(const struct aucodec *ac)
{
@@ -448,7 +450,9 @@ static void encode_rtp_send(struct audio *a, struct autx *tx,
len = mbuf_get_space(tx->mb);
- err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len, sampv, sampc);
+ err = tx->ac->ench(tx->enc, mbuf_buf(tx->mb), &len,
+ tx->enc_fmt, sampv, sampc);
+
if ((err & 0xffff0000) == 0x00010000) {
/* MPA needs some special treatment here */
tx->ts_ext = err & 0xffff;
@@ -514,11 +518,12 @@ static void poll_aubuf_tx(struct audio *a)
/* timed read from audio-buffer */
- if (tx->src_fmt == AUFMT_S16LE) {
+ if (tx->src_fmt == tx->enc_fmt) {
aubuf_read(tx->aubuf, (uint8_t *)tx->sampv, num_bytes);
}
- else {
+ else if (tx->enc_fmt == AUFMT_S16LE) {
+
/* Convert from ausrc format to 16-bit format */
void *tmp_sampv;
@@ -540,11 +545,23 @@ static void poll_aubuf_tx(struct audio *a)
mem_deref(tmp_sampv);
}
+ else {
+ warning("audio: tx: invalid sample formats (%s -> %s)\n",
+ aufmt_name(tx->src_fmt),
+ aufmt_name(tx->enc_fmt));
+ }
/* optional resampler */
if (tx->resamp.resample) {
size_t sampc_rs = AUDIO_SAMPSZ;
+ if (tx->enc_fmt != AUFMT_S16LE) {
+ warning("audio: skipping resampler due to"
+ " incompatible format (%s)\n",
+ aufmt_name(tx->enc_fmt));
+ return;
+ }
+
err = auresamp(&tx->resamp,
tx->sampv_rs, &sampc_rs,
tx->sampv, sampc);
@@ -555,15 +572,23 @@ static void poll_aubuf_tx(struct audio *a)
sampc = sampc_rs;
}
- /* Process exactly one audio-frame in list order */
- for (le = tx->filtl.head; le; le = le->next) {
- struct aufilt_enc_st *st = le->data;
+ if (tx->enc_fmt == AUFMT_S16LE) {
+
+ /* Process exactly one audio-frame in list order */
+ for (le = tx->filtl.head; le; le = le->next) {
+ struct aufilt_enc_st *st = le->data;
- if (st->af && st->af->ench)
- err |= st->af->ench(st, sampv, &sampc);
+ if (st->af && st->af->ench)
+ err |= st->af->ench(st, sampv, &sampc);
+ }
+ if (err) {
+ warning("audio: aufilter encode: %m\n", err);
+ }
}
- if (err) {
- warning("audio: aufilter encode: %m\n", err);
+ else if (!list_isempty(&tx->filtl)) {
+ warning("audio: skipping audio-filters due to"
+ " incompatible format (%s)\n",
+ aufmt_name(tx->enc_fmt));
}
/* Encode and send */
@@ -623,8 +648,10 @@ static void auplay_write_handler(void *sampv, size_t sampc, void *arg)
++rx->stats.aubuf_underrun;
+#if 0
debug("audio: rx aubuf underrun (total %llu)\n",
rx->stats.aubuf_underrun);
+#endif
}
aubuf_read(rx->aubuf, sampv, num_bytes);
@@ -726,7 +753,7 @@ static void handle_telev(struct audio *a, struct mbuf *mb)
static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
{
size_t sampc = AUDIO_SAMPSZ;
- int16_t *sampv;
+ void *sampv;
struct le *le;
int err = 0;
@@ -735,13 +762,16 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
return 0;
if (mbuf_get_left(mb)) {
- err = rx->ac->dech(rx->dec, rx->sampv, &sampc,
+
+ err = rx->ac->dech(rx->dec,
+ rx->dec_fmt, rx->sampv, &sampc,
mbuf_buf(mb), mbuf_get_left(mb));
+
}
- else if (rx->ac->plch) {
+ else if (rx->ac->plch && rx->dec_fmt == AUFMT_S16LE) {
sampc = rx->ac->srate * rx->ac->ch * rx->ptime / 1000;
- err = rx->ac->plch(rx->dec, rx->sampv, &sampc);
+ err = rx->ac->plch(rx->dec, rx->dec_fmt, rx->sampv, &sampc);
}
else {
/* no PLC in the codec, might be done in filters below */
@@ -754,12 +784,19 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
goto out;
}
- /* Process exactly one audio-frame in reverse list order */
- for (le = rx->filtl.tail; le; le = le->prev) {
- struct aufilt_dec_st *st = le->data;
+ if (rx->dec_fmt == AUFMT_S16LE) {
+ /* Process exactly one audio-frame in reverse list order */
+ for (le = rx->filtl.tail; le; le = le->prev) {
+ struct aufilt_dec_st *st = le->data;
- if (st->af && st->af->dech)
- err |= st->af->dech(st, rx->sampv, &sampc);
+ if (st->af && st->af->dech)
+ err |= st->af->dech(st, rx->sampv, &sampc);
+ }
+ }
+ else if (!list_isempty(&rx->filtl)) {
+ warning("audio: skipping audio-filters due to"
+ " incompatible format (%s)\n",
+ aufmt_name(rx->dec_fmt));
}
if (!rx->aubuf)
@@ -771,6 +808,13 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
if (rx->resamp.resample) {
size_t sampc_rs = AUDIO_SAMPSZ;
+ if (rx->dec_fmt != AUFMT_S16LE) {
+ warning("audio: skipping resampler due to"
+ " incompatible format (%s)\n",
+ aufmt_name(rx->dec_fmt));
+ return ENOTSUP;
+ }
+
err = auresamp(&rx->resamp,
rx->sampv_rs, &sampc_rs,
rx->sampv, sampc);
@@ -789,15 +833,17 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
rx->stats.aubuf_overrun);
}
- if (rx->play_fmt == AUFMT_S16LE) {
- err = aubuf_write_samp(rx->aubuf, sampv, sampc);
+ if (rx->play_fmt == rx->dec_fmt) {
+
+ size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt);
+
+ err = aubuf_write(rx->aubuf, sampv, num_bytes);
if (err)
goto out;
}
- else {
+ else if (rx->dec_fmt == AUFMT_S16LE) {
/* Convert from 16-bit to auplay format */
-
void *tmp_sampv;
size_t num_bytes = sampc * aufmt_sample_size(rx->play_fmt);
@@ -822,6 +868,11 @@ static int aurx_stream_decode(struct aurx *rx, struct mbuf *mb)
if (err)
goto out;
}
+ else {
+ warning("audio: decode: invalid sample formats (%s -> %s)\n",
+ aufmt_name(rx->dec_fmt),
+ aufmt_name(rx->play_fmt));
+ }
rx->aubuf_started = true;
@@ -945,7 +996,7 @@ static void stream_recv_handler(const struct rtp_header *hdr,
#endif
if (discard) {
- ++a->rx.n_discard;
+ ++rx->stats.n_discard;
return;
}
@@ -1057,6 +1108,9 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm,
tx->src_fmt = cfg->audio.src_fmt;
rx->play_fmt = cfg->audio.play_fmt;
+ tx->enc_fmt = cfg->audio.enc_fmt;
+ rx->dec_fmt = cfg->audio.dec_fmt;
+
err = stream_alloc(&a->strm, stream_prm, &cfg->avt, call, sdp_sess,
"audio", label,
mnat, mnat_sess, menc, menc_sess,
@@ -1101,8 +1155,11 @@ int audio_alloc(struct audio **ap, const struct stream_param *stream_prm,
}
tx->mb = mbuf_alloc(STREAM_PRESZ + 4096);
- tx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL);
- rx->sampv = mem_zalloc(AUDIO_SAMPSZ * sizeof(int16_t), NULL);
+ tx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(tx->enc_fmt),
+ NULL);
+
+ rx->sampv = mem_zalloc(AUDIO_SAMPSZ * aufmt_sample_size(rx->dec_fmt),
+ NULL);
if (!tx->mb || !tx->sampv || !rx->sampv) {
err = ENOMEM;
goto out;
@@ -1480,6 +1537,10 @@ static int start_source(struct autx *tx, struct audio *a)
}
switch (a->cfg.txmode) {
+
+ case AUDIO_MODE_POLL:
+ break;
+
#ifdef HAVE_PTHREAD
case AUDIO_MODE_THREAD:
if (!tx->u.thr.run) {
@@ -1495,7 +1556,9 @@ static int start_source(struct autx *tx, struct audio *a)
#endif
default:
- break;
+ warning("audio: tx mode not supported (%d)\n",
+ a->cfg.txmode);
+ return ENOTSUP;
}
tx->ausrc_prm = prm;
@@ -1602,6 +1665,7 @@ int audio_encoder_set(struct audio *a, const struct aucodec *ac,
struct auenc_param prm;
prm.ptime = tx->ptime;
+ prm.bitrate = 0; /* auto */
err = ac->encupdh(&tx->enc, ac, &prm, params);
if (err) {
@@ -1891,9 +1955,10 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
err = re_hprintf(pf, "\n--- Audio stream ---\n");
- err |= re_hprintf(pf, " tx: %H ptime=%ums\n",
+ err |= re_hprintf(pf, " tx: encode: %H ptime=%ums %s\n",
aucodec_print, tx->ac,
- tx->ptime);
+ tx->ptime,
+ aufmt_name(tx->enc_fmt));
err |= re_hprintf(pf, " aubuf: %H"
" (cur %.2fms, max %.2fms, or %llu, ur %llu)\n",
aubuf_debug, tx->aubuf,
@@ -1905,14 +1970,15 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
tx->ausrc_prm.ch),
tx->stats.aubuf_overrun,
tx->stats.aubuf_underrun);
-
+ err |= re_hprintf(pf, " source: %s\n",
+ aufmt_name(tx->src_fmt));
err |= re_hprintf(pf, " time = %.3f sec\n",
autx_calc_seconds(tx));
err |= re_hprintf(pf,
- " rx: %H\n"
+ " rx: decode: %H %s\n"
" ptime=%ums pt=%d\n",
- aucodec_print, rx->ac,
+ aucodec_print, rx->ac, aufmt_name(rx->dec_fmt),
rx->ptime, rx->pt);
err |= re_hprintf(pf, " aubuf: %H"
" (cur %.2fms, max %.2fms, or %llu, ur %llu)\n",
@@ -1926,9 +1992,9 @@ int audio_debug(struct re_printf *pf, const struct audio *a)
rx->stats.aubuf_overrun,
rx->stats.aubuf_underrun
);
-
+ err |= re_hprintf(pf, " player: %s\n", aufmt_name(rx->play_fmt));
err |= re_hprintf(pf, " n_discard:%llu\n",
- rx->n_discard);
+ rx->stats.n_discard);
if (rx->level_set) {
err |= re_hprintf(pf, " level %.3f dBov\n",
rx->level_last);
@@ -2079,3 +2145,57 @@ int audio_print_rtpstat(struct re_printf *pf, const struct audio *a)
return err;
}
+
+
+int audio_set_bitrate(struct audio *au, uint32_t bitrate)
+{
+ struct autx *tx;
+ const struct aucodec *ac;
+ int err;
+
+ if (!au)
+ return EINVAL;
+
+ tx = &au->tx;
+
+ ac = tx->ac;
+
+ info("audio: set bitrate for encoder '%s' to %u bits/s\n",
+ ac ? ac->name : "?",
+ bitrate);
+
+ if (ac) {
+
+ if (ac->encupdh) {
+ struct auenc_param prm;
+
+ prm.ptime = tx->ptime;
+ prm.bitrate = bitrate;
+
+ err = ac->encupdh(&tx->enc, ac, &prm, NULL);
+ if (err) {
+ warning("audio: encupdh error: %m\n", err);
+ return err;
+ }
+ }
+
+ }
+ else {
+ info("audio: set_bitrate: no audio encoder\n");
+ }
+
+ return 0;
+}
+
+
+bool audio_rxaubuf_started(struct audio *au)
+{
+ struct aurx *rx;
+
+ if (!au)
+ return false;
+
+ rx = &au->rx;
+
+ return rx->aubuf_started;
+}
diff --git a/src/call.c b/src/call.c
index 99bec4b..0868f68 100644
--- a/src/call.c
+++ b/src/call.c
@@ -59,6 +59,7 @@ struct call {
char *local_name; /**< Local display name */
char *peer_uri; /**< Peer SIP Address */
char *peer_name; /**< Peer display name */
+ char *id; /**< Cached session call-id */
struct tmr tmr_inv; /**< Timer for incoming calls */
struct tmr tmr_dtmf; /**< Timer for incoming DTMF events */
time_t time_start; /**< Time when call started */
@@ -378,6 +379,7 @@ static void call_destructor(void *arg)
tmr_cancel(&call->tmr_dtmf);
mem_deref(call->sess);
+ mem_deref(call->id);
mem_deref(call->local_uri);
mem_deref(call->local_name);
mem_deref(call->peer_uri);
@@ -901,6 +903,12 @@ int call_sdp_get(const struct call *call, struct mbuf **descp, bool offer)
}
+const char *call_id(const struct call *call)
+{
+ return call ? call->id : NULL;
+}
+
+
const char *call_peeruri(const struct call *call)
{
return call ? call->peer_uri : NULL;
@@ -940,10 +948,10 @@ int call_debug(struct re_printf *pf, const struct call *call)
err |= re_hprintf(pf,
" local_uri: %s <%s>\n"
" peer_uri: %s <%s>\n"
- " af=%s\n",
+ " af=%s id=%s\n",
call->local_name, call->local_uri,
call->peer_name, call->peer_uri,
- net_af2name(call->af));
+ net_af2name(call->af), call->id);
err |= re_hprintf(pf, " direction: %s\n",
call->outgoing ? "Outgoing" : "Incoming");
@@ -994,6 +1002,9 @@ int call_status(struct re_printf *pf, const struct call *call)
err |= video_print(pf, call->video);
#endif
+ /* remove old junk */
+ err |= re_hprintf(pf, " ");
+
return err;
}
@@ -1293,6 +1304,8 @@ static void sipsess_close_handler(int err, const struct sip_msg *msg,
if (err) {
info("%s: session closed: %m\n", call->peer_uri, err);
+ (void)re_snprintf(reason, sizeof(reason), "%m", err);
+
if (call->not) {
(void)call_notify_sipfrag(call, 500, "%m", err);
}
@@ -1421,6 +1434,11 @@ int call_accept(struct call *call, struct sipsess_sock *sess_sock,
return err;
}
+ err = str_dup(&call->id,
+ sip_dialog_callid(sipsess_dialog(call->sess)));
+ if (err)
+ return err;
+
set_state(call, STATE_INCOMING);
/* New call */
@@ -1525,11 +1543,16 @@ static int send_invite(struct call *call)
ua_print_supported, call->ua);
if (err) {
warning("call: sipsess_connect: %m\n", err);
+ goto out;
}
+ err = str_dup(&call->id,
+ sip_dialog_callid(sipsess_dialog(call->sess)));
+
/* save call setup timer */
call->time_conn = time(NULL);
+ out:
mem_deref(desc);
return err;
diff --git a/src/conf.c b/src/conf.c
index 2046216..2bb7d5a 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -289,6 +289,24 @@ int conf_get_sa(const struct conf *conf, const char *name, struct sa *sa)
}
+int conf_get_float(const struct conf *conf, const char *name, double *val)
+{
+ struct pl opt;
+ int err;
+
+ if (!conf || !name || !val)
+ return EINVAL;
+
+ err = conf_get(conf, name, &opt);
+ if (err)
+ return err;
+
+ *val = pl_float(&opt);
+
+ return 0;
+}
+
+
/**
* Configure the system with default settings
*
diff --git a/src/config.c b/src/config.c
index ce748d3..6c336d9 100644
--- a/src/config.c
+++ b/src/config.c
@@ -43,7 +43,7 @@ static struct config core_config = {
/** Audio */
{
- PREFIX "/share/baresip",
+ SHARE_PATH,
"","",
"","",
"","",
@@ -58,6 +58,8 @@ static struct config core_config = {
false,
AUFMT_S16LE,
AUFMT_S16LE,
+ AUFMT_S16LE,
+ AUFMT_S16LE,
},
#ifdef USE_VIDEO
@@ -69,6 +71,7 @@ static struct config core_config = {
500000,
25,
true,
+ VID_FMT_YUV420P,
},
#endif
@@ -178,6 +181,36 @@ static int conf_get_aufmt(const struct conf *conf, const char *name,
}
+#ifdef USE_VIDEO
+static int conf_get_vidfmt(const struct conf *conf, const char *name,
+ int *fmtp)
+{
+ struct pl pl;
+ int fmt;
+ int err;
+
+ err = conf_get(conf, name, &pl);
+ if (err)
+ return err;
+
+ for (fmt=0; fmt<VID_FMT_N; fmt++) {
+
+ const char *str = vidfmt_name(fmt);
+
+ if (0 == pl_strcasecmp(&pl, str)) {
+
+ *fmtp = fmt;
+ return 0;
+ }
+ }
+
+ warning("config: %s: pixel format not supported (%r)\n", name, &pl);
+
+ return ENOENT;
+}
+#endif
+
+
/**
* Parse the core configuration file and update baresip core config
*
@@ -270,6 +303,8 @@ int config_parse_conf(struct config *cfg, const struct conf *conf)
conf_get_aufmt(conf, "ausrc_format", &cfg->audio.src_fmt);
conf_get_aufmt(conf, "auplay_format", &cfg->audio.play_fmt);
+ conf_get_aufmt(conf, "auenc_format", &cfg->audio.enc_fmt);
+ conf_get_aufmt(conf, "audec_format", &cfg->audio.dec_fmt);
#ifdef USE_VIDEO
/* Video */
@@ -284,8 +319,10 @@ int config_parse_conf(struct config *cfg, const struct conf *conf)
cfg->video.height = size.h;
}
(void)conf_get_u32(conf, "video_bitrate", &cfg->video.bitrate);
- (void)conf_get_u32(conf, "video_fps", &cfg->video.fps);
+ (void)conf_get_float(conf, "video_fps", &cfg->video.fps);
(void)conf_get_bool(conf, "video_fullscreen", &cfg->video.fullscreen);
+
+ conf_get_vidfmt(conf, "videnc_format", &cfg->video.enc_fmt);
#else
(void)size;
#endif
@@ -352,7 +389,7 @@ int config_print(struct re_printf *pf, const struct config *cfg)
"\n"
"# Call\n"
"call_local_timeout\t%u\n"
- "call_max_calls\t%u\n"
+ "call_max_calls\t\t%u\n"
"\n"
"# Audio\n"
"audio_path\t\t%s\n"
@@ -373,7 +410,9 @@ int config_print(struct re_printf *pf, const struct config *cfg)
"video_display\t\t%s,%s\n"
"video_size\t\t\"%ux%u\"\n"
"video_bitrate\t\t%u\n"
- "video_fps\t\t%u\n"
+ "video_fps\t\t%.2f\n"
+ "video_fullscreen\t%s\n"
+ "videnc_format\t\t%s\n"
"\n"
#endif
"# AVT\n"
@@ -416,6 +455,8 @@ int config_print(struct re_printf *pf, const struct config *cfg)
cfg->video.disp_mod, cfg->video.disp_dev,
cfg->video.width, cfg->video.height,
cfg->video.bitrate, cfg->video.fps,
+ cfg->video.fullscreen ? "yes" : "no",
+ vidfmt_name(cfg->video.enc_fmt),
#endif
cfg->avt.rtp_tos,
@@ -467,6 +508,8 @@ static const char *default_video_device(void)
return "avcapture,nil";
#endif
+#elif defined (WIN32)
+ return "dshow,nil";
#else
return "v4l2,/dev/video0";
#endif
@@ -477,6 +520,8 @@ static const char *default_video_display(void)
{
#ifdef DARWIN
return "opengl,nil";
+#elif defined (WIN32)
+ return "sdl2,nil";
#else
return "x11,nil";
#endif
@@ -520,10 +565,12 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"\n"
"# Call\n"
"call_local_timeout\t%u\n"
- "call_max_calls\t%u\n"
+ "call_max_calls\t\t%u\n"
"\n"
"# Audio\n"
-#if defined (PREFIX)
+#if defined (SHARE_PATH)
+ "#audio_path\t\t" SHARE_PATH "\n"
+#elif defined (PREFIX)
"#audio_path\t\t" PREFIX "/share/baresip\n"
#else
"#audio_path\t\t/usr/share/baresip\n"
@@ -541,6 +588,8 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"audio_level\t\tno\n"
"ausrc_format\t\ts16\t\t# s16, float, ..\n"
"auplay_format\t\ts16\t\t# s16, float, ..\n"
+ "auenc_format\t\ts16\t\t# s16, float, ..\n"
+ "audec_format\t\ts16\t\t# s16, float, ..\n"
,
poll_method_name(poll_method_best()),
cfg->call.local_timeout,
@@ -559,12 +608,15 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"#video_display\t\t%s\n"
"video_size\t\t%dx%d\n"
"video_bitrate\t\t%u\n"
- "video_fps\t\t%u\n"
- "video_fullscreen\tyes\n",
+ "video_fps\t\t%.2f\n"
+ "video_fullscreen\tyes\n"
+ "videnc_format\t\t%s\n"
+ ,
default_video_device(),
default_video_display(),
cfg->video.width, cfg->video.height,
- cfg->video.bitrate, cfg->video.fps);
+ cfg->video.bitrate, cfg->video.fps,
+ vidfmt_name(cfg->video.enc_fmt));
#endif
err |= re_hprintf(pf,
@@ -624,7 +676,9 @@ static uint32_t count_modules(const char *path)
static const char *detect_module_path(bool *valid)
{
static const char * const pathv[] = {
-#if defined (PREFIX)
+#if defined (MOD_PATH)
+ MOD_PATH,
+#elif defined (PREFIX)
"" PREFIX "/lib/baresip/modules",
#else
"/usr/local/lib/baresip/modules",
@@ -853,6 +907,7 @@ int config_write_template(const char *file, const struct config *cfg)
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "presence"MOD_EXT"\n");
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "syslog"MOD_EXT"\n");
(void)re_fprintf(f, "#module_app\t\t" MOD_PRE "mqtt" MOD_EXT "\n");
+ (void)re_fprintf(f, "#module_app\t\t" MOD_PRE "ctrl_tcp" MOD_EXT "\n");
#ifdef USE_VIDEO
(void)re_fprintf(f, "module_app\t\t" MOD_PRE "vidloop"MOD_EXT"\n");
#endif
@@ -870,6 +925,9 @@ int config_write_template(const char *file, const struct config *cfg)
(void)re_fprintf(f, "http_listen\t\t0.0.0.0:8000\n");
(void)re_fprintf(f, "\n");
+ (void)re_fprintf(f, "ctrl_tcp_listen\t\t0.0.0.0:4444\n");
+
+ (void)re_fprintf(f, "\n");
(void)re_fprintf(f, "evdev_device\t\t/dev/input/event0\n");
(void)re_fprintf(f, "\n# Speex codec parameters\n");
diff --git a/src/core.h b/src/core.h
index a390e0c..ca11ab8 100644
--- a/src/core.h
+++ b/src/core.h
@@ -35,7 +35,8 @@ enum {
/** Media constants */
enum {
- AUDIO_BANDWIDTH = 128000 /**< Bandwidth for audio in bits/s */
+ AUDIO_BANDWIDTH = 128000, /**< Bandwidth for audio in bits/s */
+ VIDEO_SRATE = 90000, /**< Sampling rate for video */
};
@@ -200,6 +201,7 @@ int conf_get_range(const struct conf *conf, const char *name,
struct range *rng);
int conf_get_csv(const struct conf *conf, const char *name,
char *str1, size_t sz1, char *str2, size_t sz2);
+int conf_get_float(const struct conf *conf, const char *name, double *val);
/*
@@ -249,7 +251,7 @@ struct metric {
void metric_init(struct metric *metric);
void metric_reset(struct metric *metric);
void metric_add_packet(struct metric *metric, size_t packetsize);
-uint32_t metric_avg_bitrate(const struct metric *metric);
+double metric_avg_bitrate(const struct metric *metric);
/*
@@ -376,6 +378,7 @@ struct stream {
uint64_t ts_last; /**< Timestamp of last received RTP pkt */
bool terminated; /**< Stream is terminated flag */
uint32_t rtp_timeout_ms; /**< RTP Timeout value in [ms] */
+ bool rtp_estab; /**< True if RTP stream is established */
};
int stream_alloc(struct stream **sp, const struct stream_param *prm,
@@ -419,36 +422,6 @@ const char *uag_allowed_methods(void);
/*
- * Video Display
- */
-
-struct vidisp {
- struct le le;
- const char *name;
- vidisp_alloc_h *alloch;
- vidisp_update_h *updateh;
- vidisp_disp_h *disph;
- vidisp_hide_h *hideh;
-};
-
-struct vidisp *vidisp_get(struct vidisp_st *st);
-
-
-/*
- * Video Source
- */
-
-struct vidsrc {
- struct le le;
- const char *name;
- vidsrc_alloc_h *alloch;
- vidsrc_update_h *updateh;
-};
-
-struct vidsrc *vidsrc_get(struct vidsrc_st *st);
-
-
-/*
* Video Stream
*/
@@ -503,39 +476,5 @@ static inline uint64_t calc_extended_timestamp(uint32_t num_wraps, uint32_t ts)
}
-static inline uint64_t timestamp_duration(const struct timestamp_recv *ts)
-{
- uint64_t last_ext;
-
- if (!ts || !ts->is_set)
- return 0;
-
- last_ext = calc_extended_timestamp(ts->num_wraps, ts->last);
-
- return last_ext - ts->first;
-}
-
-
-/*
- * -1 backwards wrap-around
- * 0 no wrap-around
- * 1 forward wrap-around
- */
-static inline int timestamp_wrap(uint32_t ts_new, uint32_t ts_old)
-{
- int32_t delta;
-
- if (ts_new < ts_old) {
-
- delta = (int32_t)ts_new - (int32_t)ts_old;
-
- if (delta > 0)
- return 1;
- }
- else if ((int32_t)(ts_old - ts_new) > 0) {
-
- return -1;
- }
-
- return 0;
-}
+int timestamp_wrap(uint32_t ts_new, uint32_t ts_old);
+uint64_t timestamp_duration(const struct timestamp_recv *ts);
diff --git a/src/event.c b/src/event.c
index b29ab8b..94db0d2 100644
--- a/src/event.c
+++ b/src/event.c
@@ -79,6 +79,8 @@ static int add_rtcp_stats(struct odict *od_parent, const struct rtcp_stats *rs)
out:
mem_deref(od);
+ mem_deref(tx);
+ mem_deref(rx);
return err;
}
@@ -96,7 +98,12 @@ int event_encode_dict(struct odict *od, struct ua *ua, enum ua_event ev,
err |= odict_entry_add(od, "type", ODICT_STRING, event_str);
err |= odict_entry_add(od, "class",
ODICT_STRING, event_class_name(ev));
- err |= odict_entry_add(od, "accountaor", ODICT_STRING, ua_aor(ua));
+
+ if (ua) {
+ err |= odict_entry_add(od, "accountaor",
+ ODICT_STRING, ua_aor(ua));
+ }
+
if (err)
goto out;
@@ -109,6 +116,7 @@ int event_encode_dict(struct odict *od, struct ua *ua, enum ua_event ev,
err |= odict_entry_add(od, "direction", ODICT_STRING, dir);
err |= odict_entry_add(od, "peeruri",
ODICT_STRING, call_peeruri(call));
+ err |= odict_entry_add(od, "id", ODICT_STRING, call_id(call));
if (err)
goto out;
}
diff --git a/src/h264.c b/src/h264.c
index 2bb4a26..3786559 100644
--- a/src/h264.c
+++ b/src/h264.c
@@ -104,7 +104,7 @@ const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end)
static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz,
const uint8_t *buf, size_t sz,
- bool eof, uint32_t rtp_ts,
+ bool eof, uint64_t rtp_ts,
videnc_packet_h *pkth, void *arg)
{
return pkth(eof, rtp_ts, hdr, hdr_sz, buf, sz, arg);
@@ -112,7 +112,7 @@ static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz,
int h264_nal_send(bool first, bool last,
- bool marker, uint32_t ihdr, uint32_t rtp_ts,
+ bool marker, uint32_t ihdr, uint64_t rtp_ts,
const uint8_t *buf, size_t size, size_t maxsz,
videnc_packet_h *pkth, void *arg)
{
@@ -153,7 +153,7 @@ int h264_nal_send(bool first, bool last,
}
-int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
+int h264_packetize(uint64_t rtp_ts, const uint8_t *buf, size_t len,
size_t pktsize, videnc_packet_h *pkth, void *arg)
{
const uint8_t *start = buf;
@@ -180,3 +180,33 @@ int h264_packetize(uint32_t rtp_ts, const uint8_t *buf, size_t len,
return err;
}
+
+
+/**
+ * Get the name of an H.264 nal unit
+ *
+ * @param type NAL unit type
+ *
+ * @return A string containing the NAL unit name
+ */
+const char *h264_nalunit_name(int type)
+{
+ switch (type) {
+
+ case H264_NAL_SLICE: return "SLICE";
+ case H264_NAL_DPA: return "DPA";
+ case H264_NAL_DPB: return "DPB";
+ case H264_NAL_DPC: return "DPC";
+ case H264_NAL_IDR_SLICE: return "IDR_SLICE";
+ case H264_NAL_SEI: return "SEI";
+ case H264_NAL_SPS: return "SPS";
+ case H264_NAL_PPS: return "PPS";
+ case H264_NAL_AUD: return "AUD";
+ case H264_NAL_FILLER_DATA: return "FILLER";
+
+ case H264_NAL_FU_A: return "FU-A";
+ case H264_NAL_FU_B: return "FU-B";
+ }
+
+ return "???";
+}
diff --git a/src/log.c b/src/log.c
index 650689d..c9debdd 100644
--- a/src/log.c
+++ b/src/log.c
@@ -12,7 +12,7 @@ static struct {
struct list logl;
bool debug;
bool info;
- bool stder;
+ bool enable_stdout;
} lg = {
LIST_INIT,
false,
@@ -21,6 +21,11 @@ static struct {
};
+/**
+ * Register a log handler
+ *
+ * @param log Log handler
+ */
void log_register_handler(struct log *log)
{
if (!log)
@@ -30,6 +35,11 @@ void log_register_handler(struct log *log)
}
+/**
+ * Unregister a log handler
+ *
+ * @param log Log handler
+ */
void log_unregister_handler(struct log *log)
{
if (!log)
@@ -39,24 +49,46 @@ void log_unregister_handler(struct log *log)
}
+/**
+ * Enable debug-level logging
+ *
+ * @param enable True to enable, false to disable
+ */
void log_enable_debug(bool enable)
{
lg.debug = enable;
}
+/**
+ * Enable info-level logging
+ *
+ * @param enable True to enable, false to disable
+ */
void log_enable_info(bool enable)
{
lg.info = enable;
}
-void log_enable_stderr(bool enable)
+/**
+ * Enable logging to standard-out
+ *
+ * @param enable True to enable, false to disable
+ */
+void log_enable_stdout(bool enable)
{
- lg.stder = enable;
+ lg.enable_stdout = enable;
}
+/**
+ * Print a message to the logging system
+ *
+ * @param level Log level
+ * @param fmt Formatted message
+ * @param ap Variable argument list
+ */
void vlog(enum log_level level, const char *fmt, va_list ap)
{
char buf[4096];
@@ -65,7 +97,7 @@ void vlog(enum log_level level, const char *fmt, va_list ap)
if (re_vsnprintf(buf, sizeof(buf), fmt, ap) < 0)
return;
- if (lg.stder) {
+ if (lg.enable_stdout) {
bool color = level == LEVEL_WARN || level == LEVEL_ERROR;
@@ -91,6 +123,13 @@ void vlog(enum log_level level, const char *fmt, va_list ap)
}
+/**
+ * Print a message to the logging system
+ *
+ * @param level Log level
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void loglv(enum log_level level, const char *fmt, ...)
{
va_list ap;
@@ -107,6 +146,12 @@ void loglv(enum log_level level, const char *fmt, ...)
}
+/**
+ * Print a DEBUG message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void debug(const char *fmt, ...)
{
va_list ap;
@@ -120,6 +165,12 @@ void debug(const char *fmt, ...)
}
+/**
+ * Print an INFO message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void info(const char *fmt, ...)
{
va_list ap;
@@ -133,6 +184,12 @@ void info(const char *fmt, ...)
}
+/**
+ * Print a WARNING message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void warning(const char *fmt, ...)
{
va_list ap;
@@ -143,6 +200,12 @@ void warning(const char *fmt, ...)
}
+/**
+ * Print an ERROR message to the logging system
+ *
+ * @param fmt Formatted message
+ * @param ... Variable arguments
+ */
void error_msg(const char *fmt, ...)
{
va_list ap;
diff --git a/src/main.c b/src/main.c
index b789648..05742d8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -78,7 +78,7 @@ int main(int argc, char *argv[])
int err;
(void)re_fprintf(stdout, "baresip v%s"
- " Copyright (C) 2010 - 2017"
+ " Copyright (C) 2010 - 2018"
" Alfred E. Heggestad et al.\n",
BARESIP_VERSION);
@@ -227,7 +227,7 @@ int main(int argc, char *argv[])
if (err)
goto out;
- log_enable_stderr(false);
+ log_enable_stdout(false);
}
info("baresip is ready.\n");
diff --git a/src/metric.c b/src/metric.c
index f3e8d06..85dad3c 100644
--- a/src/metric.c
+++ b/src/metric.c
@@ -77,7 +77,7 @@ void metric_add_packet(struct metric *metric, size_t packetsize)
}
-uint32_t metric_avg_bitrate(const struct metric *metric)
+double metric_avg_bitrate(const struct metric *metric)
{
int diff;
@@ -86,5 +86,5 @@ uint32_t metric_avg_bitrate(const struct metric *metric)
diff = (int)(tmr_jiffies() - metric->ts_start);
- return 1000 * 8 * (metric->n_bytes / diff);
+ return 1000.0 * 8 * (double)metric->n_bytes / (double)diff;
}
diff --git a/src/reg.c b/src/reg.c
index 23bb337..7756636 100644
--- a/src/reg.c
+++ b/src/reg.c
@@ -183,6 +183,7 @@ int reg_add(struct list *lst, struct ua *ua, int regid)
int reg_register(struct reg *reg, const char *reg_uri, const char *params,
uint32_t regint, const char *outbound)
{
+ struct account *acc;
const char *routev[1];
int err;
@@ -191,10 +192,12 @@ int reg_register(struct reg *reg, const char *reg_uri, const char *params,
reg->scode = 0;
routev[0] = outbound;
+ acc = ua_account(reg->ua);
reg->sipreg = mem_deref(reg->sipreg);
err = sipreg_register(&reg->sipreg, uag_sip(), reg_uri,
- ua_aor(reg->ua), ua_aor(reg->ua),
+ ua_aor(reg->ua),
+ acc ? acc->dispname : NULL, ua_aor(reg->ua),
regint, ua_local_cuser(reg->ua),
routev[0] ? routev : NULL,
routev[0] ? 1 : 0,
diff --git a/src/srcs.mk b/src/srcs.mk
index a35e0d8..be7906c 100644
--- a/src/srcs.mk
+++ b/src/srcs.mk
@@ -34,6 +34,8 @@ SRCS += rtpkeep.c
SRCS += sdp.c
SRCS += sipreq.c
SRCS += stream.c
+SRCS += timer.c
+SRCS += timestamp.c
SRCS += ua.c
SRCS += ui.c
@@ -46,6 +48,7 @@ SRCS += vidcodec.c
SRCS += vidfilt.c
SRCS += vidisp.c
SRCS += vidsrc.c
+SRCS += vidutil.c
endif
ifneq ($(STATIC),)
diff --git a/src/stream.c b/src/stream.c
index 38db2d6..e4fb655 100644
--- a/src/stream.c
+++ b/src/stream.c
@@ -110,8 +110,8 @@ static void print_rtp_stats(const struct stream *s)
,
sdp_media_name(s->sdp),
s->metric_tx.n_packets, s->metric_rx.n_packets,
- 1.0*metric_avg_bitrate(&s->metric_tx)/1000,
- 1.0*metric_avg_bitrate(&s->metric_rx)/1000,
+ 1.0*metric_avg_bitrate(&s->metric_tx)/1000.0,
+ 1.0*metric_avg_bitrate(&s->metric_rx)/1000.0,
s->metric_tx.n_err, s->metric_rx.n_err
);
@@ -223,6 +223,13 @@ static void rtp_handler(const struct sa *src, const struct rtp_header *hdr,
metric_add_packet(&s->metric_rx, mbuf_get_left(mb));
+ if (!s->rtp_estab) {
+ info("stream: incoming rtp for '%s' established"
+ ", receiving from %J\n",
+ sdp_media_name(s->sdp), src);
+ s->rtp_estab = true;
+ }
+
if (hdr->ssrc != s->ssrc_rx) {
if (s->ssrc_rx) {
flush = true;
diff --git a/src/timer.c b/src/timer.c
new file mode 100644
index 0000000..d12f650
--- /dev/null
+++ b/src/timer.c
@@ -0,0 +1,71 @@
+/**
+ * @file timer.c Timer functions
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+#define _BSD_SOURCE 1
+#define _DEFAULT_SOURCE 1
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <time.h>
+#endif
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Get the timer jiffies in microseconds [us]
+ *
+ * @return Jiffies in [us]
+ */
+uint64_t tmr_jiffies_usec(void)
+{
+ uint64_t jfs;
+
+#if defined(WIN32)
+ FILETIME ft;
+ ULARGE_INTEGER li;
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ jfs = li.QuadPart/10;
+#elif defined(HAVE_CLOCK_GETTIME)
+ struct timespec now;
+ clockid_t clock_id;
+
+#if defined (CLOCK_BOOTTIME)
+ clock_id = CLOCK_BOOTTIME;
+#else
+ clock_id = CLOCK_MONOTONIC;
+#endif
+
+ if (0 != clock_gettime(clock_id, &now)) {
+ warning("timer: clock_gettime() failed (%m)\n", errno);
+ return 0;
+ }
+
+ jfs = (long)now.tv_sec * (uint64_t)1000000;
+ jfs += now.tv_nsec / (uint64_t)1000;
+
+#else
+ struct timeval now;
+
+ if (0 != gettimeofday(&now, NULL)) {
+ warning("timer: gettimeofday() failed (%m)\n", errno);
+ return 0;
+ }
+
+ jfs = (long)now.tv_sec * (uint64_t)1000000;
+ jfs += now.tv_usec;
+#endif
+
+ return jfs;
+}
diff --git a/src/timestamp.c b/src/timestamp.c
new file mode 100644
index 0000000..dedf8d9
--- /dev/null
+++ b/src/timestamp.c
@@ -0,0 +1,65 @@
+/**
+ * @file timestamp.c Timestamp helpers
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+
+#include <re.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Check if a 32-bit timestamp wraps around
+ *
+ * @param ts_new Timestamp of the current packet
+ * @param ts_old Timestamp of the previous packet
+ *
+ * @return Integer describing the wrap-around
+
+ * @retval -1 backwards wrap-around
+ * @retval 0 no wrap-around
+ * @retval 1 forward wrap-around
+ */
+int timestamp_wrap(uint32_t ts_new, uint32_t ts_old)
+{
+ int32_t delta;
+
+ if (ts_new < ts_old) {
+
+ delta = (int32_t)ts_new - (int32_t)ts_old;
+
+ if (delta > 0)
+ return 1;
+ }
+ else if ((int32_t)(ts_old - ts_new) > 0) {
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Calculate the total timestamp duration, in timestamp units.
+ * The duration is calculated as the delta between the
+ * last extended timestamp and the first extended timestamp.
+ *
+ * @param ts Receiver timestamp struct
+ *
+ * @return Timestamp duration
+ */
+uint64_t timestamp_duration(const struct timestamp_recv *ts)
+{
+ uint64_t last_ext;
+
+ if (!ts || !ts->is_set)
+ return 0;
+
+ last_ext = calc_extended_timestamp(ts->num_wraps, ts->last);
+
+ return last_ext - ts->first;
+}
+
+
diff --git a/src/ua.c b/src/ua.c
index 0467e35..76023d5 100644
--- a/src/ua.c
+++ b/src/ua.c
@@ -30,6 +30,7 @@ struct ua {
int af; /**< Preferred Address Family */
int af_media; /**< Preferred Address Family for media */
enum presence_status my_status; /**< Presence Status */
+ bool catchall; /**< Catch all inbound requests */
};
struct ua_eh {
@@ -201,6 +202,8 @@ int ua_register(struct ua *ua)
acc->regint, acc->outboundv[i]);
if (err) {
warning("ua: SIP register failed: %m\n", err);
+
+ ua_event(ua, UA_EVENT_REGISTER_FAIL, NULL, "%m", err);
goto out;
}
}
@@ -837,7 +840,8 @@ void ua_hangup(struct ua *ua, struct call *call,
(void)call_hangup(call, scode, reason);
- ua_event(ua, UA_EVENT_CALL_CLOSED, call, reason);
+ ua_event(ua, UA_EVENT_CALL_CLOSED, call,
+ reason ? reason : "Connection reset by user");
mem_deref(call);
@@ -1658,6 +1662,14 @@ struct ua *uag_find(const struct pl *cuser)
return ua;
}
+ /* Last resort, try any catchall UAs */
+ for (le = uag.ual.head; le; le = le->next) {
+ struct ua *ua = le->data;
+
+ if (ua->catchall)
+ return ua;
+ }
+
return NULL;
}
@@ -1895,6 +1907,22 @@ void ua_set_media_af(struct ua *ua, int af_media)
}
+/**
+ * Enable handling of all inbound requests, even if
+ * the request uri is not matching.
+ *
+ * @param ua User-Agent
+ * @param enabled True to enable, false to disable
+ */
+void ua_set_catchall(struct ua *ua, bool enabled)
+{
+ if (!ua)
+ return;
+
+ ua->catchall = enabled;
+}
+
+
int uag_set_extra_params(const char *eprm)
{
uag.eprm = mem_deref(uag.eprm);
diff --git a/src/video.c b/src/video.c
index f191215..e21b626 100644
--- a/src/video.c
+++ b/src/video.c
@@ -18,14 +18,7 @@
#include "magic.h"
-/** Internal video-encoder format */
-#ifndef VIDENC_INTERNAL_FMT
-#define VIDENC_INTERNAL_FMT (VID_FMT_YUV420P)
-#endif
-
-
enum {
- SRATE = 90000,
MAX_MUTED_FRAMES = 3,
};
@@ -103,9 +96,14 @@ struct vtx {
bool picup; /**< Send picture update */
bool muted; /**< Muted flag */
int frames; /**< Number of frames sent */
- int efps; /**< Estimated frame-rate */
- uint32_t ts_min;
- uint32_t ts_max;
+ double efps; /**< Estimated frame-rate */
+ uint64_t ts_base; /**< First RTP timestamp sent */
+ uint64_t ts_last; /**< Last RTP timestamp sent */
+
+ /** Statistics */
+ struct {
+ uint64_t src_frames; /**< Total frames from vidsrc */
+ } stats;
};
@@ -135,15 +133,21 @@ struct vrx {
struct list filtl; /**< Filters in decoding order */
struct tmr tmr_picup; /**< Picture update timer */
struct vidsz size; /**< Incoming video resolution */
+ enum vidfmt fmt; /**< Incoming pixel format */
enum vidorient orient; /**< Display orientation */
char device[128]; /**< Display device name */
int pt_rx; /**< Incoming RTP payload type */
int frames; /**< Number of frames received */
- int efps; /**< Estimated frame-rate */
+ double efps; /**< Estimated frame-rate */
unsigned n_intra; /**< Intra-frames decoded */
unsigned n_picup; /**< Picture updates sent */
uint32_t ts_min;
uint32_t ts_max;
+
+ /** Statistics */
+ struct {
+ uint64_t disp_frames; /** Total frames displayed */
+ } stats;
};
@@ -325,23 +329,21 @@ static void video_destructor(void *arg)
}
-static int get_fps(const struct video *v)
+static double get_fps(const struct video *v)
{
const char *attr;
/* RFC4566 */
attr = sdp_media_rattr(stream_sdpmedia(v->strm), "framerate");
if (attr) {
- /* NOTE: fractional values are ignored */
- const double fps = atof(attr);
- return (int)fps;
+ return atof(attr);
}
else
return v->cfg.fps;
}
-static int packet_handler(bool marker, uint32_t ts,
+static int packet_handler(bool marker, uint64_t ts,
const uint8_t *hdr, size_t hdr_len,
const uint8_t *pld, size_t pld_len,
void *arg)
@@ -352,14 +354,12 @@ static int packet_handler(bool marker, uint32_t ts,
uint32_t rtp_ts;
int err;
- /* NOTE: does not handle timestamp wrap around */
- if (ts < vtx->ts_min)
- vtx->ts_min = ts;
- if (ts > vtx->ts_max)
- vtx->ts_max = ts;
+ if (!vtx->ts_base)
+ vtx->ts_base = ts;
+ vtx->ts_last = ts;
/* add random timestamp offset */
- rtp_ts = vtx->ts_offset + ts;
+ rtp_ts = vtx->ts_offset + (ts & 0xffffffff);
err = vidqent_alloc(&qent, marker, strm->pt_enc, rtp_ts,
hdr, hdr_len, pld, pld_len);
@@ -404,13 +404,14 @@ static void encode_rtp_send(struct vtx *vtx, struct vidframe *frame)
lock_write_get(vtx->lock);
/* Convert image */
- if (frame->fmt != VIDENC_INTERNAL_FMT) {
+ if (frame->fmt != (enum vidfmt)vtx->video->cfg.enc_fmt) {
vtx->vsrc_size = frame->size;
if (!vtx->frame) {
- err = vidframe_alloc(&vtx->frame, VIDENC_INTERNAL_FMT,
+ err = vidframe_alloc(&vtx->frame,
+ vtx->video->cfg.enc_fmt,
&vtx->vsrc_size);
if (err)
goto unlock;
@@ -452,12 +453,17 @@ static void encode_rtp_send(struct vtx *vtx, struct vidframe *frame)
*
* @note This function has REAL-TIME properties
*/
-static void vidsrc_frame_handler(struct vidframe *frame, void *arg)
+static void vidsrc_frame_handler(struct vidframe *frame, uint64_t timestamp,
+ void *arg)
{
struct vtx *vtx = arg;
+ /* XXX: save timestamp(s) and pass to encoder */
+
++vtx->frames;
+ ++vtx->stats.src_frames;
+
/* Is the video muted? If so insert video mute image */
if (vtx->muted)
frame = vtx->mute_frame;
@@ -501,8 +507,6 @@ static int vtx_alloc(struct vtx *vtx, struct video *video)
tmr_start(&vtx->tmr_rtp, 1, rtp_tmr_handler, vtx);
- vtx->ts_min = ~0;
-
return err;
}
@@ -522,6 +526,7 @@ static int vrx_alloc(struct vrx *vrx, struct video *video)
str_ncpy(vrx->device, video->cfg.disp_dev, sizeof(vrx->device));
vrx->ts_min = ~0;
+ vrx->fmt = (enum vidfmt)-1;
return err;
}
@@ -618,6 +623,7 @@ static int video_stream_decode(struct vrx *vrx, const struct rtp_header *hdr,
goto out;
vrx->size = frame->size;
+ vrx->fmt = frame->fmt;
if (!list_isempty(&vrx->filtl)) {
@@ -639,6 +645,8 @@ static int video_stream_decode(struct vrx *vrx, const struct rtp_header *hdr,
err |= st->vf->dech(st, frame);
}
+ ++vrx->stats.disp_frames;
+
err = vidisp_display(vrx->vidisp, v->peer, frame);
frame_filt = mem_deref(frame_filt);
if (err == ENODEV) {
@@ -827,7 +835,7 @@ int video_alloc(struct video **vp, const struct stream_param *stream_prm,
}
err |= sdp_media_set_lattr(stream_sdpmedia(v->strm), true,
- "framerate", "%d", v->cfg.fps);
+ "framerate", "%.2f", v->cfg.fps);
/* RFC 4585 */
err |= sdp_media_set_lattr(stream_sdpmedia(v->strm), true,
@@ -939,7 +947,7 @@ static int set_encoder_format(struct vtx *vtx, const char *src,
}
vtx->mute_frame = mem_deref(vtx->mute_frame);
- err = vidframe_alloc(&vtx->mute_frame, VIDENC_INTERNAL_FMT, size);
+ err = vidframe_alloc(&vtx->mute_frame, vtx->video->cfg.enc_fmt, size);
if (err)
return err;
@@ -957,8 +965,8 @@ static void tmr_handler(void *arg)
tmr_start(&v->tmr, TMR_INTERVAL * 1000, tmr_handler, v);
/* Estimate framerates */
- v->vtx.efps = v->vtx.frames / TMR_INTERVAL;
- v->vrx.efps = v->vrx.frames / TMR_INTERVAL;
+ v->vtx.efps = (double)v->vtx.frames / (double)TMR_INTERVAL;
+ v->vrx.efps = (double)v->vrx.frames / (double)TMR_INTERVAL;
v->vtx.frames = 0;
v->vrx.frames = 0;
@@ -980,7 +988,7 @@ int video_start(struct video *v, const char *peer)
return err;
}
- stream_set_srate(v->strm, SRATE, SRATE);
+ stream_set_srate(v->strm, VIDEO_SRATE, VIDEO_SRATE);
if (vidisp_find(baresip_vidispl(), NULL)) {
err = set_vidisp(&v->vrx);
@@ -1149,7 +1157,7 @@ int video_encoder_set(struct video *v, struct vidcodec *vc,
prm.fps = get_fps(v);
prm.max_fs = -1;
- info("Set video encoder: %s %s (%u bit/s, %u fps)\n",
+ info("Set video encoder: %s %s (%u bit/s, %.2f fps)\n",
vc->name, vc->variant, prm.bitrate, prm.fps);
vtx->enc = mem_deref(vtx->enc);
@@ -1304,6 +1312,54 @@ void video_sdp_attr_decode(struct video *v)
}
+static int vtx_debug(struct re_printf *pf, const struct vtx *vtx)
+{
+ int err = 0;
+
+ err |= re_hprintf(pf, " tx: encode: %s %s\n",
+ vtx->vc ? vtx->vc->name : "none",
+ vtx->frame ? vidfmt_name(vtx->frame->fmt) : "?");
+ err |= re_hprintf(pf, " source: %s %u x %u, fps=%.2f"
+ " frames=%llu\n",
+ vtx->vsrc ? vidsrc_get(vtx->vsrc)->name : "none",
+ vtx->vsrc_size.w,
+ vtx->vsrc_size.h, vtx->vsrc_prm.fps,
+ vtx->stats.src_frames);
+ err |= re_hprintf(pf, " skipc=%u sendq=%u\n",
+ vtx->skipc, list_count(&vtx->sendq));
+
+ if (vtx->ts_base) {
+ err |= re_hprintf(pf, " time = %.3f sec\n",
+ video_calc_seconds(vtx->ts_last - vtx->ts_base));
+ }
+ else {
+ err |= re_hprintf(pf, " time = (not started)\n");
+ }
+
+ return err;
+}
+
+
+static int vrx_debug(struct re_printf *pf, const struct vrx *vrx)
+{
+ int err = 0;
+
+ err |= re_hprintf(pf, " rx: decode: %s %s\n",
+ vrx->vc ? vrx->vc->name : "none",
+ vidfmt_name(vrx->fmt));
+ err |= re_hprintf(pf, " vidisp: %s %u x %u frames=%llu\n",
+ vrx->vidisp ? vidisp_get(vrx->vidisp)->name : "none",
+ vrx->size.w, vrx->size.h,
+ vrx->stats.disp_frames);
+ err |= re_hprintf(pf, " n_intra=%u, n_picup=%u\n",
+ vrx->n_intra, vrx->n_picup);
+ err |= re_hprintf(pf, " time = %.3f sec\n",
+ video_calc_seconds(vrx->ts_max - vrx->ts_min));
+
+ return err;
+}
+
+
int video_debug(struct re_printf *pf, const struct video *v)
{
const struct vtx *vtx;
@@ -1319,20 +1375,10 @@ int video_debug(struct re_printf *pf, const struct video *v)
err = re_hprintf(pf, "\n--- Video stream ---\n");
err |= re_hprintf(pf, " started: %s\n", v->started ? "yes" : "no");
- err |= re_hprintf(pf, " tx: %u x %u, fps=%d\n",
- vtx->vsrc_size.w,
- vtx->vsrc_size.h, vtx->vsrc_prm.fps);
- err |= re_hprintf(pf, " skipc=%u\n", vtx->skipc);
- err |= re_hprintf(pf, " time = %.3f sec\n",
- video_calc_seconds(vtx->ts_max - vtx->ts_min));
-
- err |= re_hprintf(pf, " rx: %u x %u\n", vrx->size.w, vrx->size.h);
- err |= re_hprintf(pf, " pt=%d\n", vrx->pt_rx);
-
- err |= re_hprintf(pf, " n_intra=%u, n_picup=%u\n",
- vrx->n_intra, vrx->n_picup);
- err |= re_hprintf(pf, " time = %.3f sec\n",
- video_calc_seconds(vrx->ts_max - vrx->ts_min));
+ err |= vtx_debug(pf, vtx);
+ err |= vrx_debug(pf, vrx);
+ if (err)
+ return err;
if (!list_isempty(baresip_vidfiltl())) {
err |= vtx_print_pipeline(pf, vtx);
@@ -1350,7 +1396,7 @@ int video_print(struct re_printf *pf, const struct video *v)
if (!v)
return 0;
- return re_hprintf(pf, " efps=%d/%d", v->vtx.efps, v->vrx.efps);
+ return re_hprintf(pf, " efps=%.1f/%.1f", v->vtx.efps, v->vrx.efps);
}
@@ -1384,38 +1430,3 @@ void video_set_devicename(struct video *v, const char *src, const char *disp)
str_ncpy(v->vtx.device, src, sizeof(v->vtx.device));
str_ncpy(v->vrx.device, disp, sizeof(v->vrx.device));
}
-
-
-/**
- * Calculate the RTP timestamp from Presentation Time Stamp (PTS)
- * or Decoding Time Stamp (DTS) and framerate.
- *
- * @note The calculated RTP Timestamp may wrap around.
- *
- * @param pts Presentation Time Stamp (PTS)
- * @param fps Framerate in [frames per second]
- *
- * @return RTP Timestamp
- */
-uint32_t video_calc_rtp_timestamp(int64_t pts, unsigned fps)
-{
- uint64_t rtp_ts;
-
- if (!fps)
- return 0;
-
- rtp_ts = ((uint64_t)SRATE * pts) / fps;
-
- return (uint32_t)rtp_ts;
-}
-
-
-double video_calc_seconds(uint32_t rtp_ts)
-{
- double timestamp;
-
- /* convert from RTP clockrate to seconds */
- timestamp = (double)rtp_ts / (double)SRATE;
-
- return timestamp;
-}
diff --git a/src/vidisp.c b/src/vidisp.c
index d267f58..2a2def6 100644
--- a/src/vidisp.c
+++ b/src/vidisp.c
@@ -126,6 +126,13 @@ int vidisp_display(struct vidisp_st *st, const char *title,
}
+/**
+ * Get the video display module from a video display state
+ *
+ * @param st Video display state
+ *
+ * @return Video display module
+ */
struct vidisp *vidisp_get(struct vidisp_st *st)
{
return st ? st->vd : NULL;
diff --git a/src/vidsrc.c b/src/vidsrc.c
index 2c8f9ff..03a039a 100644
--- a/src/vidsrc.c
+++ b/src/vidsrc.c
@@ -119,6 +119,13 @@ int vidsrc_alloc(struct vidsrc_st **stp, struct list *vidsrcl,
}
+/**
+ * Get the video source module from a video source state
+ *
+ * @param st Video source state
+ *
+ * @return Video source module
+ */
struct vidsrc *vidsrc_get(struct vidsrc_st *st)
{
return st ? st->vs : NULL;
diff --git a/src/vidutil.c b/src/vidutil.c
new file mode 100644
index 0000000..a6d0b61
--- /dev/null
+++ b/src/vidutil.c
@@ -0,0 +1,65 @@
+/**
+ * @file vidutil.c Video utility functions
+ *
+ * Copyright (C) 2017 Creytiv.com
+ */
+
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "core.h"
+
+
+/**
+ * Calculate the RTP timestamp from Presentation Time Stamp (PTS)
+ * or Decoding Time Stamp (DTS) and framerate.
+ *
+ * @note The calculated RTP Timestamp may NOT wrap around.
+ *
+ * @param pts Presentation Time Stamp (PTS)
+ * @param fps Framerate in [frames per second]
+ *
+ * @return Extended RTP Timestamp
+ */
+uint64_t video_calc_rtp_timestamp(int64_t pts, double fps)
+{
+ uint64_t rtp_ts;
+
+ if (!fps)
+ return 0;
+
+ rtp_ts = ((uint64_t)VIDEO_SRATE * pts) / fps;
+
+ return rtp_ts;
+}
+
+
+/**
+ * Calculate the timestamp in seconds from the RTP timestamp.
+ *
+ * @param rtp_ts RTP Timestamp
+ *
+ * @return Timestamp in seconds
+ */
+double video_calc_seconds(uint64_t rtp_ts)
+{
+ double timestamp;
+
+ /* convert from RTP clockrate to seconds */
+ timestamp = (double)rtp_ts / (double)VIDEO_SRATE;
+
+ return timestamp;
+}
+
+
+/**
+ * Convert a video timestamp to seconds
+ *
+ * @param timestamp Timestamp in VIDEO_TIMEBASE units
+ *
+ * @return Timestamp in seconds
+ */
+double video_timestamp_to_seconds(uint64_t timestamp)
+{
+ return (double)timestamp / (double)VIDEO_TIMEBASE;
+}
diff --git a/test/account.c b/test/account.c
index bf03b03..cb62acd 100644
--- a/test/account.c
+++ b/test/account.c
@@ -15,9 +15,10 @@
static const char str[] =
- "\"Mr User\" <sip:user:pass@domain.com>"
+ "\"Mr User\" <sip:user@domain.com>"
";answermode=auto"
";auth_user=xuser"
+ ";auth_pass=pass"
";outbound=\"sip:edge.domain.com\""
";ptime=10"
";regint=600"
@@ -45,7 +46,7 @@ int test_account(void)
TEST_STRCMP("Mr User", 7, addr->dname.p, addr->dname.l);
TEST_STRCMP("sip", 3, addr->uri.scheme.p, addr->uri.scheme.l);
TEST_STRCMP("user", 4, addr->uri.user.p, addr->uri.user.l);
- TEST_STRCMP("pass", 4, addr->uri.password.p, addr->uri.password.l);
+ TEST_STRCMP("", 0, addr->uri.password.p, addr->uri.password.l);
TEST_STRCMP("domain.com", 10, addr->uri.host.p, addr->uri.host.l);
ASSERT_EQ(0, addr->uri.params.l);
ASSERT_TRUE(addr->params.l > 0);
@@ -53,6 +54,7 @@ int test_account(void)
/* verify all decoded parameters */
ASSERT_TRUE(ANSWERMODE_AUTO == account_answermode(acc));
ASSERT_STREQ("xuser", account_auth_user(acc));
+ ASSERT_STREQ("pass", account_auth_pass(acc));
ASSERT_STREQ("sip:edge.domain.com", account_outbound(acc, 0));
ASSERT_TRUE(NULL == account_outbound(acc, 1));
ASSERT_TRUE(NULL == account_outbound(acc, 333));
diff --git a/test/call.c b/test/call.c
index 34c5fd5..ec12524 100644
--- a/test/call.c
+++ b/test/call.c
@@ -176,6 +176,8 @@ static void event_handler(struct ua *ua, enum ua_event ev,
case UA_EVENT_CALL_ESTABLISHED:
++ag->n_established;
+ ASSERT_TRUE(str_isset(call_id(call)));
+
/* are both agents established? */
if (ag->n_established >= f->exp_estab &&
ag->peer->n_established >= f->exp_estab) {
@@ -828,8 +830,15 @@ static void float_sample_handler(const void *sampv, size_t sampc, void *arg)
(void)sampv;
(void)sampc;
- if (sampc && fix->a.n_established && fix->b.n_established)
+ /* Wait until the call is established and the incoming
+ * audio samples are successfully decoded.
+ */
+ if (sampc && fix->a.n_established && fix->b.n_established &&
+ audio_rxaubuf_started(call_audio(ua_call(fix->a.ua))) &&
+ audio_rxaubuf_started(call_audio(ua_call(fix->b.ua)))
+ ) {
re_cancel();
+ }
}
@@ -840,7 +849,7 @@ static int test_media_base(enum audio_mode txmode)
struct auplay *auplay = NULL;
int err = 0;
- fixture_init(f);
+ fixture_init_prm(f, ";ptime=1");
conf_config()->audio.txmode = txmode;
@@ -861,7 +870,7 @@ static int test_media_base(enum audio_mode txmode)
TEST_ERR(err);
/* run main-loop with timeout, wait for events */
- err = re_main_timeout(5000);
+ err = re_main_timeout(15000);
TEST_ERR(err);
TEST_ERR(fix.err);
@@ -896,11 +905,65 @@ int test_call_format_float(void)
err = test_media_base(AUDIO_MODE_POLL);
ASSERT_EQ(0, err);
+#ifdef HAVE_PTHREAD
err = test_media_base(AUDIO_MODE_THREAD);
ASSERT_EQ(0, err);
+#endif
conf_config()->audio.txmode = AUDIO_MODE_POLL;
out:
return err;
}
+
+
+int test_call_mediaenc(void)
+{
+ struct fixture fix, *f = &fix;
+ struct ausrc *ausrc = NULL;
+ struct auplay *auplay = NULL;
+ int err = 0;
+
+ mock_menc_register();
+
+ /* Enable a dummy media encryption protocol */
+ fixture_init_prm(f, ";mediaenc=xrtp;ptime=1");
+
+ err = mock_ausrc_register(&ausrc);
+ TEST_ERR(err);
+ err = mock_auplay_register(&auplay, float_sample_handler, f);
+ TEST_ERR(err);
+
+ f->estab_action = ACTION_NOTHING;
+
+ f->behaviour = BEHAVIOUR_ANSWER;
+
+ /* Make a call from A to B */
+ err = ua_connect(f->a.ua, 0, NULL, f->buri, NULL, VIDMODE_OFF);
+ TEST_ERR(err);
+
+ /* run main-loop with timeout, wait for events */
+ err = re_main_timeout(5000);
+ TEST_ERR(err);
+ TEST_ERR(fix.err);
+
+ ASSERT_EQ(1, fix.a.n_established);
+ ASSERT_EQ(0, fix.a.n_closed);
+
+ ASSERT_EQ(1, fix.b.n_established);
+ ASSERT_EQ(0, fix.b.n_closed);
+
+ /* XXX: verify that the call was encrypted */
+
+ out:
+ fixture_close(f);
+ mem_deref(auplay);
+ mem_deref(ausrc);
+
+ mock_menc_unregister();
+
+ if (fix.err)
+ return fix.err;
+
+ return err;
+}
diff --git a/test/event.c b/test/event.c
new file mode 100644
index 0000000..563d5d3
--- /dev/null
+++ b/test/event.c
@@ -0,0 +1,55 @@
+/**
+ * @file test/event.c Baresip selftest -- event handling
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#include <string.h>
+#include <re.h>
+#include <baresip.h>
+#include "test.h"
+
+
+int test_event(void)
+{
+ struct odict *od = NULL;
+ size_t i;
+ int err = 0;
+
+ static const enum ua_event eventv[] = {
+ UA_EVENT_REGISTERING,
+ UA_EVENT_REGISTER_OK,
+ UA_EVENT_REGISTER_FAIL,
+ UA_EVENT_UNREGISTERING,
+ UA_EVENT_SHUTDOWN,
+ UA_EVENT_EXIT
+ /* .. more events .. */
+ };
+
+ for (i=0; i<ARRAY_SIZE(eventv); i++) {
+
+ const enum ua_event ev = eventv[i];
+ const struct odict_entry *entry;
+
+ err = odict_alloc(&od, 8);
+ ASSERT_EQ(0, err);
+
+ err = event_encode_dict(od, NULL, ev, NULL, NULL);
+ ASSERT_EQ(0, err);
+
+ /* verify that something was added */
+ ASSERT_TRUE(odict_count(od, false) >= 2);
+
+ /* verify the mandatory entries */
+ entry = odict_lookup(od, "type");
+ ASSERT_TRUE(entry != NULL);
+ ASSERT_EQ(ODICT_STRING, entry->type);
+ ASSERT_STREQ(uag_event_str(ev), entry->u.str);
+
+ od = mem_deref(od);
+ }
+
+ out:
+ mem_deref(od);
+
+ return err;
+}
diff --git a/test/main.c b/test/main.c
index e917f2d..01937f4 100644
--- a/test/main.c
+++ b/test/main.c
@@ -30,6 +30,7 @@ static const struct test tests[] = {
TEST(test_call_answer_hangup_b),
TEST(test_call_reject),
TEST(test_call_rtp_timeout),
+ TEST(test_call_mediaenc),
TEST(test_call_multiple),
TEST(test_call_max),
TEST(test_call_dtmf),
@@ -44,6 +45,7 @@ static const struct test tests[] = {
TEST(test_cmd_long),
TEST(test_contact),
TEST(test_cplusplus),
+ TEST(test_event),
TEST(test_message),
TEST(test_mos),
TEST(test_network),
diff --git a/test/mock/mock_aucodec.c b/test/mock/mock_aucodec.c
index fd91721..8115a36 100644
--- a/test/mock/mock_aucodec.c
+++ b/test/mock/mock_aucodec.c
@@ -16,9 +16,10 @@
static int mock_l16_encode(struct auenc_state *st, uint8_t *buf, size_t *len,
- const int16_t *sampv, size_t sampc)
+ int fmt, const void *sampv_void, size_t sampc)
{
int16_t *p = (void *)buf;
+ const int16_t *sampv = sampv_void;
(void)st;
if (!buf || !len || !sampv)
@@ -27,6 +28,9 @@ static int mock_l16_encode(struct auenc_state *st, uint8_t *buf, size_t *len,
if (*len < sampc*2)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*len = 2 + sampc*2;
*p++ = L16_HEADER;
@@ -39,10 +43,11 @@ static int mock_l16_encode(struct auenc_state *st, uint8_t *buf, size_t *len,
static int mock_l16_decode(struct audec_state *st,
- int16_t *sampv, size_t *sampc,
+ int fmt, void *sampv_void, size_t *sampc,
const uint8_t *buf, size_t len)
{
int16_t *p = (void *)buf;
+ int16_t *sampv = sampv_void;
uint16_t hdr;
(void)st;
@@ -55,6 +60,9 @@ static int mock_l16_decode(struct audec_state *st,
if (*sampc < len/2)
return ENOMEM;
+ if (fmt != AUFMT_S16LE)
+ return ENOTSUP;
+
*sampc = (len - 2)/2;
hdr = *p++;
diff --git a/test/mock/mock_menc.c b/test/mock/mock_menc.c
new file mode 100644
index 0000000..cbd2a5f
--- /dev/null
+++ b/test/mock/mock_menc.c
@@ -0,0 +1,126 @@
+/**
+ * @file mock/mock_menc.c Mock media encryption
+ *
+ * Copyright (C) 2010 - 2018 Creytiv.com
+ */
+
+#include <string.h>
+#include <re.h>
+#include <baresip.h>
+#include "../test.h"
+
+
+#define SECRET_KEY 0xdd
+
+
+struct menc_media {
+ void *rtpsock;
+ struct udp_helper *uh_rtp;
+};
+
+
+/*
+ * Encrypt/decrypt an RTP payload with a dummy key.
+ * We use a simple XOR scheme for simplicity.
+ */
+static void mock_crypt(struct mbuf *mb)
+{
+ size_t i, len = mbuf_get_left(mb);
+
+ for (i = RTP_HEADER_SIZE; i < len; i++) {
+ mb->buf[mb->pos + i] ^= SECRET_KEY;
+ }
+}
+
+
+static void media_destructor(void *data)
+{
+ struct menc_media *mm = data;
+
+ mem_deref(mm->uh_rtp);
+ mem_deref(mm->rtpsock);
+}
+
+
+static bool send_handler(int *err, struct sa *dst, struct mbuf *mb, void *arg)
+{
+ struct menc_media *mm = arg;
+ (void)mm;
+ (void)err;
+ (void)dst;
+
+ mock_crypt(mb);
+
+ return false; /* continue processing */
+}
+
+
+static bool recv_handler(struct sa *src, struct mbuf *mb, void *arg)
+{
+ struct menc_media *mm = arg;
+ (void)mm;
+ (void)src;
+
+ mock_crypt(mb);
+
+ return false; /* continue processing */
+}
+
+
+static int mock_media_alloc(struct menc_media **mmp, struct menc_sess *sess,
+ struct rtp_sock *rtp, int proto,
+ void *rtpsock, void *rtcpsock,
+ struct sdp_media *sdpm)
+{
+ struct menc_media *mm;
+ const int layer = 10; /* above zero */
+ int err = 0;
+ (void)sess;
+ (void)rtp;
+ (void)rtcpsock;
+
+ if (!mmp || !sdpm)
+ return EINVAL;
+ if (proto != IPPROTO_UDP)
+ return EPROTONOSUPPORT;
+
+ mm = *mmp;
+ if (!mm) {
+ mm = mem_zalloc(sizeof(*mm), media_destructor);
+ if (!mm)
+ return ENOMEM;
+
+ mm->rtpsock = mem_ref(rtpsock);
+ err = udp_register_helper(&mm->uh_rtp, rtpsock, layer,
+ send_handler, recv_handler, mm);
+ if (err)
+ goto out;
+
+ *mmp = mm;
+ }
+
+ out:
+ if (err)
+ mem_deref(mm);
+
+ return err;
+}
+
+
+static struct menc menc_mock = {
+ .id = "XRTP",
+ .sdp_proto = "RTP/XAVP",
+ .mediah = mock_media_alloc
+};
+
+
+void mock_menc_register(void)
+{
+ menc_register(baresip_mencl(), &menc_mock);
+}
+
+
+void mock_menc_unregister(void)
+{
+ menc_unregister(&menc_mock);
+}
diff --git a/test/mock/mock_vidcodec.c b/test/mock/mock_vidcodec.c
index 9609e65..93f7a7f 100644
--- a/test/mock/mock_vidcodec.c
+++ b/test/mock/mock_vidcodec.c
@@ -22,7 +22,7 @@ struct hdr {
struct videnc_state {
int64_t pts;
- unsigned fps;
+ double fps;
videnc_packet_h *pkth;
void *arg;
};
@@ -88,7 +88,7 @@ static int mock_encode(struct videnc_state *ves, bool update,
{
struct mbuf *hdr;
uint8_t payload[2] = {0,0};
- uint32_t rtp_ts;
+ uint64_t rtp_ts;
int err;
(void)update;
diff --git a/test/mock/mock_vidsrc.c b/test/mock/mock_vidsrc.c
index 8f92bc4..781e04a 100644
--- a/test/mock/mock_vidsrc.c
+++ b/test/mock/mock_vidsrc.c
@@ -14,7 +14,8 @@ struct vidsrc_st {
struct vidframe *frame;
struct tmr tmr;
- int fps;
+ uint64_t timestamp;
+ double fps;
vidsrc_frame_h *frameh;
void *arg;
};
@@ -27,7 +28,9 @@ static void tmr_handler(void *arg)
tmr_start(&st->tmr, 1000/st->fps, tmr_handler, st);
if (st->frameh)
- st->frameh(st->frame, st->arg);
+ st->frameh(st->frame, st->timestamp, st->arg);
+
+ st->timestamp += VIDEO_TIMEBASE / st->fps;
}
@@ -71,7 +74,7 @@ static int mock_vidsrc_alloc(struct vidsrc_st **stp, const struct vidsrc *vs,
tmr_start(&st->tmr, 0, tmr_handler, st);
- info("mock_vidsrc: new instance with size %u x %u (%d fps)\n",
+ info("mock_vidsrc: new instance with size %u x %u (%.2f fps)\n",
size->w, size->h, prm->fps);
out:
diff --git a/test/sip/domain.c b/test/sip/domain.c
index 063e3b9..2aec1a9 100644
--- a/test/sip/domain.c
+++ b/test/sip/domain.c
@@ -163,7 +163,8 @@ int domain_auth(struct sip_server *srv,
break;
}
- err = httpauth_digest_response_auth(&resp, &msg->met,usr->ha1);
+ err = httpauth_digest_response_auth(&resp, &msg->met,
+ user_ha1(usr));
if (err)
return err;
diff --git a/test/sip/sipsrv.c b/test/sip/sipsrv.c
index 374ea3b..1174893 100644
--- a/test/sip/sipsrv.c
+++ b/test/sip/sipsrv.c
@@ -322,7 +322,7 @@ int sip_server_uri(struct sip_server *srv, char *uri, size_t sz,
return err;
/* NOTE: angel brackets needed to parse ;transport parameter */
- if (re_snprintf(uri, sz, "<sip:x:x@%J%s>",
+ if (re_snprintf(uri, sz, "<sip:x@%J%s>",
&laddr, sip_transp_param(tp)) < 0)
return ENOMEM;
diff --git a/test/sip/sipsrv.h b/test/sip/sipsrv.h
index a4b8bbf..1f1076c 100644
--- a/test/sip/sipsrv.h
+++ b/test/sip/sipsrv.h
@@ -111,12 +111,9 @@ void location_rollback(struct list *locl);
* User
*/
-struct user {
- struct le he;
- uint8_t ha1[MD5_SIZE];
- char *name;
-};
+struct user;
int user_add(struct hash *ht, const char *username, const char *password,
const char *realm);
struct user *user_find(struct hash *ht, const struct pl *name);
+const uint8_t *user_ha1(const struct user *usr);
diff --git a/test/sip/user.c b/test/sip/user.c
index 99fb47d..73a101e 100644
--- a/test/sip/user.c
+++ b/test/sip/user.c
@@ -7,6 +7,13 @@
#include "sipsrv.h"
+struct user {
+ struct le he;
+ uint8_t ha1[MD5_SIZE];
+ char *name;
+};
+
+
static void destructor(void *arg)
{
struct user *usr = arg;
@@ -71,3 +78,9 @@ struct user *user_find(struct hash *ht, const struct pl *name)
return NULL;
}
+
+
+const uint8_t *user_ha1(const struct user *usr)
+{
+ return usr ? usr->ha1 : NULL;
+}
diff --git a/test/srcs.mk b/test/srcs.mk
index 0bcb6de..6cd6d3d 100644
--- a/test/srcs.mk
+++ b/test/srcs.mk
@@ -14,6 +14,7 @@ TEST_SRCS += call.c
TEST_SRCS += cmd.c
TEST_SRCS += contact.c
TEST_SRCS += cplusplus.c
+TEST_SRCS += event.c
TEST_SRCS += message.c
TEST_SRCS += mos.c
TEST_SRCS += net.c
@@ -43,6 +44,7 @@ endif
TEST_SRCS += mock/mock_aucodec.c
TEST_SRCS += mock/mock_auplay.c
TEST_SRCS += mock/mock_ausrc.c
+TEST_SRCS += mock/mock_menc.c
ifneq ($(USE_VIDEO),)
TEST_SRCS += mock/mock_vidsrc.c
TEST_SRCS += mock/mock_vidcodec.c
diff --git a/test/test.h b/test/test.h
index f276a8d..8072cfd 100644
--- a/test/test.h
+++ b/test/test.h
@@ -150,6 +150,14 @@ int mock_auplay_register(struct auplay **auplayp,
/*
+ * Mock Media encryption
+ */
+
+void mock_menc_register(void);
+void mock_menc_unregister(void);
+
+
+/*
* Mock Video-source
*/
@@ -181,6 +189,7 @@ int test_account(void);
int test_aulevel(void);
int test_cmd(void);
int test_cmd_long(void);
+int test_event(void);
int test_contact(void);
int test_ua_alloc(void);
int test_uag_find_param(void);
@@ -207,6 +216,7 @@ int test_call_video(void);
int test_call_aulevel(void);
int test_call_progress(void);
int test_call_format_float(void);
+int test_call_mediaenc(void);
#ifdef USE_VIDEO
int test_video(void);
diff --git a/test/ua.c b/test/ua.c
index 4f04e4f..0621e92 100644
--- a/test/ua.c
+++ b/test/ua.c
@@ -293,7 +293,7 @@ static int reg_dns(enum sip_transp tp)
t.srvc = server_count;
/* NOTE: angel brackets needed to parse ;transport parameter */
- if (re_snprintf(aor, sizeof(aor), "<sip:x:x@%s;transport=%s>",
+ if (re_snprintf(aor, sizeof(aor), "<sip:x@%s;transport=%s>",
domain, sip_transp_name(tp)) < 0)
return ENOMEM;
@@ -362,7 +362,7 @@ int test_ua_register_dns(void)
#define USER "alfredh"
-#define PASS "pass%40word" /* NOTE: url-encoded */
+#define PASS "pass@word"
#define DOMAIN "localhost"
static int reg_auth(enum sip_transp tp)
@@ -384,7 +384,7 @@ static int reg_auth(enum sip_transp tp)
TEST_ERR(err);
err = user_add(domain_lookup(t.srvv[0], DOMAIN)->ht_usr,
- "alfredh", "pass@word", DOMAIN);
+ USER, PASS, DOMAIN);
TEST_ERR(err);
t.srvv[0]->auth_enabled = true;
@@ -395,10 +395,12 @@ static int reg_auth(enum sip_transp tp)
/* NOTE: angel brackets needed to parse ;transport parameter */
if (re_snprintf(aor, sizeof(aor),
- "<sip:%s:%s@%s>;outbound=\"sip:%J;transport=%s\"",
+ "<sip:%s@%s>"
+ ";auth_pass=%s"
+ ";outbound=\"sip:%J;transport=%s\"",
USER,
- PASS,
DOMAIN,
+ PASS,
&laddr,
sip_transp_name(tp)) < 0)
return ENOMEM;
@@ -540,8 +542,10 @@ static int reg_auth_dns(enum sip_transp tp)
t.srvc = server_count;
/* NOTE: angel brackets needed to parse ;transport parameter */
- if (re_snprintf(aor, sizeof(aor), "<sip:%s:%s@%s;transport=%s>",
- username, password, domain, sip_transp_name(tp)) < 0)
+ if (re_snprintf(aor, sizeof(aor),
+ "<sip:%s@%s;transport=%s>;auth_pass=%s",
+ username, domain, sip_transp_name(tp),
+ password) < 0)
return ENOMEM;
/*
diff --git a/test/video.c b/test/video.c
index 09c5e77..c2b829b 100644
--- a/test/video.c
+++ b/test/video.c
@@ -30,8 +30,8 @@ int test_video(void)
ASSERT_EQ( 300000000, video_calc_rtp_timestamp( 100000, 30));
ASSERT_EQ(3000000000, video_calc_rtp_timestamp(1000000, 30));
- ASSERT_EQ(4294965000, video_calc_rtp_timestamp(1431655, 30));
- ASSERT_EQ( 704, video_calc_rtp_timestamp(1431656, 30));
+ ASSERT_EQ(4294965000ULL, video_calc_rtp_timestamp(1431655, 30));
+ ASSERT_EQ(4294968000ULL, video_calc_rtp_timestamp(1431656, 30));
out:
return err;