summaryrefslogtreecommitdiff
path: root/pjsip-apps/src/samples
diff options
context:
space:
mode:
Diffstat (limited to 'pjsip-apps/src/samples')
-rw-r--r--pjsip-apps/src/samples/aectest.c28
-rw-r--r--pjsip-apps/src/samples/auddemo.c18
-rw-r--r--pjsip-apps/src/samples/aviplay.c531
-rw-r--r--pjsip-apps/src/samples/confbench.c22
-rw-r--r--pjsip-apps/src/samples/encdec.c33
-rw-r--r--pjsip-apps/src/samples/jbsim.c56
-rw-r--r--pjsip-apps/src/samples/latency.c16
-rw-r--r--pjsip-apps/src/samples/level.c8
-rw-r--r--pjsip-apps/src/samples/mix.c4
-rw-r--r--pjsip-apps/src/samples/pcaputil.c40
-rw-r--r--pjsip-apps/src/samples/pjsip-perf.c13
-rw-r--r--pjsip-apps/src/samples/playfile.c8
-rw-r--r--pjsip-apps/src/samples/playsine.c32
-rw-r--r--pjsip-apps/src/samples/recfile.c8
-rw-r--r--pjsip-apps/src/samples/resampleplay.c5
-rw-r--r--pjsip-apps/src/samples/simpleua.c443
-rw-r--r--pjsip-apps/src/samples/stereotest.c12
-rw-r--r--pjsip-apps/src/samples/streamutil.c91
-rw-r--r--pjsip-apps/src/samples/vid_streamutil.c929
19 files changed, 1961 insertions, 336 deletions
diff --git a/pjsip-apps/src/samples/aectest.c b/pjsip-apps/src/samples/aectest.c
index 518a3e26..4168f698 100644
--- a/pjsip-apps/src/samples/aectest.c
+++ b/pjsip-apps/src/samples/aectest.c
@@ -197,23 +197,23 @@ int main(int argc, char *argv[])
}
/* play and rec WAVs must have the same clock rate */
- if (wav_play->info.clock_rate != wav_rec->info.clock_rate) {
+ if (PJMEDIA_PIA_SRATE(&wav_play->info) != PJMEDIA_PIA_SRATE(&wav_rec->info)) {
puts("Error: clock rate mismatch in the WAV files");
return 1;
}
/* .. and channel count */
- if (wav_play->info.channel_count != wav_rec->info.channel_count) {
+ if (PJMEDIA_PIA_CCNT(&wav_play->info) != PJMEDIA_PIA_CCNT(&wav_rec->info)) {
puts("Error: clock rate mismatch in the WAV files");
return 1;
}
/* Create output wav */
status = pjmedia_wav_writer_port_create(pool, argv[pj_optind+2],
- wav_play->info.clock_rate,
- wav_play->info.channel_count,
- wav_play->info.samples_per_frame,
- wav_play->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&wav_play->info),
+ PJMEDIA_PIA_CCNT(&wav_play->info),
+ PJMEDIA_PIA_SPF(&wav_play->info),
+ PJMEDIA_PIA_BITS(&wav_play->info),
0, 0, &wav_out);
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Error opening output WAV file", status);
@@ -221,9 +221,9 @@ int main(int argc, char *argv[])
}
/* Create echo canceller */
- status = pjmedia_echo_create2(pool, wav_play->info.clock_rate,
- wav_play->info.channel_count,
- wav_play->info.samples_per_frame,
+ status = pjmedia_echo_create2(pool, PJMEDIA_PIA_SRATE(&wav_play->info),
+ PJMEDIA_PIA_CCNT(&wav_play->info),
+ PJMEDIA_PIA_SPF(&wav_play->info),
tail_ms, latency_ms,
opt, &ec);
if (status != PJ_SUCCESS) {
@@ -233,19 +233,19 @@ int main(int argc, char *argv[])
/* Processing loop */
- play_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1);
- rec_frame.buf = pj_pool_alloc(pool, wav_play->info.samples_per_frame<<1);
+ play_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
+ rec_frame.buf = pj_pool_alloc(pool, PJMEDIA_PIA_SPF(&wav_play->info)<<1);
pj_get_timestamp(&t0);
for (i=0; i < repeat; ++i) {
for (;;) {
- play_frame.size = wav_play->info.samples_per_frame << 1;
+ play_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
status = pjmedia_port_get_frame(wav_play, &play_frame);
if (status != PJ_SUCCESS)
break;
status = pjmedia_echo_playback(ec, (short*)play_frame.buf);
- rec_frame.size = wav_play->info.samples_per_frame << 1;
+ rec_frame.size = PJMEDIA_PIA_SPF(&wav_play->info) << 1;
status = pjmedia_port_get_frame(wav_rec, &rec_frame);
if (status != PJ_SUCCESS)
break;
@@ -264,7 +264,7 @@ int main(int argc, char *argv[])
pj_get_timestamp(&t1);
i = pjmedia_wav_writer_port_get_pos(wav_out) / sizeof(pj_int16_t) * 1000 /
- (wav_out->info.clock_rate * wav_out->info.channel_count);
+ (PJMEDIA_PIA_SRATE(&wav_out->info) * PJMEDIA_PIA_CCNT(&wav_out->info));
PJ_LOG(3,(THIS_FILE, "Processed %3d.%03ds audio",
i / 1000, i % 1000));
PJ_LOG(3,(THIS_FILE, "Completed in %u msec\n", pj_elapsed_msec(&t0, &t1)));
diff --git a/pjsip-apps/src/samples/auddemo.c b/pjsip-apps/src/samples/auddemo.c
index 3c97b0db..48bcad4e 100644
--- a/pjsip-apps/src/samples/auddemo.c
+++ b/pjsip-apps/src/samples/auddemo.c
@@ -144,7 +144,7 @@ static void show_dev_info(unsigned index)
strcat(formats, "unknown/");
break;
}
- sprintf(bitrate, "%u", info.ext_fmt[i].bitrate);
+ sprintf(bitrate, "%u", info.ext_fmt[i].det.aud.avg_bps);
strcat(formats, bitrate);
strcat(formats, " ");
}
@@ -276,10 +276,10 @@ static void record(unsigned rec_index, const char *filename)
}
param.dir = PJMEDIA_DIR_CAPTURE;
- param.clock_rate = wav->info.clock_rate;
- param.samples_per_frame = wav->info.samples_per_frame;
- param.channel_count = wav->info.channel_count;
- param.bits_per_sample = wav->info.bits_per_sample;
+ param.clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
+ param.samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
+ param.channel_count = PJMEDIA_PIA_CCNT(&wav->info);
+ param.bits_per_sample = PJMEDIA_PIA_BITS(&wav->info);
status = pjmedia_aud_stream_create(&param, &wav_rec_cb, NULL, wav,
&strm);
@@ -343,10 +343,10 @@ static void play_file(unsigned play_index, const char *filename)
}
param.dir = PJMEDIA_DIR_PLAYBACK;
- param.clock_rate = wav->info.clock_rate;
- param.samples_per_frame = wav->info.samples_per_frame;
- param.channel_count = wav->info.channel_count;
- param.bits_per_sample = wav->info.bits_per_sample;
+ param.clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
+ param.samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
+ param.channel_count = PJMEDIA_PIA_CCNT(&wav->info);
+ param.bits_per_sample = PJMEDIA_PIA_BITS(&wav->info);
status = pjmedia_aud_stream_create(&param, NULL, &wav_play_cb, wav,
&strm);
diff --git a/pjsip-apps/src/samples/aviplay.c b/pjsip-apps/src/samples/aviplay.c
new file mode 100644
index 00000000..a6602ba1
--- /dev/null
+++ b/pjsip-apps/src/samples/aviplay.c
@@ -0,0 +1,531 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <pjmedia.h>
+#include <pjmedia/converter.h>
+#include <pjmedia-codec.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+/**
+ * \page page_pjmedia_samples_aviplay_c Samples: Playing AVI File to
+ * Video and Sound Devices
+ *
+ * This is a very simple example to use the @ref PJMEDIA_FILE_PLAY,
+ * @ref PJMED_SND_PORT, and @ref PJMEDIA_VID_PORT. In this example, we
+ * open the file, video, and sound devices, then connect the file to both
+ * video and sound devices to play the contents of the file.
+ *
+ *
+ * This file is pjsip-apps/src/samples/aviplay.c
+ *
+ * \includelineno aviplay.c
+ */
+
+
+/*
+ * aviplay.c
+ *
+ * PURPOSE:
+ * Play a AVI file to video and sound devices.
+ *
+ * USAGE:
+ * aviplay FILE.AVI
+ */
+
+
+/* For logging purpose. */
+#define THIS_FILE "aviplay.c"
+
+static const char *desc =
+" FILE \n"
+" \n"
+" aviplay.c \n"
+" \n"
+" PURPOSE \n"
+" \n"
+" Demonstrate how to play a AVI file. \n"
+" \n"
+" USAGE \n"
+" \n"
+" aviplay FILE.AVI \n";
+
+struct codec_fmt {
+ pj_uint32_t pjmedia_id;
+ const char *codec_id;
+ /* Do we need to convert the decoded frame? */
+ pj_bool_t need_conversion;
+ /* If conversion is needed, dst_fmt indicates the destination format */
+ pjmedia_format_id dst_fmt;
+} codec_fmts[] = {{PJMEDIA_FORMAT_MJPEG, "mjpeg",
+ PJ_TRUE , PJMEDIA_FORMAT_I420},
+ {PJMEDIA_FORMAT_H263 , "h263" ,
+ PJ_FALSE, 0},
+ {PJMEDIA_FORMAT_XVID , "xvid"},
+ };
+
+typedef struct avi_port_t
+{
+ pjmedia_vid_port *vid_port;
+ pjmedia_snd_port *snd_port;
+ pj_bool_t is_running;
+ pj_bool_t is_quitting;
+} avi_port_t;
+
+typedef struct codec_port_data_t
+{
+ pjmedia_vid_codec *codec;
+ pjmedia_port *src_port;
+ pj_uint8_t *enc_buf;
+ pj_size_t enc_buf_size;
+
+ pjmedia_converter *conv;
+} codec_port_data_t;
+
+static pj_status_t avi_event_cb(pjmedia_event_subscription *esub,
+ pjmedia_event *event)
+{
+ avi_port_t *ap = (avi_port_t *)esub->user_data;
+
+ switch (event->type) {
+ case PJMEDIA_EVENT_WND_CLOSED:
+ ap->is_quitting = PJ_TRUE;
+ break;
+ case PJMEDIA_EVENT_MOUSE_BTN_DOWN:
+ if (ap->is_running) {
+ pjmedia_vid_port_stop(ap->vid_port);
+ if (ap->snd_port)
+ pjmedia_aud_stream_stop(
+ pjmedia_snd_port_get_snd_stream(ap->snd_port));
+ } else {
+ pjmedia_vid_port_start(ap->vid_port);
+ if (ap->snd_port)
+ pjmedia_aud_stream_start(
+ pjmedia_snd_port_get_snd_stream(ap->snd_port));
+ }
+ ap->is_running = !ap->is_running;
+ break;
+ default:
+ return PJ_SUCCESS;
+ }
+
+ /* We handled the event on our own, so return non-PJ_SUCCESS here */
+ return -1;
+}
+
+static pj_status_t codec_get_frame(pjmedia_port *port,
+ pjmedia_frame *frame)
+{
+ codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata;
+ pjmedia_vid_codec *codec = port_data->codec;
+ pjmedia_frame enc_frame;
+ pj_status_t status;
+
+ enc_frame.buf = port_data->enc_buf;
+ enc_frame.size = port_data->enc_buf_size;
+
+ if (port_data->conv) {
+ pj_size_t frame_size = frame->size;
+
+ status = pjmedia_port_get_frame(port_data->src_port, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ status = pjmedia_vid_codec_decode(codec, frame, frame->size, &enc_frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ frame->size = frame_size;
+ status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ return PJ_SUCCESS;
+ }
+
+ status = pjmedia_port_get_frame(port_data->src_port, &enc_frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ status = pjmedia_vid_codec_decode(codec, &enc_frame, frame->size, frame);
+ if (status != PJ_SUCCESS) goto on_error;
+
+ return PJ_SUCCESS;
+
+on_error:
+ pj_perror(3, THIS_FILE, status, "codec_get_frame() error");
+ return status;
+}
+
+static int aviplay(pj_pool_t *pool, const char *fname)
+{
+ pjmedia_vid_port *renderer=NULL;
+ pjmedia_vid_port_param param;
+ const pjmedia_video_format_info *vfi;
+ pjmedia_video_format_detail *vfd;
+ pjmedia_snd_port *snd_port = NULL;
+ pj_status_t status;
+ int rc = 0;
+ pjmedia_avi_streams *avi_streams;
+ pjmedia_avi_stream *vid_stream, *aud_stream;
+ pjmedia_port *vid_port = NULL, *aud_port = NULL;
+ pjmedia_vid_codec *codec=NULL;
+ pjmedia_event_subscription esub;
+ avi_port_t avi_port;
+
+ pj_bzero(&avi_port, sizeof(avi_port));
+
+ status = pjmedia_avi_player_create_streams(pool, fname, 0, &avi_streams);
+ if (status != PJ_SUCCESS) {
+ PJ_PERROR(2,("", status, " Error playing %s", fname));
+ rc = 210; goto on_return;
+ }
+
+ vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
+ 0,
+ PJMEDIA_TYPE_VIDEO);
+ vid_port = pjmedia_avi_stream_get_port(vid_stream);
+
+ if (vid_port) {
+ pjmedia_vid_port_param_default(&param);
+
+ status = pjmedia_vid_dev_default_param(pool,
+ PJMEDIA_VID_DEFAULT_RENDER_DEV,
+ &param.vidparam);
+ if (status != PJ_SUCCESS) {
+ rc = 220; goto on_return;
+ }
+
+ /* Create renderer, set it to active */
+ param.active = PJ_TRUE;
+ param.vidparam.dir = PJMEDIA_DIR_RENDER;
+ vfd = pjmedia_format_get_video_format_detail(&vid_port->info.fmt,
+ PJ_TRUE);
+ pjmedia_format_init_video(&param.vidparam.fmt,
+ vid_port->info.fmt.id,
+ vfd->size.w, vfd->size.h,
+ vfd->fps.num, vfd->fps.denum);
+
+ vfi = pjmedia_get_video_format_info(
+ pjmedia_video_format_mgr_instance(),
+ vid_port->info.fmt.id);
+ /* Check whether the frame is encoded */
+ if (!vfi || vfi->bpp == 0) {
+ /* Yes, prepare codec */
+ pj_str_t codec_id_st;
+ unsigned info_cnt = 1, i, k;
+ const pjmedia_vid_codec_info *codec_info;
+ pj_str_t port_name = {"codec", 5};
+ pj_uint8_t *enc_buf = NULL;
+ pj_size_t enc_buf_size = 0;
+ pjmedia_vid_dev_info rdr_info;
+ pjmedia_port codec_port;
+ codec_port_data_t codec_port_data;
+ pjmedia_vid_codec_param codec_param;
+ struct codec_fmt *codecp = NULL;
+
+ /* Lookup codec */
+ for (i = 0; i < sizeof(codec_fmts)/sizeof(codec_fmts[0]); i++) {
+ if (vid_port->info.fmt.id == codec_fmts[i].pjmedia_id) {
+ codecp = &codec_fmts[i];
+ break;
+ }
+ }
+ if (!codecp) {
+ rc = 242; goto on_return;
+ }
+ pj_cstr(&codec_id_st, codecp->codec_id);
+ status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
+ &codec_id_st,
+ &info_cnt,
+ &codec_info,
+ NULL);
+ if (status != PJ_SUCCESS) {
+ rc = 245; goto on_return;
+ }
+ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
+ &codec_param);
+ if (status != PJ_SUCCESS) {
+ rc = 246; goto on_return;
+ }
+
+ pjmedia_vid_dev_get_info(param.vidparam.rend_id, &rdr_info);
+ for (i=0; i<codec_info->dec_fmt_id_cnt; ++i) {
+ for (k=0; k<rdr_info.fmt_cnt; ++k) {
+ if (codec_info->dec_fmt_id[i]==(int)rdr_info.fmt[k].id)
+ {
+ param.vidparam.fmt.id = codec_info->dec_fmt_id[i];
+ }
+ }
+ }
+
+ /* Open codec */
+ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info,
+ &codec);
+ if (status != PJ_SUCCESS) {
+ rc = 250; goto on_return;
+ }
+
+ status = pjmedia_vid_codec_init(codec, pool);
+ if (status != PJ_SUCCESS) {
+ rc = 251; goto on_return;
+ }
+
+ pjmedia_format_copy(&codec_param.dec_fmt, &param.vidparam.fmt);
+
+ status = pjmedia_vid_codec_open(codec, &codec_param);
+ if (status != PJ_SUCCESS) {
+ rc = 252; goto on_return;
+ }
+
+ /* Alloc encoding buffer */
+ enc_buf_size = codec_param.dec_fmt.det.vid.size.w *
+ codec_param.dec_fmt.det.vid.size.h * 4
+ + 16; /*< padding, just in case */
+ enc_buf = pj_pool_alloc(pool,enc_buf_size);
+
+ /* Init codec port */
+ pj_bzero(&codec_port, sizeof(codec_port));
+ status = pjmedia_port_info_init2(&codec_port.info, &port_name,
+ 0x1234,
+ PJMEDIA_DIR_ENCODING,
+ &codec_param.dec_fmt);
+ if (status != PJ_SUCCESS) {
+ rc = 260; goto on_return;
+ }
+ pj_bzero(&codec_port_data, sizeof(codec_port_data));
+ codec_port_data.codec = codec;
+ codec_port_data.src_port = vid_port;
+ codec_port_data.enc_buf = enc_buf;
+ codec_port_data.enc_buf_size = enc_buf_size;
+
+ codec_port.get_frame = &codec_get_frame;
+ codec_port.port_data.pdata = &codec_port_data;
+
+ /* Check whether we need to convert the decoded frame */
+ if (codecp->need_conversion) {
+ pjmedia_conversion_param conv_param;
+
+ pjmedia_format_copy(&conv_param.src, &param.vidparam.fmt);
+ pjmedia_format_copy(&conv_param.dst, &param.vidparam.fmt);
+ conv_param.dst.id = codecp->dst_fmt;
+ param.vidparam.fmt.id = conv_param.dst.id;
+
+ status = pjmedia_converter_create(NULL, pool, &conv_param,
+ &codec_port_data.conv);
+ if (status != PJ_SUCCESS) {
+ rc = 270; goto on_return;
+ }
+ }
+
+ status = pjmedia_vid_port_create(pool, &param, &renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 230; goto on_return;
+ }
+
+ status = pjmedia_vid_port_connect(renderer, &codec_port,
+ PJ_FALSE);
+ } else {
+ status = pjmedia_vid_port_create(pool, &param, &renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 230; goto on_return;
+ }
+
+ /* Connect avi port to renderer */
+ status = pjmedia_vid_port_connect(renderer, vid_port,
+ PJ_FALSE);
+ }
+
+ if (status != PJ_SUCCESS) {
+ rc = 240; goto on_return;
+ }
+ }
+
+ aud_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
+ 0,
+ PJMEDIA_TYPE_AUDIO);
+ aud_port = pjmedia_avi_stream_get_port(aud_stream);
+
+ if (aud_port) {
+ /* Create sound player port. */
+ status = pjmedia_snd_port_create_player(
+ pool, /* pool */
+ -1, /* use default dev. */
+ PJMEDIA_PIA_SRATE(&aud_port->info),/* clock rate. */
+ PJMEDIA_PIA_CCNT(&aud_port->info), /* # of channels. */
+ PJMEDIA_PIA_SPF(&aud_port->info), /* samples per frame. */
+ PJMEDIA_PIA_BITS(&aud_port->info), /* bits per sample. */
+ 0, /* options */
+ &snd_port /* returned port */
+ );
+ if (status != PJ_SUCCESS) {
+ rc = 310; goto on_return;
+ }
+
+ /* Connect file port to the sound player.
+ * Stream playing will commence immediately.
+ */
+ status = pjmedia_snd_port_connect(snd_port, aud_port);
+ if (status != PJ_SUCCESS) {
+ rc = 330; goto on_return;
+ }
+ }
+
+ if (vid_port) {
+ pjmedia_vid_dev_cb cb;
+
+ pj_bzero(&cb, sizeof(cb));
+ avi_port.snd_port = snd_port;
+ avi_port.vid_port = renderer;
+ avi_port.is_running = PJ_TRUE;
+ pjmedia_vid_port_set_cb(renderer, &cb, &avi_port);
+
+ /* subscribe events */
+ pjmedia_event_subscription_init(&esub, &avi_event_cb, &avi_port);
+ pjmedia_event_subscribe(
+ pjmedia_vid_port_get_event_publisher(renderer),
+ &esub);
+
+ if (snd_port) {
+ /* Synchronize video rendering and audio playback */
+ pjmedia_vid_port_set_clock_src(
+ renderer,
+ pjmedia_snd_port_get_clock_src(
+ snd_port, PJMEDIA_DIR_PLAYBACK));
+ }
+
+
+ /* Start video streaming.. */
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS) {
+ rc = 270; goto on_return;
+ }
+ }
+
+ while (!avi_port.is_quitting) {
+ pj_thread_sleep(100);
+ }
+
+on_return:
+ if (snd_port) {
+ pjmedia_snd_port_disconnect(snd_port);
+ /* Without this sleep, Windows/DirectSound will repeteadly
+ * play the last frame during destroy.
+ */
+ pj_thread_sleep(100);
+ pjmedia_snd_port_destroy(snd_port);
+ }
+ if (renderer)
+ pjmedia_vid_port_destroy(renderer);
+ if (aud_port)
+ pjmedia_port_destroy(aud_port);
+ if (vid_port)
+ pjmedia_port_destroy(vid_port);
+ if (codec) {
+ pjmedia_vid_codec_close(codec);
+ pjmedia_vid_codec_mgr_dealloc_codec(NULL, codec);
+ }
+
+ return rc;
+}
+
+
+static int main_func(int argc, char *argv[])
+{
+ pj_caching_pool cp;
+ pj_pool_t *pool;
+ int rc = 0;
+ pj_status_t status = PJ_SUCCESS;
+
+ if (argc != 2) {
+ puts("Error: filename required");
+ puts(desc);
+ return 1;
+ }
+
+
+ /* Must init PJLIB first: */
+ status = pj_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Must create a pool factory before we can allocate any memory. */
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+ /* Create memory pool for our file player */
+ pool = pj_pool_create( &cp.factory, /* pool factory */
+ "AVI", /* pool name. */
+ 4000, /* init size */
+ 4000, /* increment size */
+ NULL /* callback on error */
+ );
+
+ pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
+ pjmedia_converter_mgr_create(pool, NULL);
+ pjmedia_vid_codec_mgr_create(pool, NULL);
+
+ status = pjmedia_vid_dev_subsys_init(&cp.factory);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ status = pjmedia_aud_subsys_init(&cp.factory);
+ if (status != PJ_SUCCESS) {
+ goto on_return;
+ }
+
+ status = pjmedia_codec_ffmpeg_init(NULL, &cp.factory);
+ if (status != PJ_SUCCESS)
+ goto on_return;
+
+ rc = aviplay(pool, argv[1]);
+
+ /*
+ * File should be playing and looping now
+ */
+
+ /* Without this sleep, Windows/DirectSound will repeteadly
+ * play the last frame during destroy.
+ */
+ pj_thread_sleep(100);
+
+on_return:
+ pjmedia_codec_ffmpeg_deinit();
+ pjmedia_aud_subsys_shutdown();
+ pjmedia_vid_dev_subsys_shutdown();
+
+ pjmedia_video_format_mgr_destroy(pjmedia_video_format_mgr_instance());
+ pjmedia_converter_mgr_destroy(pjmedia_converter_mgr_instance());
+ pjmedia_vid_codec_mgr_destroy(pjmedia_vid_codec_mgr_instance());
+
+ /* Release application pool */
+ pj_pool_release( pool );
+
+ /* Destroy pool factory */
+ pj_caching_pool_destroy( &cp );
+
+ /* Shutdown PJLIB */
+ pj_shutdown();
+
+ /* Done. */
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ return pj_run_app(&main_func, argc, argv, 0);
+}
diff --git a/pjsip-apps/src/samples/confbench.c b/pjsip-apps/src/samples/confbench.c
index 264947f9..db9cd55f 100644
--- a/pjsip-apps/src/samples/confbench.c
+++ b/pjsip-apps/src/samples/confbench.c
@@ -147,7 +147,7 @@ static pj_status_t sine_get_frame( pjmedia_port *port,
unsigned i, count, left, right;
/* Get number of samples */
- count = frame->size / 2 / port->info.channel_count;
+ count = frame->size / 2 / PJMEDIA_PIA_CCNT(&port->info);
left = 0;
right = 0;
@@ -156,7 +156,7 @@ static pj_status_t sine_get_frame( pjmedia_port *port,
*samples++ = sine->samples[left];
++left;
- if (port->info.channel_count == 2) {
+ if (PJMEDIA_PIA_CCNT(&port->info) == 2) {
*samples++ = sine->samples[right];
right += 2; /* higher pitch so we can distinguish left and right. */
if (right >= count)
@@ -187,6 +187,7 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
pjmedia_port *port;
unsigned i;
unsigned count;
+ pj_str_t port_name;
port_data *sine;
PJ_ASSERT_RETURN(pool && channel_count > 0 && channel_count <= 2,
@@ -196,17 +197,10 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);
/* Fill in port info. */
- port->info.bits_per_sample = 16;
- port->info.channel_count = channel_count;
- port->info.encoding_name = pj_str("pcm");
- port->info.has_info = 1;
- port->info.name = pj_str("sine generator");
- port->info.need_info = 0;
- port->info.pt = 0xFF;
- port->info.clock_rate = sampling_rate;
- port->info.samples_per_frame = sampling_rate * SINE_PTIME / 1000 * channel_count;
- port->info.bytes_per_frame = port->info.samples_per_frame * 2;
- port->info.type = PJMEDIA_TYPE_AUDIO;
+ port_name = pj_str("sine generator");
+ pjmedia_port_info_init(&port->info, &port_name,
+ 12345, sampling_rate, channel_count, 16,
+ sampling_rate * SINE_PTIME / 1000 * channel_count);
/* Set the function to feed frame */
port->get_frame = &sine_get_frame;
@@ -215,7 +209,7 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
port->port_data.pdata = sine = pj_pool_zalloc(pool, sizeof(port_data));
/* Create samples */
- count = port->info.samples_per_frame / channel_count;
+ count = PJMEDIA_PIA_SPF(&port->info) / channel_count;
sine->samples = pj_pool_alloc(pool, count * sizeof(pj_int16_t));
PJ_ASSERT_RETURN(sine->samples != NULL, PJ_ENOMEM);
diff --git a/pjsip-apps/src/samples/encdec.c b/pjsip-apps/src/samples/encdec.c
index 0d38ce88..117497b9 100644
--- a/pjsip-apps/src/samples/encdec.c
+++ b/pjsip-apps/src/samples/encdec.c
@@ -137,8 +137,8 @@ static pj_status_t enc_dec_test(const char *codec_id,
/* Alloc codec */
CHECK( pjmedia_codec_mgr_alloc_codec(cm, pci, &codec) );
- CHECK( codec->op->init(codec, pool) );
- CHECK( codec->op->open(codec, &param) );
+ CHECK( pjmedia_codec_init(codec, pool) );
+ CHECK( pjmedia_codec_open(codec, &param) );
for (;;) {
pjmedia_frame frm_pcm, frm_bit, out_frm, frames[4];
@@ -162,7 +162,8 @@ static pj_status_t enc_dec_test(const char *codec_id,
/* Encode */
frm_bit.buf = bitstream;
frm_bit.size = sizeof(bitstream);
- CHECK(codec->op->encode(codec, &frm_pcm, sizeof(bitstream), &frm_bit));
+ CHECK(pjmedia_codec_encode(codec, &frm_pcm, sizeof(bitstream),
+ &frm_bit));
/* On DTX, write zero frame to wavout to maintain duration */
if (frm_bit.size == 0 || frm_bit.type != PJMEDIA_FRAME_TYPE_AUDIO) {
@@ -180,8 +181,8 @@ static pj_status_t enc_dec_test(const char *codec_id,
*/
ts.u64 = 0;
cnt = PJ_ARRAY_SIZE(frames);
- CHECK( codec->op->parse(codec, bitstream, frm_bit.size, &ts, &cnt,
- frames) );
+ CHECK( pjmedia_codec_parse(codec, bitstream, frm_bit.size, &ts, &cnt,
+ frames) );
CHECK( (cnt==1 ? PJ_SUCCESS : -1) );
/* Decode or simulate packet loss */
@@ -190,11 +191,11 @@ static pj_status_t enc_dec_test(const char *codec_id,
if ((pj_rand() % 100) < (int)lost_pct) {
/* Simulate loss */
- CHECK( codec->op->recover(codec, sizeof(pcmbuf), &out_frm) );
+ CHECK( pjmedia_codec_recover(codec, sizeof(pcmbuf), &out_frm) );
TRACE_((THIS_FILE, "%d.%03d Packet lost", T));
} else {
/* Decode */
- CHECK( codec->op->decode(codec, &frames[0], sizeof(pcmbuf),
+ CHECK( pjmedia_codec_decode(codec, &frames[0], sizeof(pcmbuf),
&out_frm) );
}
@@ -210,7 +211,7 @@ static pj_status_t enc_dec_test(const char *codec_id,
pjmedia_port_destroy(wavin);
/* Close codec */
- codec->op->close(codec);
+ pjmedia_codec_close(codec);
pjmedia_codec_mgr_dealloc_codec(cm, codec);
/* Release pool */
@@ -238,21 +239,7 @@ int main(int argc, char *argv[])
CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &mept) );
/* Register all codecs */
-#if PJMEDIA_HAS_G711_CODEC
- CHECK( pjmedia_codec_g711_init(mept) );
-#endif
-#if PJMEDIA_HAS_GSM_CODEC
- CHECK( pjmedia_codec_gsm_init(mept) );
-#endif
-#if PJMEDIA_HAS_ILBC_CODEC
- CHECK( pjmedia_codec_ilbc_init(mept, 30) );
-#endif
-#if PJMEDIA_HAS_SPEEX_CODEC
- CHECK( pjmedia_codec_speex_init(mept, 0, 5, 5) );
-#endif
-#if PJMEDIA_HAS_G722_CODEC
- CHECK( pjmedia_codec_g722_init(mept) );
-#endif
+ CHECK( pjmedia_codec_register_audio_codecs(mept, NULL) );
pj_gettimeofday(&t0);
status = enc_dec_test(argv[1], argv[2], argv[3]);
diff --git a/pjsip-apps/src/samples/jbsim.c b/pjsip-apps/src/samples/jbsim.c
index e023dd55..27b11284 100644
--- a/pjsip-apps/src/samples/jbsim.c
+++ b/pjsip-apps/src/samples/jbsim.c
@@ -472,31 +472,7 @@ static pj_status_t test_init(void)
}
/* Register codecs */
-#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC != 0
- pjmedia_codec_gsm_init(g_app.endpt);
-#endif
-#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
- pjmedia_codec_g711_init(g_app.endpt);
-#endif
-#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
- pjmedia_codec_speex_init(g_app.endpt, 0, PJMEDIA_CODEC_SPEEX_DEFAULT_QUALITY,
- PJMEDIA_CODEC_SPEEX_DEFAULT_COMPLEXITY);
-#endif
-#if defined(PJMEDIA_HAS_G722_CODEC) && (PJMEDIA_HAS_G722_CODEC != 0)
- pjmedia_codec_g722_init(g_app.endpt);
-#endif
-#if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC != 0
- /* Init ILBC with mode=20 to make the losts occur at the same
- * places as other codecs.
- */
- pjmedia_codec_ilbc_init(g_app.endpt, 20);
-#endif
-#if defined(PJMEDIA_HAS_INTEL_IPP) && PJMEDIA_HAS_INTEL_IPP != 0
- pjmedia_codec_ipp_init(g_app.endpt);
-#endif
-#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC != 0
- pjmedia_codec_l16_init(g_app.endpt, 0);
-#endif
+ pjmedia_codec_register_audio_codecs(g_app.endpt, NULL);
/* Create the loop transport */
status = pjmedia_transport_loop_create(g_app.endpt, &g_app.loop);
@@ -530,8 +506,8 @@ static pj_status_t test_init(void)
}
/* Make sure stream and WAV parameters match */
- if (g_app.tx_wav->info.clock_rate != g_app.tx->port->info.clock_rate ||
- g_app.tx_wav->info.channel_count != g_app.tx->port->info.channel_count)
+ if (PJMEDIA_PIA_SRATE(&g_app.tx_wav->info) != PJMEDIA_PIA_SRATE(&g_app.tx->port->info) ||
+ PJMEDIA_PIA_CCNT(&g_app.tx_wav->info) != PJMEDIA_PIA_CCNT(&g_app.tx->port->info))
{
jbsim_perror("Error: Input WAV file has different clock rate "
"or number of channels than the codec", PJ_SUCCESS);
@@ -554,10 +530,10 @@ static pj_status_t test_init(void)
/* Create receiver WAV */
status = pjmedia_wav_writer_port_create(g_app.pool,
g_app.cfg.rx_wav_out,
- g_app.rx->port->info.clock_rate,
- g_app.rx->port->info.channel_count,
- g_app.rx->port->info.samples_per_frame,
- g_app.rx->port->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&g_app.rx->port->info),
+ PJMEDIA_PIA_CCNT(&g_app.rx->port->info),
+ PJMEDIA_PIA_SPF(&g_app.rx->port->info),
+ PJMEDIA_PIA_BITS(&g_app.rx->port->info),
0,
0,
&g_app.rx_wav);
@@ -570,8 +546,8 @@ static pj_status_t test_init(void)
/* Frame buffer */
g_app.framebuf = (pj_int16_t*)
pj_pool_alloc(g_app.pool,
- MAX(g_app.rx->port->info.samples_per_frame,
- g_app.tx->port->info.samples_per_frame) * sizeof(pj_int16_t));
+ MAX(PJMEDIA_PIA_SPF(&g_app.rx->port->info),
+ PJMEDIA_PIA_SPF(&g_app.tx->port->info)) * sizeof(pj_int16_t));
/* Set the receiver in the loop transport */
@@ -594,15 +570,15 @@ static void run_one_frame(pjmedia_port *src, pjmedia_port *dst,
pj_bzero(&frame, sizeof(frame));
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.buf = g_app.framebuf;
- frame.size = dst->info.samples_per_frame * 2;
+ frame.size = PJMEDIA_PIA_SPF(&dst->info) * 2;
status = pjmedia_port_get_frame(src, &frame);
pj_assert(status == PJ_SUCCESS);
if (status!= PJ_SUCCESS || frame.type != PJMEDIA_FRAME_TYPE_AUDIO) {
frame.buf = g_app.framebuf;
- pjmedia_zero_samples(g_app.framebuf, src->info.samples_per_frame);
- frame.size = src->info.samples_per_frame * 2;
+ pjmedia_zero_samples(g_app.framebuf, PJMEDIA_PIA_SPF(&src->info));
+ frame.size = PJMEDIA_PIA_SPF(&src->info) * 2;
if (has_frame)
*has_frame = PJ_FALSE;
} else {
@@ -628,8 +604,8 @@ static void tx_tick(const pj_time_val *t)
long pkt_interval;
/* packet interval, without jitter */
- pkt_interval = port->info.samples_per_frame * 1000 /
- port->info.clock_rate;
+ pkt_interval = PJMEDIA_PIA_SPF(&port->info) * 1000 /
+ PJMEDIA_PIA_SRATE(&port->info);
while (PJ_TIME_VAL_GTE(*t, strm->state.tx.next_schedule)) {
struct log_entry entry;
@@ -777,8 +753,8 @@ static void rx_tick(const pj_time_val *t)
pjmedia_port *port = g_app.rx->port;
long pkt_interval;
- pkt_interval = port->info.samples_per_frame * 1000 /
- port->info.clock_rate *
+ pkt_interval = PJMEDIA_PIA_SPF(&port->info) * 1000 /
+ PJMEDIA_PIA_SRATE(&port->info) *
g_app.cfg.rx_snd_burst;
if (PJ_TIME_VAL_GTE(*t, strm->state.rx.next_schedule)) {
diff --git a/pjsip-apps/src/samples/latency.c b/pjsip-apps/src/samples/latency.c
index f2f0779e..297b80b7 100644
--- a/pjsip-apps/src/samples/latency.c
+++ b/pjsip-apps/src/samples/latency.c
@@ -60,7 +60,7 @@ static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
lat_min = 10000,
lat_max = 0;
- samples_per_frame = wav->info.samples_per_frame;
+ samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
frm.buf = pj_pool_alloc(pool, samples_per_frame * 2);
frm.size = samples_per_frame * 2;
len = pjmedia_wav_player_get_len(wav);
@@ -76,13 +76,13 @@ static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
read += samples_per_frame;
}
- if (read < 2 * wav->info.clock_rate) {
+ if (read < 2 * PJMEDIA_PIA_SRATE(&wav->info)) {
puts("Error: too short");
return -1;
}
start_pos = 0;
- while (start_pos < len/2 - wav->info.clock_rate) {
+ while (start_pos < len/2 - PJMEDIA_PIA_SRATE(&wav->info)) {
int max_signal = 0;
unsigned max_signal_pos = start_pos;
unsigned max_echo_pos = 0;
@@ -90,7 +90,7 @@ static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
unsigned lat;
/* Get the largest signal in the next 0.7s */
- for (i=start_pos; i<start_pos + wav->info.clock_rate * 700 / 1000; ++i) {
+ for (i=start_pos; i<start_pos + PJMEDIA_PIA_SRATE(&wav->info) * 700 / 1000; ++i) {
if (abs(buf[i]) > max_signal) {
max_signal = abs(buf[i]);
max_signal_pos = i;
@@ -98,19 +98,19 @@ static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
}
/* Advance 10ms from max_signal_pos */
- pos = max_signal_pos + 10 * wav->info.clock_rate / 1000;
+ pos = max_signal_pos + 10 * PJMEDIA_PIA_SRATE(&wav->info) / 1000;
/* Get the largest signal in the next 500ms */
max_signal = 0;
max_echo_pos = pos;
- for (i=pos; i<pos+wav->info.clock_rate/2; ++i) {
+ for (i=pos; i<pos+PJMEDIA_PIA_SRATE(&wav->info)/2; ++i) {
if (abs(buf[i]) > max_signal) {
max_signal = abs(buf[i]);
max_echo_pos = i;
}
}
- lat = (max_echo_pos - max_signal_pos) * 1000 / wav->info.clock_rate;
+ lat = (max_echo_pos - max_signal_pos) * 1000 / PJMEDIA_PIA_SRATE(&wav->info);
#if 0
printf("Latency = %u\n", lat);
@@ -124,7 +124,7 @@ static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
lat_max = lat;
/* Advance next loop */
- start_pos += wav->info.clock_rate;
+ start_pos += PJMEDIA_PIA_SRATE(&wav->info);
}
printf("Latency average = %u\n", lat_sum / lat_cnt);
diff --git a/pjsip-apps/src/samples/level.c b/pjsip-apps/src/samples/level.c
index d4a5ae16..6bba3fe1 100644
--- a/pjsip-apps/src/samples/level.c
+++ b/pjsip-apps/src/samples/level.c
@@ -124,7 +124,7 @@ int main(int argc, char *argv[])
return 1;
}
- if (file_port->info.samples_per_frame > NSAMPLES) {
+ if (PJMEDIA_PIA_SPF(&file_port->info) > NSAMPLES) {
app_perror(THIS_FILE, "WAV clock rate is too big", PJ_EINVAL);
return 1;
}
@@ -145,11 +145,11 @@ int main(int argc, char *argv[])
pjmedia_port_get_frame(file_port, &frm);
level32 = pjmedia_calc_avg_signal(framebuf,
- file_port->info.samples_per_frame);
+ PJMEDIA_PIA_SPF(&file_port->info));
level = pjmedia_linear2ulaw(level32) ^ 0xFF;
- ms = i * 1000 * file_port->info.samples_per_frame /
- file_port->info.clock_rate;
+ ms = i * 1000 * PJMEDIA_PIA_SPF(&file_port->info) /
+ PJMEDIA_PIA_SRATE(&file_port->info);
printf("%03d.%03d\t%7d\t%7d\n",
ms/1000, ms%1000, level, level32);
}
diff --git a/pjsip-apps/src/samples/mix.c b/pjsip-apps/src/samples/mix.c
index 513e5466..cc139f76 100644
--- a/pjsip-apps/src/samples/mix.c
+++ b/pjsip-apps/src/samples/mix.c
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
&wav_input[i].port) );
len = pjmedia_wav_player_get_len(wav_input[i].port);
len = (pj_ssize_t)(len * 1.0 * clock_rate /
- wav_input[i].port->info.clock_rate);
+ PJMEDIA_PIA_SRATE(&wav_input[i].port->info));
if (len > (pj_ssize_t)longest)
longest = len;
@@ -199,7 +199,7 @@ int main(int argc, char *argv[])
pjmedia_frame frame;
frame.buf = framebuf;
- frame.size = cp->info.samples_per_frame * 2;
+ frame.size = PJMEDIA_PIA_SPF(&cp->info) * 2;
pj_assert(frame.size <= sizeof(framebuf));
CHECK( pjmedia_port_get_frame(cp, &frame) );
diff --git a/pjsip-apps/src/samples/pcaputil.c b/pjsip-apps/src/samples/pcaputil.c
index d565bd63..1f6efb27 100644
--- a/pjsip-apps/src/samples/pcaputil.c
+++ b/pjsip-apps/src/samples/pcaputil.c
@@ -87,7 +87,7 @@ static void err_exit(const char *title, pj_status_t status)
pj_ssize_t pos = pjmedia_wav_writer_port_get_pos(app.wav);
if (pos >= 0) {
unsigned msec;
- msec = pos / 2 * 1000 / app.wav->info.clock_rate;
+ msec = pos / 2 * 1000 / PJMEDIA_PIA_SRATE(&app.wav->info);
printf("Written: %dm:%02ds.%03d\n",
msec / 1000 / 60,
(msec / 1000) % 60,
@@ -98,7 +98,7 @@ static void err_exit(const char *title, pj_status_t status)
if (app.pcap) pj_pcap_close(app.pcap);
if (app.codec) {
pjmedia_codec_mgr *cmgr;
- app.codec->op->close(app.codec);
+ pjmedia_codec_close(app.codec);
cmgr = pjmedia_endpt_get_codec_mgr(app.mept);
pjmedia_codec_mgr_dealloc_codec(cmgr, app.codec);
}
@@ -229,29 +229,7 @@ static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto,
pj_status_t status;
/* Initialize all codecs */
-#if PJMEDIA_HAS_SPEEX_CODEC
- T( pjmedia_codec_speex_init(app.mept, 0, 10, 10) );
-#endif /* PJMEDIA_HAS_SPEEX_CODEC */
-
-#if PJMEDIA_HAS_ILBC_CODEC
- T( pjmedia_codec_ilbc_init(app.mept, 30) );
-#endif /* PJMEDIA_HAS_ILBC_CODEC */
-
-#if PJMEDIA_HAS_GSM_CODEC
- T( pjmedia_codec_gsm_init(app.mept) );
-#endif /* PJMEDIA_HAS_GSM_CODEC */
-
-#if PJMEDIA_HAS_G711_CODEC
- T( pjmedia_codec_g711_init(app.mept) );
-#endif /* PJMEDIA_HAS_G711_CODEC */
-
-#if PJMEDIA_HAS_G722_CODEC
- T( pjmedia_codec_g722_init(app.mept) );
-#endif /* PJMEDIA_HAS_G722_CODEC */
-
-#if PJMEDIA_HAS_L16_CODEC
- T( pjmedia_codec_l16_init(app.mept, 0) );
-#endif /* PJMEDIA_HAS_L16_CODEC */
+ T( pjmedia_codec_register_audio_codecs(app.mept, NULL) );
/* Create SRTP transport is needed */
#if PJMEDIA_HAS_SRTP
@@ -282,8 +260,8 @@ static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto,
/* Alloc and init codec */
T( pjmedia_codec_mgr_alloc_codec(cmgr, ci, &app.codec) );
- T( app.codec->op->init(app.codec, app.pool) );
- T( app.codec->op->open(app.codec, &param) );
+ T( pjmedia_codec_init(app.codec, app.pool) );
+ T( pjmedia_codec_open(app.codec, &param) );
/* Open WAV file */
samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000;
@@ -307,7 +285,7 @@ static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto,
/* Parse first packet */
ts.u64 = 0;
frame_cnt = PJ_ARRAY_SIZE(frames);
- T( app.codec->op->parse(app.codec, pkt0.payload, pkt0.payload_len,
+ T( pjmedia_codec_parse(app.codec, pkt0.payload, pkt0.payload_len,
&ts, &frame_cnt, frames) );
/* Decode and write to WAV file */
@@ -318,7 +296,7 @@ static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto,
pcm_frame.buf = pcm;
pcm_frame.size = samples_per_frame * 2;
- T( app.codec->op->decode(app.codec, &frames[i], pcm_frame.size,
+ T( pjmedia_codec_decode(app.codec, &frames[i], pcm_frame.size,
&pcm_frame) );
T( pjmedia_port_put_frame(app.wav, &pcm_frame) );
samples_cnt += samples_per_frame;
@@ -337,8 +315,8 @@ static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto,
pcm_frame.size = samples_per_frame * 2;
if (app.codec->op->recover) {
- T( app.codec->op->recover(app.codec, pcm_frame.size,
- &pcm_frame) );
+ T( pjmedia_codec_recover(app.codec, pcm_frame.size,
+ &pcm_frame) );
} else {
pj_bzero(pcm_frame.buf, pcm_frame.size);
}
diff --git a/pjsip-apps/src/samples/pjsip-perf.c b/pjsip-apps/src/samples/pjsip-perf.c
index 9c8fec3a..c462cf84 100644
--- a/pjsip-apps/src/samples/pjsip-perf.c
+++ b/pjsip-apps/src/samples/pjsip-perf.c
@@ -928,18 +928,7 @@ static pj_status_t init_media()
/* Must register all codecs to be supported */
-#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
- pjmedia_codec_g711_init(app.med_endpt);
-#endif
-#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC!=0
- pjmedia_codec_gsm_init(app.med_endpt);
-#endif
-#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
- pjmedia_codec_speex_init(app.med_endpt, PJMEDIA_SPEEX_NO_UWB, 3, 3);
-#endif
-#if defined(PJMEDIA_HAS_G722_CODEC) && PJMEDIA_HAS_G722_CODEC!=0
- pjmedia_codec_g722_init(app.med_endpt);
-#endif
+ pjmedia_codec_register_audio_codecs(app.med_endpt, NULL);
/* Init dummy socket addresses */
app.skinfo_cnt = 0;
diff --git a/pjsip-apps/src/samples/playfile.c b/pjsip-apps/src/samples/playfile.c
index 98e80826..10116ffa 100644
--- a/pjsip-apps/src/samples/playfile.c
+++ b/pjsip-apps/src/samples/playfile.c
@@ -139,10 +139,10 @@ int main(int argc, char *argv[])
status = pjmedia_snd_port_create_player(
pool, /* pool */
-1, /* use default dev. */
- file_port->info.clock_rate, /* clock rate. */
- file_port->info.channel_count, /* # of channels. */
- file_port->info.samples_per_frame, /* samples per frame. */
- file_port->info.bits_per_sample, /* bits per sample. */
+ PJMEDIA_PIA_SRATE(&file_port->info),/* clock rate. */
+ PJMEDIA_PIA_CCNT(&file_port->info),/* # of channels. */
+ PJMEDIA_PIA_SPF(&file_port->info), /* samples per frame. */
+ PJMEDIA_PIA_BITS(&file_port->info),/* bits per sample. */
0, /* options */
&snd_port /* returned port */
);
diff --git a/pjsip-apps/src/samples/playsine.c b/pjsip-apps/src/samples/playsine.c
index a1370c24..00cabe47 100644
--- a/pjsip-apps/src/samples/playsine.c
+++ b/pjsip-apps/src/samples/playsine.c
@@ -86,7 +86,7 @@ static pj_status_t sine_get_frame( pjmedia_port *port,
unsigned i, count, left, right;
/* Get number of samples */
- count = frame->size / 2 / port->info.channel_count;
+ count = frame->size / 2 / PJMEDIA_PIA_CCNT(&port->info);
left = 0;
right = 0;
@@ -95,7 +95,7 @@ static pj_status_t sine_get_frame( pjmedia_port *port,
*samples++ = sine->samples[left];
++left;
- if (port->info.channel_count == 2) {
+ if (PJMEDIA_PIA_CCNT(&port->info) == 2) {
*samples++ = sine->samples[right];
right += 2; /* higher pitch so we can distinguish left and right. */
if (right >= count)
@@ -126,6 +126,7 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
pjmedia_port *port;
unsigned i;
unsigned count;
+ pj_str_t name;
port_data *sine;
PJ_ASSERT_RETURN(pool && channel_count > 0 && channel_count <= 2,
@@ -135,17 +136,12 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
PJ_ASSERT_RETURN(port != NULL, PJ_ENOMEM);
/* Fill in port info. */
- port->info.bits_per_sample = 16;
- port->info.channel_count = channel_count;
- port->info.encoding_name = pj_str("pcm");
- port->info.has_info = 1;
- port->info.name = pj_str("sine generator");
- port->info.need_info = 0;
- port->info.pt = 0xFF;
- port->info.clock_rate = sampling_rate;
- port->info.samples_per_frame = sampling_rate * 20 / 1000 * channel_count;
- port->info.bytes_per_frame = port->info.samples_per_frame * 2;
- port->info.type = PJMEDIA_TYPE_AUDIO;
+ name = pj_str("sine generator");
+ pjmedia_port_info_init(&port->info, &name,
+ PJMEDIA_SIG_CLASS_PORT_AUD('s', 'i'),
+ sampling_rate,
+ channel_count,
+ 16, sampling_rate * 20 / 1000 * channel_count);
/* Set the function to feed frame */
port->get_frame = &sine_get_frame;
@@ -154,7 +150,7 @@ static pj_status_t create_sine_port(pj_pool_t *pool,
port->port_data.pdata = sine = pj_pool_zalloc(pool, sizeof(port_data));
/* Create samples */
- count = port->info.samples_per_frame / channel_count;
+ count = PJMEDIA_PIA_SPF(&port->info) / channel_count;
sine->samples = pj_pool_alloc(pool, count * sizeof(pj_int16_t));
PJ_ASSERT_RETURN(sine->samples != NULL, PJ_ENOMEM);
@@ -244,10 +240,10 @@ int main(int argc, char *argv[])
status = pjmedia_snd_port_create_player(
pool, /* pool */
-1, /* use default dev. */
- sine_port->info.clock_rate, /* clock rate. */
- sine_port->info.channel_count, /* # of channels. */
- sine_port->info.samples_per_frame, /* samples per frame. */
- sine_port->info.bits_per_sample, /* bits per sample. */
+ PJMEDIA_PIA_SRATE(&sine_port->info),/* clock rate. */
+ PJMEDIA_PIA_CCNT(&sine_port->info),/* # of channels. */
+ PJMEDIA_PIA_SPF(&sine_port->info), /* samples per frame. */
+ PJMEDIA_PIA_BITS(&sine_port->info),/* bits per sample. */
0, /* options */
&snd_port /* returned port */
);
diff --git a/pjsip-apps/src/samples/recfile.c b/pjsip-apps/src/samples/recfile.c
index bd38bd80..60ca4e4f 100644
--- a/pjsip-apps/src/samples/recfile.c
+++ b/pjsip-apps/src/samples/recfile.c
@@ -134,10 +134,10 @@ int main(int argc, char *argv[])
status = pjmedia_snd_port_create_rec(
pool, /* pool */
-1, /* use default dev. */
- file_port->info.clock_rate, /* clock rate. */
- file_port->info.channel_count, /* # of channels. */
- file_port->info.samples_per_frame, /* samples per frame. */
- file_port->info.bits_per_sample, /* bits per sample. */
+ PJMEDIA_PIA_SRATE(&file_port->info),/* clock rate. */
+ PJMEDIA_PIA_CCNT(&file_port->info),/* # of channels. */
+ PJMEDIA_PIA_SPF(&file_port->info), /* samples per frame. */
+ PJMEDIA_PIA_BITS(&file_port->info),/* bits per sample. */
0, /* options */
&snd_port /* returned port */
);
diff --git a/pjsip-apps/src/samples/resampleplay.c b/pjsip-apps/src/samples/resampleplay.c
index 2132d618..5a40e308 100644
--- a/pjsip-apps/src/samples/resampleplay.c
+++ b/pjsip-apps/src/samples/resampleplay.c
@@ -129,7 +129,7 @@ int main(int argc, char *argv[])
}
/* File must have same number of channels. */
- if (file_port->info.channel_count != (unsigned)channel_count) {
+ if (PJMEDIA_PIA_CCNT(&file_port->info) != (unsigned)channel_count) {
PJ_LOG(3,(THIS_FILE, "Error: file has different number of channels. "
"Perhaps you'd need -c option?"));
pjmedia_port_destroy(file_port);
@@ -186,7 +186,8 @@ int main(int argc, char *argv[])
printf("Playing %s at sampling rate %d (original file sampling rate=%d)\n",
- argv[pj_optind], sampling_rate, file_port->info.clock_rate);
+ argv[pj_optind], sampling_rate,
+ PJMEDIA_PIA_SRATE(&file_port->info));
puts("");
puts("Press <ENTER> to stop playing and quit");
diff --git a/pjsip-apps/src/samples/simpleua.c b/pjsip-apps/src/samples/simpleua.c
index 38b13923..2ec49d37 100644
--- a/pjsip-apps/src/samples/simpleua.c
+++ b/pjsip-apps/src/samples/simpleua.c
@@ -67,11 +67,19 @@
/* Settings */
-#define AF pj_AF_INET() /* Change to pj_AF_INET6() for IPv6.
+#define AF pj_AF_INET() /* Change to pj_AF_INET6() for IPv6.
* PJ_HAS_IPV6 must be enabled and
* your system must support IPv6. */
-#define SIP_PORT 5060 /* Listening SIP port */
-#define RTP_PORT 4000 /* RTP port */
+#if 0
+#define SIP_PORT 5080 /* Listening SIP port */
+#define RTP_PORT 5000 /* RTP port */
+#else
+#define SIP_PORT 5060 /* Listening SIP port */
+#define RTP_PORT 4000 /* RTP port */
+#endif
+
+#define MAX_MEDIA_CNT 2 /* Media count, set to 1 for audio
+ * only or 2 for audio and video */
/*
* Static variables.
@@ -82,15 +90,24 @@ static pjsip_endpoint *g_endpt; /* SIP endpoint. */
static pj_caching_pool cp; /* Global pool factory. */
static pjmedia_endpt *g_med_endpt; /* Media endpoint. */
-static pjmedia_transport_info g_med_tpinfo; /* Socket info for media */
-static pjmedia_transport *g_med_transport;/* Media stream transport */
+
+static pjmedia_transport_info g_med_tpinfo[MAX_MEDIA_CNT];
+ /* Socket info for media */
+static pjmedia_transport *g_med_transport[MAX_MEDIA_CNT];
+ /* Media stream transport */
+static pjmedia_sock_info g_sock_info[MAX_MEDIA_CNT];
+ /* Socket info array */
/* Call variables: */
static pjsip_inv_session *g_inv; /* Current invite session. */
-static pjmedia_session *g_med_session; /* Call's media session. */
-static pjmedia_snd_port *g_snd_player; /* Call's sound player */
-static pjmedia_snd_port *g_snd_rec; /* Call's sound recorder. */
+static pjmedia_stream *g_med_stream; /* Call's audio stream. */
+static pjmedia_snd_port *g_snd_port; /* Sound device. */
+#if PJMEDIA_HAS_VIDEO
+static pjmedia_vid_stream *g_med_vstream; /* Call's video stream. */
+static pjmedia_vid_port *g_vid_capturer;/* Call's video capturer. */
+static pjmedia_vid_port *g_vid_renderer;/* Call's video renderer. */
+#endif /* PJMEDIA_HAS_VIDEO */
/*
* Prototypes:
@@ -136,6 +153,68 @@ static pjsip_module mod_simpleua =
};
+/* Notification on incoming messages */
+static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
+{
+ PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
+ "%.*s\n"
+ "--end msg--",
+ rdata->msg_info.len,
+ pjsip_rx_data_get_info(rdata),
+ rdata->tp_info.transport->type_name,
+ rdata->pkt_info.src_name,
+ rdata->pkt_info.src_port,
+ (int)rdata->msg_info.len,
+ rdata->msg_info.msg_buf));
+
+ /* Always return false, otherwise messages will not get processed! */
+ return PJ_FALSE;
+}
+
+/* Notification on outgoing messages */
+static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
+{
+
+ /* Important note:
+ * tp_info field is only valid after outgoing messages has passed
+ * transport layer. So don't try to access tp_info when the module
+ * has lower priority than transport layer.
+ */
+
+ PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
+ "%.*s\n"
+ "--end msg--",
+ (tdata->buf.cur - tdata->buf.start),
+ pjsip_tx_data_get_info(tdata),
+ tdata->tp_info.transport->type_name,
+ tdata->tp_info.dst_name,
+ tdata->tp_info.dst_port,
+ (int)(tdata->buf.cur - tdata->buf.start),
+ tdata->buf.start));
+
+ /* Always return success, otherwise message will not get sent! */
+ return PJ_SUCCESS;
+}
+
+/* The module instance. */
+static pjsip_module msg_logger =
+{
+ NULL, NULL, /* prev, next. */
+ { "mod-msg-log", 13 }, /* Name. */
+ -1, /* Id */
+ PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
+ NULL, /* load() */
+ NULL, /* start() */
+ NULL, /* stop() */
+ NULL, /* unload() */
+ &logging_on_rx_msg, /* on_rx_request() */
+ &logging_on_rx_msg, /* on_rx_response() */
+ &logging_on_tx_msg, /* on_tx_request. */
+ &logging_on_tx_msg, /* on_tx_response() */
+ NULL, /* on_tsx_state() */
+
+};
+
/*
* main()
@@ -145,12 +224,15 @@ static pjsip_module mod_simpleua =
*/
int main(int argc, char *argv[])
{
+ pj_pool_t *pool;
pj_status_t status;
+ unsigned i;
/* Must init PJLIB first: */
status = pj_init();
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+ pj_log_set_level(5);
/* Then init PJLIB-UTIL: */
status = pjlib_util_init();
@@ -262,6 +344,12 @@ int main(int argc, char *argv[])
status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+ /*
+ * Register message logger module.
+ */
+ status = pjsip_endpt_register_module( g_endpt, &msg_logger);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
/*
* Initialize media endpoint.
@@ -284,27 +372,52 @@ int main(int argc, char *argv[])
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
#endif
+
+ /* Init video subsystem */
+#if PJMEDIA_HAS_VIDEO
+ pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512);
+ status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+ status = pjmedia_converter_mgr_create(pool, NULL);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+ status = pjmedia_vid_codec_mgr_create(pool, NULL);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+ status = pjmedia_vid_dev_subsys_init(&cp.factory);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+# if PJMEDIA_HAS_FFMPEG_CODEC
+ /* Init ffmpeg video codecs */
+ status = pjmedia_codec_ffmpeg_init(NULL, &cp.factory);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+# endif /* PJMEDIA_HAS_FFMPEG_CODEC */
+
+#endif /* PJMEDIA_HAS_VIDEO */
/*
* Create media transport used to send/receive RTP/RTCP socket.
* One media transport is needed for each call. Application may
* opt to re-use the same media transport for subsequent calls.
*/
- status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL,
- RTP_PORT, 0, &g_med_transport);
- if (status != PJ_SUCCESS) {
- app_perror(THIS_FILE, "Unable to create media transport", status);
- return 1;
- }
+ for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) {
+ status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL,
+ RTP_PORT + i*2, 0,
+ &g_med_transport[i]);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to create media transport", status);
+ return 1;
+ }
- /*
- * Get socket info (address, port) of the media transport. We will
- * need this info to create SDP (i.e. the address and port info in
- * the SDP).
- */
- pjmedia_transport_info_init(&g_med_tpinfo);
- pjmedia_transport_get_info(g_med_transport, &g_med_tpinfo);
+ /*
+ * Get socket info (address, port) of the media transport. We will
+ * need this info to create SDP (i.e. the address and port info in
+ * the SDP).
+ */
+ pjmedia_transport_info_init(&g_med_tpinfo[i]);
+ pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]);
+ pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info,
+ sizeof(pjmedia_sock_info));
+ }
/*
* If URL is specified, then make call immediately.
@@ -360,15 +473,12 @@ int main(int argc, char *argv[])
/* Get the SDP body to be put in the outgoing INVITE, by asking
- * media endpoint to create one for us. The SDP will contain all
- * codecs that have been registered to it (in this case, only
- * PCMA and PCMU), plus telephony event.
+ * media endpoint to create one for us.
*/
status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */
dlg->pool, /* pool. */
- 1, /* # of streams */
- &g_med_tpinfo.sock_info,
- /* RTP sock info */
+ MAX_MEDIA_CNT, /* # of streams */
+ g_sock_info, /* RTP sock info */
&local_sdp); /* the SDP result */
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
@@ -440,6 +550,51 @@ int main(int argc, char *argv[])
/* On exit, dump current memory usage: */
dump_pool_usage(THIS_FILE, &cp);
+ /* Destroy audio ports. Destroy the audio port first
+ * before the stream since the audio port has threads
+ * that get/put frames to the stream.
+ */
+ if (g_snd_port)
+ pjmedia_snd_port_destroy(g_snd_port);
+
+ /* Destroy video ports */
+#if PJMEDIA_HAS_VIDEO
+ if (g_vid_capturer)
+ pjmedia_vid_port_destroy(g_vid_capturer);
+ if (g_vid_renderer)
+ pjmedia_vid_port_destroy(g_vid_renderer);
+#endif
+
+ /* Destroy streams */
+ if (g_med_stream)
+ pjmedia_stream_destroy(g_med_stream);
+#if PJMEDIA_HAS_VIDEO
+ if (g_med_vstream)
+ pjmedia_vid_stream_destroy(g_med_vstream);
+#endif
+
+ /* Destroy media transports */
+ for (i = 0; i < MAX_MEDIA_CNT; ++i) {
+ if (g_med_transport[i])
+ pjmedia_transport_close(g_med_transport[i]);
+ }
+
+ /* Deinit ffmpeg codec */
+#if PJMEDIA_HAS_FFMPEG_CODEC
+ pjmedia_codec_ffmpeg_deinit();
+#endif
+
+ /* Deinit pjmedia endpoint */
+ if (g_med_endpt)
+ pjmedia_endpt_destroy(g_med_endpt);
+
+ /* Deinit pjsip endpoint */
+ if (g_endpt)
+ pjsip_endpt_destroy(g_endpt);
+
+ /* Release pool */
+ pj_pool_release(pool);
+
return 0;
}
@@ -574,9 +729,8 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
* Get media capability from media endpoint:
*/
- status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1,
- &g_med_tpinfo.sock_info,
- &local_sdp);
+ status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool,
+ MAX_MEDIA_CNT, g_sock_info, &local_sdp);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
@@ -639,7 +793,7 @@ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
static void call_on_media_update( pjsip_inv_session *inv,
pj_status_t status)
{
- pjmedia_session_info sess_info;
+ pjmedia_stream_info stream_info;
const pjmedia_sdp_session *local_sdp;
const pjmedia_sdp_session *remote_sdp;
pjmedia_port *media_port;
@@ -662,88 +816,211 @@ static void call_on_media_update( pjsip_inv_session *inv,
status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
- /* Create session info based on the two SDPs.
- * We only support one stream per session for now.
- */
- status = pjmedia_session_info_from_sdp(inv->dlg->pool, g_med_endpt,
- 1, &sess_info,
- local_sdp, remote_sdp);
+ /* Create stream info based on the media audio SDP. */
+ status = pjmedia_stream_info_from_sdp(&stream_info, inv->dlg->pool,
+ g_med_endpt,
+ local_sdp, remote_sdp, 0);
if (status != PJ_SUCCESS) {
- app_perror( THIS_FILE, "Unable to create media session", status);
+ app_perror(THIS_FILE,"Unable to create audio stream info",status);
return;
}
- /* If required, we can also change some settings in the session info,
+ /* If required, we can also change some settings in the stream info,
* (such as jitter buffer settings, codec settings, etc) before we
- * create the session.
+ * create the stream.
*/
- /* Create new media session, passing the two SDPs, and also the
+ /* Create new audio media stream, passing the stream info, and also the
* media socket that we created earlier.
- * The media session is active immediately.
*/
- status = pjmedia_session_create( g_med_endpt, &sess_info,
- &g_med_transport, NULL, &g_med_session );
+ status = pjmedia_stream_create(g_med_endpt, inv->dlg->pool, &stream_info,
+ g_med_transport[0], NULL, &g_med_stream);
if (status != PJ_SUCCESS) {
- app_perror( THIS_FILE, "Unable to create media session", status);
+ app_perror( THIS_FILE, "Unable to create audio stream", status);
return;
}
+ /* Start the audio stream */
+ status = pjmedia_stream_start(g_med_stream);
+ if (status != PJ_SUCCESS) {
+ app_perror( THIS_FILE, "Unable to start audio stream", status);
+ return;
+ }
- /* Get the media port interface of the first stream in the session.
+ /* Get the media port interface of the audio stream.
* Media port interface is basicly a struct containing get_frame() and
* put_frame() function. With this media port interface, we can attach
* the port interface to conference bridge, or directly to a sound
* player/recorder device.
*/
- pjmedia_session_get_port(g_med_session, 0, &media_port);
-
+ pjmedia_stream_get_port(g_med_stream, &media_port);
+
+ /* Create sound port */
+ pjmedia_snd_port_create(inv->pool,
+ PJMEDIA_AUD_DEFAULT_CAPTURE_DEV,
+ PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV,
+ PJMEDIA_PIA_SRATE(&media_port->info),/* clock rate */
+ PJMEDIA_PIA_CCNT(&media_port->info),/* channel count */
+ PJMEDIA_PIA_SPF(&media_port->info), /* samples per frame*/
+ PJMEDIA_PIA_BITS(&media_port->info),/* bits per sample */
+ 0,
+ &g_snd_port);
-
- /* Create a sound Player device and connect the media port to the
- * sound device.
- */
- status = pjmedia_snd_port_create_player(
- inv->pool, /* pool */
- -1, /* sound dev id */
- media_port->info.clock_rate, /* clock rate */
- media_port->info.channel_count, /* channel count */
- media_port->info.samples_per_frame, /* samples per frame*/
- media_port->info.bits_per_sample, /* bits per sample */
- 0, /* options */
- &g_snd_player);
if (status != PJ_SUCCESS) {
- app_perror( THIS_FILE, "Unable to create sound player", status);
+ app_perror( THIS_FILE, "Unable to create sound port", status);
PJ_LOG(3,(THIS_FILE, "%d %d %d %d",
- media_port->info.clock_rate, /* clock rate */
- media_port->info.channel_count, /* channel count */
- media_port->info.samples_per_frame, /* samples per frame*/
- media_port->info.bits_per_sample /* bits per sample */
+ PJMEDIA_PIA_SRATE(&media_port->info),/* clock rate */
+ PJMEDIA_PIA_CCNT(&media_port->info),/* channel count */
+ PJMEDIA_PIA_SPF(&media_port->info), /* samples per frame*/
+ PJMEDIA_PIA_BITS(&media_port->info) /* bits per sample */
));
return;
}
- status = pjmedia_snd_port_connect(g_snd_player, media_port);
+ status = pjmedia_snd_port_connect(g_snd_port, media_port);
- /* Create a sound recorder device and connect the media port to the
- * sound device.
+ /* Get the media port interface of the second stream in the session,
+ * which is video stream. With this media port interface, we can attach
+ * the port directly to a renderer/capture video device.
*/
- status = pjmedia_snd_port_create_rec(
- inv->pool, /* pool */
- -1, /* sound dev id */
- media_port->info.clock_rate, /* clock rate */
- media_port->info.channel_count, /* channel count */
- media_port->info.samples_per_frame, /* samples per frame*/
- media_port->info.bits_per_sample, /* bits per sample */
- 0, /* options */
- &g_snd_rec);
- if (status != PJ_SUCCESS) {
- app_perror( THIS_FILE, "Unable to create sound recorder", status);
- return;
- }
+#if PJMEDIA_HAS_VIDEO
+ if (local_sdp->media_count > 1) {
+ pjmedia_vid_stream_info vstream_info;
+ pjmedia_vid_port_param vport_param;
+
+ pjmedia_vid_port_param_default(&vport_param);
+
+ /* Create stream info based on the media video SDP. */
+ status = pjmedia_vid_stream_info_from_sdp(&vstream_info,
+ inv->dlg->pool, g_med_endpt,
+ local_sdp, remote_sdp, 1);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE,"Unable to create video stream info",status);
+ return;
+ }
+
+ /* If required, we can also change some settings in the stream info,
+ * (such as jitter buffer settings, codec settings, etc) before we
+ * create the video stream.
+ */
+
+ /* Create new video media stream, passing the stream info, and also the
+ * media socket that we created earlier.
+ */
+ status = pjmedia_vid_stream_create(g_med_endpt, NULL, &vstream_info,
+ g_med_transport[1], NULL,
+ &g_med_vstream);
+ if (status != PJ_SUCCESS) {
+ app_perror( THIS_FILE, "Unable to create video stream", status);
+ return;
+ }
+
+ /* Start the video stream */
+ status = pjmedia_vid_stream_start(g_med_vstream);
+ if (status != PJ_SUCCESS) {
+ app_perror( THIS_FILE, "Unable to start video stream", status);
+ return;
+ }
+
+ if (vstream_info.dir & PJMEDIA_DIR_DECODING) {
+ status = pjmedia_vid_dev_default_param(
+ inv->pool, PJMEDIA_VID_DEFAULT_RENDER_DEV,
+ &vport_param.vidparam);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to get default param of video "
+ "renderer device", status);
+ return;
+ }
- status = pjmedia_snd_port_connect(g_snd_rec, media_port);
+ /* Get video stream port for decoding direction */
+ pjmedia_vid_stream_get_port(g_med_vstream, PJMEDIA_DIR_DECODING,
+ &media_port);
+
+ /* Set format */
+ pjmedia_format_copy(&vport_param.vidparam.fmt,
+ &media_port->info.fmt);
+ vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
+ vport_param.active = PJ_TRUE;
+
+ /* Create renderer */
+ status = pjmedia_vid_port_create(inv->pool, &vport_param,
+ &g_vid_renderer);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to create video renderer device",
+ status);
+ return;
+ }
+
+ /* Connect renderer to media_port */
+ status = pjmedia_vid_port_connect(g_vid_renderer, media_port,
+ PJ_FALSE);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to connect renderer to stream",
+ status);
+ return;
+ }
+ }
+
+ /* Create capturer */
+ if (vstream_info.dir & PJMEDIA_DIR_ENCODING) {
+ status = pjmedia_vid_dev_default_param(
+ inv->pool, PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
+ &vport_param.vidparam);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to get default param of video "
+ "capture device", status);
+ return;
+ }
+
+ /* Get video stream port for decoding direction */
+ pjmedia_vid_stream_get_port(g_med_vstream, PJMEDIA_DIR_ENCODING,
+ &media_port);
+
+ /* Get capturer format from stream info */
+ pjmedia_format_copy(&vport_param.vidparam.fmt,
+ &media_port->info.fmt);
+ vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
+ vport_param.active = PJ_TRUE;
+
+ /* Create capturer */
+ status = pjmedia_vid_port_create(inv->pool, &vport_param,
+ &g_vid_capturer);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to create video capture device",
+ status);
+ return;
+ }
+
+ /* Connect capturer to media_port */
+ status = pjmedia_vid_port_connect(g_vid_capturer, media_port,
+ PJ_FALSE);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to connect capturer to stream",
+ status);
+ return;
+ }
+ }
+
+ /* Start streaming */
+ if (g_vid_renderer) {
+ status = pjmedia_vid_port_start(g_vid_renderer);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to start video renderer",
+ status);
+ return;
+ }
+ }
+ if (g_vid_capturer) {
+ status = pjmedia_vid_port_start(g_vid_capturer);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to start video capturer",
+ status);
+ return;
+ }
+ }
+ }
+#endif /* PJMEDIA_HAS_VIDEO */
/* Done with media. */
}
diff --git a/pjsip-apps/src/samples/stereotest.c b/pjsip-apps/src/samples/stereotest.c
index f2422d22..ab552f9e 100644
--- a/pjsip-apps/src/samples/stereotest.c
+++ b/pjsip-apps/src/samples/stereotest.c
@@ -189,11 +189,11 @@ int main(int argc, char *argv[])
status = pjmedia_snd_port_create_player(
pool, /* pool */
dev_id, /* device id. */
- file_port->info.clock_rate, /* clock rate. */
+ PJMEDIA_PIA_SRATE(&file_port->info),/* clock rate. */
snd_ch_cnt, /* # of channels. */
snd_ch_cnt * PTIME * /* samples per frame. */
- file_port->info.clock_rate / 1000,
- file_port->info.bits_per_sample, /* bits per sample. */
+ PJMEDIA_PIA_SRATE(&file_port->info) / 1000,
+ PJMEDIA_PIA_BITS(&file_port->info),/* bits per sample. */
0, /* options */
&snd_port /* returned port */
);
@@ -202,7 +202,7 @@ int main(int argc, char *argv[])
return 1;
}
- if (snd_ch_cnt != file_port->info.channel_count) {
+ if (snd_ch_cnt != PJMEDIA_PIA_CCNT(&file_port->info)) {
status = pjmedia_stereo_port_create( pool,
file_port,
snd_ch_cnt,
@@ -289,9 +289,9 @@ int main(int argc, char *argv[])
pj_thread_sleep(100);
printf("Mode = %s\n", (mode == MODE_PLAY? "playing" : "recording") );
- printf("File port channel count = %d\n", file_port->info.channel_count);
+ printf("File port channel count = %d\n", PJMEDIA_PIA_CCNT(&file_port->info));
printf("Sound port channel count = %d\n",
- pjmedia_snd_port_get_port(snd_port)->info.channel_count);
+ PJMEDIA_PIA_CCNT(&pjmedia_snd_port_get_port(snd_port)->info));
puts("");
puts("Press <ENTER> to stop and quit");
diff --git a/pjsip-apps/src/samples/streamutil.c b/pjsip-apps/src/samples/streamutil.c
index 7237b7b8..7037a94e 100644
--- a/pjsip-apps/src/samples/streamutil.c
+++ b/pjsip-apps/src/samples/streamutil.c
@@ -100,37 +100,7 @@ int hex_string_to_octet_string(char *raw, char *hex, int len);
*/
static pj_status_t init_codecs(pjmedia_endpt *med_endpt)
{
- pj_status_t status;
-
- /* To suppress warning about unused var when all codecs are disabled */
- PJ_UNUSED_ARG(status);
-
-#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
- status = pjmedia_codec_g711_init(med_endpt);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-#endif
-
-#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC!=0
- status = pjmedia_codec_gsm_init(med_endpt);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-#endif
-
-#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
- status = pjmedia_codec_speex_init(med_endpt, 0, -1, -1);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-#endif
-
-#if defined(PJMEDIA_HAS_G722_CODEC) && PJMEDIA_HAS_G722_CODEC!=0
- status = pjmedia_codec_g722_init(med_endpt);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-#endif
-
-#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC!=0
- status = pjmedia_codec_l16_init(med_endpt, 0);
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
-#endif
-
- return PJ_SUCCESS;
+ return pjmedia_codec_register_audio_codecs(med_endpt, NULL);
}
@@ -505,8 +475,7 @@ int main(int argc, char *argv[])
if (play_file) {
unsigned wav_ptime;
- wav_ptime = stream_port->info.samples_per_frame * 1000 /
- stream_port->info.clock_rate;
+ wav_ptime = PJMEDIA_PIA_PTIME(&stream_port->info);
status = pjmedia_wav_player_port_create(pool, play_file, wav_ptime,
0, -1, &play_file_port);
if (status != PJ_SUCCESS) {
@@ -532,10 +501,10 @@ int main(int argc, char *argv[])
} else if (rec_file) {
status = pjmedia_wav_writer_port_create(pool, rec_file,
- stream_port->info.clock_rate,
- stream_port->info.channel_count,
- stream_port->info.samples_per_frame,
- stream_port->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&stream_port->info),
+ PJMEDIA_PIA_CCNT(&stream_port->info),
+ PJMEDIA_PIA_SPF(&stream_port->info),
+ PJMEDIA_PIA_BITS(&stream_port->info),
0, 0, &rec_file_port);
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Unable to use file", status);
@@ -562,24 +531,24 @@ int main(int argc, char *argv[])
/* Create sound device port. */
if (dir == PJMEDIA_DIR_ENCODING_DECODING)
status = pjmedia_snd_port_create(pool, -1, -1,
- stream_port->info.clock_rate,
- stream_port->info.channel_count,
- stream_port->info.samples_per_frame,
- stream_port->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&stream_port->info),
+ PJMEDIA_PIA_CCNT(&stream_port->info),
+ PJMEDIA_PIA_SPF(&stream_port->info),
+ PJMEDIA_PIA_BITS(&stream_port->info),
0, &snd_port);
else if (dir == PJMEDIA_DIR_ENCODING)
status = pjmedia_snd_port_create_rec(pool, -1,
- stream_port->info.clock_rate,
- stream_port->info.channel_count,
- stream_port->info.samples_per_frame,
- stream_port->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&stream_port->info),
+ PJMEDIA_PIA_CCNT(&stream_port->info),
+ PJMEDIA_PIA_SPF(&stream_port->info),
+ PJMEDIA_PIA_BITS(&stream_port->info),
0, &snd_port);
else
status = pjmedia_snd_port_create_player(pool, -1,
- stream_port->info.clock_rate,
- stream_port->info.channel_count,
- stream_port->info.samples_per_frame,
- stream_port->info.bits_per_sample,
+ PJMEDIA_PIA_SRATE(&stream_port->info),
+ PJMEDIA_PIA_CCNT(&stream_port->info),
+ PJMEDIA_PIA_SPF(&stream_port->info),
+ PJMEDIA_PIA_BITS(&stream_port->info),
0, &snd_port);
@@ -757,11 +726,9 @@ static void print_stream_stat(pjmedia_stream *stream,
now.msec);
- printf(" Info: audio %.*s@%dHz, %dms/frame, %sB/s (%sB/s +IP hdr)\n",
- (int)port->info.encoding_name.slen,
- port->info.encoding_name.ptr,
- port->info.clock_rate,
- port->info.samples_per_frame * 1000 / port->info.clock_rate,
+ printf(" Info: audio %dHz, %dms/frame, %sB/s (%sB/s +IP hdr)\n",
+ PJMEDIA_PIA_SRATE(&port->info),
+ PJMEDIA_PIA_PTIME(&port->info),
good_number(bps, (codec_param->info.avg_bps+7)/8),
good_number(ipbps, ((codec_param->info.avg_bps+7)/8) +
(40 * 1000 /
@@ -900,14 +867,14 @@ static void print_stream_stat(pjmedia_stream *stream,
unsigned jmin, jmax, jmean, jdev;
SAMPLES_TO_USEC(jmin, xr_stat.rx.stat_sum.jitter.min,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jmax, xr_stat.rx.stat_sum.jitter.max,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jmean, xr_stat.rx.stat_sum.jitter.mean,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jdev,
pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.jitter),
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",
jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);
} else
@@ -963,14 +930,14 @@ static void print_stream_stat(pjmedia_stream *stream,
unsigned jmin, jmax, jmean, jdev;
SAMPLES_TO_USEC(jmin, xr_stat.tx.stat_sum.jitter.min,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jmax, xr_stat.tx.stat_sum.jitter.max,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jmean, xr_stat.tx.stat_sum.jitter.mean,
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
SAMPLES_TO_USEC(jdev,
pj_math_stat_get_stddev(&xr_stat.tx.stat_sum.jitter),
- port->info.clock_rate);
+ port->info.fmt.det.aud.clock_rate);
sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",
jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);
} else
diff --git a/pjsip-apps/src/samples/vid_streamutil.c b/pjsip-apps/src/samples/vid_streamutil.c
new file mode 100644
index 00000000..4d50b387
--- /dev/null
+++ b/pjsip-apps/src/samples/vid_streamutil.c
@@ -0,0 +1,929 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/**
+ * \page page_pjmedia_samples_vid_streamutil_c Samples: Video Streaming
+ *
+ * This example mainly demonstrates how to stream video to remote
+ * peer using RTP.
+ *
+ * This file is pjsip-apps/src/samples/vid_streamutil.c
+ *
+ * \includelineno vid_streamutil.c
+ */
+
+#include <pjlib.h>
+#include <pjlib-util.h>
+#include <pjmedia.h>
+#include <pjmedia-codec.h>
+#include <pjmedia/transport_srtp.h>
+
+#include <stdlib.h> /* atoi() */
+#include <stdio.h>
+
+#include "util.h"
+
+
+static const char *desc =
+ " vid_streamutil \n"
+ "\n"
+ " PURPOSE: \n"
+ " Demonstrate how to use pjmedia video stream component to \n"
+ " transmit/receive RTP packets to/from video device/file. \n"
+ "\n"
+ "\n"
+ " USAGE: \n"
+ " vid_streamutil [options] \n"
+ "\n"
+ "\n"
+ " Options: \n"
+ " --codec=CODEC Set the codec name. \n"
+ " --local-port=PORT Set local RTP port (default=4000) \n"
+ " --remote=IP:PORT Set the remote peer. If this option is set, \n"
+ " the program will transmit RTP audio to the \n"
+ " specified address. (default: recv only) \n"
+ " --play-file=AVI Send video from the AVI file instead of from \n"
+ " the video device. \n"
+ " --send-recv Set stream direction to bidirectional. \n"
+ " --send-only Set stream direction to send only \n"
+ " --recv-only Set stream direction to recv only (default) \n"
+
+ " --send-width Video width to be sent \n"
+ " --send-height Video height to be sent \n"
+ " --send-width and --send-height not applicable \n"
+ " for file streaming (see --play-file) \n"
+
+ " --send-pt Payload type for sending \n"
+ " --recv-pt Payload type for receiving \n"
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ " --use-srtp[=NAME] Enable SRTP with crypto suite NAME \n"
+ " e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
+ " AES_CM_128_HMAC_SHA1_32 \n"
+ " Use this option along with the TX & RX keys, \n"
+ " formated of 60 hex digits (e.g: E148DA..) \n"
+ " --srtp-tx-key SRTP key for transmiting \n"
+ " --srtp-rx-key SRTP key for receiving \n"
+#endif
+
+ "\n"
+;
+
+#define THIS_FILE "vid_streamutil.c"
+
+
+/* If set, local renderer will be created to play original file */
+#define HAS_LOCAL_RENDERER_FOR_PLAY_FILE 1
+
+
+/* Default width and height for the renderer, better be set to maximum
+ * acceptable size.
+ */
+#define DEF_RENDERER_WIDTH 640
+#define DEF_RENDERER_HEIGHT 480
+
+
+/* Prototype */
+static void print_stream_stat(pjmedia_vid_stream *stream,
+ const pjmedia_vid_codec_param *codec_param);
+
+/* Prototype for LIBSRTP utility in file datatypes.c */
+int hex_string_to_octet_string(char *raw, char *hex, int len);
+
+/*
+ * Register all codecs.
+ */
+static pj_status_t init_codecs(pj_pool_factory *pf)
+{
+ pj_status_t status;
+
+ /* To suppress warning about unused var when all codecs are disabled */
+ PJ_UNUSED_ARG(status);
+
+#if defined(PJMEDIA_HAS_FFMPEG_CODEC) && PJMEDIA_HAS_FFMPEG_CODEC != 0
+ status = pjmedia_codec_ffmpeg_init(NULL, pf);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+#endif
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Register all codecs.
+ */
+static void deinit_codecs()
+{
+#if defined(PJMEDIA_HAS_FFMPEG_CODEC) && PJMEDIA_HAS_FFMPEG_CODEC != 0
+ pjmedia_codec_ffmpeg_deinit();
+#endif
+}
+
+static pj_status_t create_file_player( pj_pool_t *pool,
+ const char *file_name,
+ pjmedia_port **p_play_port)
+{
+ pjmedia_avi_streams *avi_streams;
+ pjmedia_avi_stream *vid_stream;
+ pjmedia_port *play_port;
+ pj_status_t status;
+
+ status = pjmedia_avi_player_create_streams(pool, file_name, 0, &avi_streams);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ vid_stream = pjmedia_avi_streams_get_stream_by_media(avi_streams,
+ 0,
+ PJMEDIA_TYPE_VIDEO);
+ if (!vid_stream)
+ return PJ_ENOTFOUND;
+
+ play_port = pjmedia_avi_stream_get_port(vid_stream);
+ pj_assert(play_port);
+
+ *p_play_port = play_port;
+
+ return PJ_SUCCESS;
+}
+
+/*
+ * Create stream based on the codec, dir, remote address, etc.
+ */
+static pj_status_t create_stream( pj_pool_t *pool,
+ pjmedia_endpt *med_endpt,
+ const pjmedia_vid_codec_info *codec_info,
+ pjmedia_vid_codec_param *codec_param,
+ pjmedia_dir dir,
+ pj_int8_t rx_pt,
+ pj_int8_t tx_pt,
+ pj_uint16_t local_port,
+ const pj_sockaddr_in *rem_addr,
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ pj_bool_t use_srtp,
+ const pj_str_t *crypto_suite,
+ const pj_str_t *srtp_tx_key,
+ const pj_str_t *srtp_rx_key,
+#endif
+ pjmedia_vid_stream **p_stream )
+{
+ pjmedia_vid_stream_info info;
+ pjmedia_transport *transport = NULL;
+ pj_status_t status;
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ pjmedia_transport *srtp_tp = NULL;
+#endif
+
+ /* Reset stream info. */
+ pj_bzero(&info, sizeof(info));
+
+ /* Initialize stream info formats */
+ info.type = PJMEDIA_TYPE_VIDEO;
+ info.dir = dir;
+ info.codec_info = *codec_info;
+ info.tx_pt = (tx_pt == -1)? codec_info->pt : tx_pt;
+ info.rx_pt = (rx_pt == -1)? codec_info->pt : rx_pt;
+ info.ssrc = pj_rand();
+ if (codec_param)
+ info.codec_param = codec_param;
+
+ /* Copy remote address */
+ pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
+
+ /* If remote address is not set, set to an arbitrary address
+ * (otherwise stream will assert).
+ */
+ if (info.rem_addr.addr.sa_family == 0) {
+ const pj_str_t addr = pj_str("127.0.0.1");
+ pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
+ }
+
+ /* Create media transport */
+ status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
+ 0, &transport);
+ if (status != PJ_SUCCESS)
+ return status;
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ /* Check if SRTP enabled */
+ if (use_srtp) {
+ pjmedia_srtp_crypto tx_plc, rx_plc;
+
+ status = pjmedia_transport_srtp_create(med_endpt, transport,
+ NULL, &srtp_tp);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
+ pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
+
+ tx_plc.key = *srtp_tx_key;
+ tx_plc.name = *crypto_suite;
+ rx_plc.key = *srtp_rx_key;
+ rx_plc.name = *crypto_suite;
+
+ status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ transport = srtp_tp;
+ }
+#endif
+
+ /* Now that the stream info is initialized, we can create the
+ * stream.
+ */
+
+ status = pjmedia_vid_stream_create( med_endpt, pool, &info,
+ transport,
+ NULL, p_stream);
+
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Error creating stream", status);
+ pjmedia_transport_close(transport);
+ return status;
+ }
+
+
+ return PJ_SUCCESS;
+}
+
+
+typedef struct play_file_data
+{
+ const char *file_name;
+ pjmedia_port *play_port;
+ pjmedia_port *stream_port;
+ pjmedia_vid_codec *decoder;
+ pjmedia_port *renderer;
+ void *read_buf;
+ pj_size_t read_buf_size;
+ void *dec_buf;
+ pj_size_t dec_buf_size;
+} play_file_data;
+
+
+static void clock_cb(const pj_timestamp *ts, void *user_data)
+{
+ play_file_data *play_file = (play_file_data*)user_data;
+ pjmedia_frame read_frame, write_frame;
+ pj_status_t status;
+
+ PJ_UNUSED_ARG(ts);
+
+ /* Read frame from file */
+ read_frame.buf = play_file->read_buf;
+ read_frame.size = play_file->read_buf_size;
+ pjmedia_port_get_frame(play_file->play_port, &read_frame);
+
+ /* Decode frame, if needed */
+ if (play_file->decoder) {
+ pjmedia_vid_codec *decoder = play_file->decoder;
+
+ write_frame.buf = play_file->dec_buf;
+ write_frame.size = play_file->dec_buf_size;
+ status = decoder->op->decode(decoder, &read_frame, write_frame.size,
+ &write_frame);
+ if (status != PJ_SUCCESS)
+ return;
+ } else {
+ write_frame = read_frame;
+ }
+
+ /* Display frame locally */
+ if (play_file->renderer)
+ pjmedia_port_put_frame(play_file->renderer, &write_frame);
+
+ /* Send frame */
+ pjmedia_port_put_frame(play_file->stream_port, &write_frame);
+}
+
+
+/*
+ * usage()
+ */
+static void usage()
+{
+ puts(desc);
+}
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+ pj_caching_pool cp;
+ pjmedia_endpt *med_endpt;
+ pj_pool_t *pool;
+ pjmedia_vid_stream *stream = NULL;
+ pjmedia_port *enc_port, *dec_port;
+ pj_status_t status;
+
+ pjmedia_vid_port *capture=NULL, *renderer=NULL;
+ pjmedia_vid_port_param vpp;
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ /* SRTP variables */
+ pj_bool_t use_srtp = PJ_FALSE;
+ char tmp_tx_key[64];
+ char tmp_rx_key[64];
+ pj_str_t srtp_tx_key = {NULL, 0};
+ pj_str_t srtp_rx_key = {NULL, 0};
+ pj_str_t srtp_crypto_suite = {NULL, 0};
+ int tmp_key_len;
+#endif
+
+ /* Default values */
+ const pjmedia_vid_codec_info *codec_info;
+ pjmedia_vid_codec_param codec_param;
+ pjmedia_dir dir = PJMEDIA_DIR_DECODING;
+ pj_sockaddr_in remote_addr;
+ pj_uint16_t local_port = 4000;
+ char *codec_id = NULL;
+ pjmedia_rect_size tx_size = {0};
+ pj_int8_t rx_pt = -1, tx_pt = -1;
+
+ play_file_data play_file = { NULL };
+ pjmedia_port *play_port = NULL;
+ pjmedia_vid_codec *play_decoder = NULL;
+ pjmedia_clock *play_clock = NULL;
+
+ enum {
+ OPT_CODEC = 'c',
+ OPT_LOCAL_PORT = 'p',
+ OPT_REMOTE = 'r',
+ OPT_PLAY_FILE = 'f',
+ OPT_SEND_RECV = 'b',
+ OPT_SEND_ONLY = 's',
+ OPT_RECV_ONLY = 'i',
+ OPT_SEND_WIDTH = 'W',
+ OPT_SEND_HEIGHT = 'H',
+ OPT_RECV_PT = 't',
+ OPT_SEND_PT = 'T',
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ OPT_USE_SRTP = 'S',
+#endif
+ OPT_SRTP_TX_KEY = 'x',
+ OPT_SRTP_RX_KEY = 'y',
+ OPT_HELP = 'h',
+ };
+
+ struct pj_getopt_option long_options[] = {
+ { "codec", 1, 0, OPT_CODEC },
+ { "local-port", 1, 0, OPT_LOCAL_PORT },
+ { "remote", 1, 0, OPT_REMOTE },
+ { "play-file", 1, 0, OPT_PLAY_FILE },
+ { "send-recv", 0, 0, OPT_SEND_RECV },
+ { "send-only", 0, 0, OPT_SEND_ONLY },
+ { "recv-only", 0, 0, OPT_RECV_ONLY },
+ { "send-width", 1, 0, OPT_SEND_WIDTH },
+ { "send-height", 1, 0, OPT_SEND_HEIGHT },
+ { "recv-pt", 1, 0, OPT_RECV_PT },
+ { "send-pt", 1, 0, OPT_SEND_PT },
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ { "use-srtp", 2, 0, OPT_USE_SRTP },
+ { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
+ { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
+#endif
+ { "help", 0, 0, OPT_HELP },
+ { NULL, 0, 0, 0 },
+ };
+
+ int c;
+ int option_index;
+
+
+ pj_bzero(&remote_addr, sizeof(remote_addr));
+
+
+ /* init PJLIB : */
+ status = pj_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+
+ /* Parse arguments */
+ pj_optind = 0;
+ while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1)
+ {
+ switch (c) {
+ case OPT_CODEC:
+ codec_id = pj_optarg;
+ break;
+
+ case OPT_LOCAL_PORT:
+ local_port = (pj_uint16_t) atoi(pj_optarg);
+ if (local_port < 1) {
+ printf("Error: invalid local port %s\n", pj_optarg);
+ return 1;
+ }
+ break;
+
+ case OPT_REMOTE:
+ {
+ pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
+ pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
+
+ status = pj_sockaddr_in_init(&remote_addr, &ip, port);
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Invalid remote address", status);
+ return 1;
+ }
+ }
+ break;
+
+ case OPT_PLAY_FILE:
+ play_file.file_name = pj_optarg;
+ break;
+
+ case OPT_SEND_RECV:
+ dir = PJMEDIA_DIR_ENCODING_DECODING;
+ break;
+
+ case OPT_SEND_ONLY:
+ dir = PJMEDIA_DIR_ENCODING;
+ break;
+
+ case OPT_RECV_ONLY:
+ dir = PJMEDIA_DIR_DECODING;
+ break;
+
+ case OPT_SEND_WIDTH:
+ tx_size.w = (unsigned)atoi(pj_optarg);
+ break;
+
+ case OPT_SEND_HEIGHT:
+ tx_size.h = (unsigned)atoi(pj_optarg);
+ break;
+
+ case OPT_RECV_PT:
+ rx_pt = (pj_int8_t)atoi(pj_optarg);
+ break;
+
+ case OPT_SEND_PT:
+ tx_pt = (pj_int8_t)atoi(pj_optarg);
+ break;
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ case OPT_USE_SRTP:
+ use_srtp = PJ_TRUE;
+ if (pj_optarg) {
+ pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
+ } else {
+ srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
+ }
+ break;
+
+ case OPT_SRTP_TX_KEY:
+ tmp_key_len = hex_string_to_octet_string(tmp_tx_key, pj_optarg,
+ strlen(pj_optarg));
+ pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
+ break;
+
+ case OPT_SRTP_RX_KEY:
+ tmp_key_len = hex_string_to_octet_string(tmp_rx_key, pj_optarg,
+ strlen(pj_optarg));
+ pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
+ break;
+#endif
+
+ case OPT_HELP:
+ usage();
+ return 1;
+
+ default:
+ printf("Invalid options %s\n", argv[pj_optind]);
+ return 1;
+ }
+
+ }
+
+
+ /* Verify arguments. */
+ if (dir & PJMEDIA_DIR_ENCODING) {
+ if (remote_addr.sin_addr.s_addr == 0) {
+ printf("Error: remote address must be set\n");
+ return 1;
+ }
+ }
+
+ if (play_file.file_name != NULL && dir != PJMEDIA_DIR_ENCODING) {
+ printf("Direction is set to --send-only because of --play-file\n");
+ dir = PJMEDIA_DIR_ENCODING;
+ }
+
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ /* SRTP validation */
+ if (use_srtp) {
+ if (!srtp_tx_key.slen || !srtp_rx_key.slen)
+ {
+ printf("Error: Key for each SRTP stream direction must be set\n");
+ return 1;
+ }
+ }
+#endif
+
+ /* Must create a pool factory before we can allocate any memory. */
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+ /*
+ * Initialize media endpoint.
+ * This will implicitly initialize PJMEDIA too.
+ */
+ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Create memory pool for application purpose */
+ pool = pj_pool_create( &cp.factory, /* pool factory */
+ "app", /* pool name. */
+ 4000, /* init size */
+ 4000, /* increment size */
+ NULL /* callback on error */
+ );
+
+ /* Init video format manager */
+ pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
+
+ /* Init video converter manager */
+ pjmedia_converter_mgr_create(pool, NULL);
+
+ /* Init video codec manager */
+ pjmedia_vid_codec_mgr_create(pool, NULL);
+
+ /* Init video subsystem */
+ pjmedia_vid_dev_subsys_init(&cp.factory);
+
+ /* Register all supported codecs */
+ status = init_codecs(&cp.factory);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+
+ /* Find which codec to use. */
+ if (codec_id) {
+ unsigned count = 1;
+ pj_str_t str_codec_id = pj_str(codec_id);
+
+ status = pjmedia_vid_codec_mgr_find_codecs_by_id(NULL,
+ &str_codec_id, &count,
+ &codec_info, NULL);
+ if (status != PJ_SUCCESS) {
+ printf("Error: unable to find codec %s\n", codec_id);
+ return 1;
+ }
+ } else {
+ static pjmedia_vid_codec_info info[1];
+ unsigned count = PJ_ARRAY_SIZE(info);
+
+ /* Default to first codec */
+ pjmedia_vid_codec_mgr_enum_codecs(NULL, &count, info, NULL);
+ codec_info = &info[0];
+ }
+
+ /* Get codec default param for info */
+ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info,
+ &codec_param);
+ pj_assert(status == PJ_SUCCESS);
+
+ /* Set outgoing video size */
+ if (tx_size.w && tx_size.h)
+ codec_param.enc_fmt.det.vid.size = tx_size;
+
+#if DEF_RENDERER_WIDTH && DEF_RENDERER_HEIGHT
+ /* Set incoming video size */
+ codec_param.dec_fmt.det.vid.size.w = DEF_RENDERER_WIDTH;
+ codec_param.dec_fmt.det.vid.size.h = DEF_RENDERER_HEIGHT;
+#endif
+
+ if (play_file.file_name) {
+ pjmedia_video_format_detail *file_vfd;
+ pjmedia_clock_param clock_param;
+
+ /* Create file player */
+ status = create_file_player(pool, play_file.file_name, &play_port);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Collect format info */
+ file_vfd = pjmedia_format_get_video_format_detail(&play_port->info.fmt,
+ PJ_TRUE);
+ PJ_LOG(2, (THIS_FILE, "Reading video stream %dx%d %c%c%c%c @%.2ffps",
+ file_vfd->size.w, file_vfd->size.h,
+ ((play_port->info.fmt.id & 0x000000FF) >> 0),
+ ((play_port->info.fmt.id & 0x0000FF00) >> 8),
+ ((play_port->info.fmt.id & 0x00FF0000) >> 16),
+ ((play_port->info.fmt.id & 0xFF000000) >> 24),
+ (1.0*file_vfd->fps.num/file_vfd->fps.denum)));
+
+ /* Allocate file read buffer */
+ play_file.read_buf_size = PJMEDIA_MAX_VIDEO_ENC_FRAME_SIZE;
+ play_file.read_buf = pj_pool_zalloc(pool, play_file.read_buf_size);
+
+ /* Create decoder, if the file and the stream uses different codec */
+ if (codec_info->fmt_id != (pjmedia_format_id)play_port->info.fmt.id) {
+ const pjmedia_video_format_info *dec_vfi;
+ pjmedia_video_apply_fmt_param dec_vafp = {0};
+ const pjmedia_vid_codec_info *codec_info2;
+ pjmedia_vid_codec_param codec_param2;
+
+ /* Find decoder */
+ status = pjmedia_vid_codec_mgr_get_codec_info2(NULL,
+ play_port->info.fmt.id,
+ &codec_info2);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Init decoder */
+ status = pjmedia_vid_codec_mgr_alloc_codec(NULL, codec_info2,
+ &play_decoder);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ status = play_decoder->op->init(play_decoder, pool);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Open decoder */
+ status = pjmedia_vid_codec_mgr_get_default_param(NULL, codec_info2,
+ &codec_param2);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ codec_param2.dir = PJMEDIA_DIR_DECODING;
+ status = play_decoder->op->open(play_decoder, &codec_param2);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Get decoder format info and apply param */
+ dec_vfi = pjmedia_get_video_format_info(NULL,
+ codec_info2->dec_fmt_id[0]);
+ if (!dec_vfi || !dec_vfi->apply_fmt) {
+ status = PJ_ENOTSUP;
+ goto on_exit;
+ }
+ dec_vafp.size = file_vfd->size;
+ (*dec_vfi->apply_fmt)(dec_vfi, &dec_vafp);
+
+ /* Allocate buffer to receive decoder output */
+ play_file.dec_buf_size = dec_vafp.framebytes;
+ play_file.dec_buf = pj_pool_zalloc(pool, play_file.dec_buf_size);
+ }
+
+ /* Create player clock */
+ clock_param.usec_interval = PJMEDIA_PTIME(&file_vfd->fps);
+ clock_param.clock_rate = codec_info->clock_rate;
+ status = pjmedia_clock_create2(pool, &clock_param,
+ PJMEDIA_CLOCK_NO_HIGHEST_PRIO,
+ &clock_cb, &play_file, &play_clock);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Override stream codec param for encoding direction */
+ codec_param.enc_fmt.det.vid.size = file_vfd->size;
+ codec_param.enc_fmt.det.vid.fps = file_vfd->fps;
+
+ } else {
+ pjmedia_vid_port_param_default(&vpp);
+
+ /* Set as active for all video devices */
+ vpp.active = PJ_TRUE;
+
+ /* Create video device port. */
+ if (dir & PJMEDIA_DIR_ENCODING) {
+ /* Create capture */
+ status = pjmedia_vid_dev_default_param(
+ pool,
+ 0,//PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
+ &vpp.vidparam);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.enc_fmt);
+ vpp.vidparam.fmt.id = codec_param.dec_fmt.id;
+ vpp.vidparam.dir = PJMEDIA_DIR_CAPTURE;
+
+ status = pjmedia_vid_port_create(pool, &vpp, &capture);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ }
+
+ if (dir & PJMEDIA_DIR_DECODING) {
+ /* Create renderer */
+ status = pjmedia_vid_dev_default_param(
+ pool,
+ 1,//PJMEDIA_VID_DEFAULT_RENDER_DEV,
+ &vpp.vidparam);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
+ vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
+ vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
+
+ status = pjmedia_vid_port_create(pool, &vpp, &renderer);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ }
+ }
+
+ /* Create stream based on program arguments */
+ status = create_stream(pool, med_endpt, codec_info, &codec_param,
+ dir, rx_pt, tx_pt, local_port, &remote_addr,
+#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
+ use_srtp, &srtp_crypto_suite,
+ &srtp_tx_key, &srtp_rx_key,
+#endif
+ &stream);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Get the port interface of the stream */
+ status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_ENCODING,
+ &enc_port);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ status = pjmedia_vid_stream_get_port(stream, PJMEDIA_DIR_DECODING,
+ &dec_port);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Start streaming */
+ status = pjmedia_vid_stream_start(stream);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ /* Start renderer */
+ if (renderer) {
+ status = pjmedia_vid_port_connect(renderer, dec_port, PJ_FALSE);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ }
+
+ /* Start capture */
+ if (capture) {
+ status = pjmedia_vid_port_connect(capture, enc_port, PJ_FALSE);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ status = pjmedia_vid_port_start(capture);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ }
+
+ /* Start playing file */
+ if (play_file.file_name) {
+
+#if HAS_LOCAL_RENDERER_FOR_PLAY_FILE
+ /* Create local renderer */
+ pjmedia_vid_port_param_default(&vpp);
+ vpp.active = PJ_FALSE;
+ status = pjmedia_vid_dev_default_param(
+ pool,
+ 1,//PJMEDIA_VID_DEFAULT_RENDER_DEV,
+ &vpp.vidparam);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+
+ vpp.vidparam.dir = PJMEDIA_DIR_RENDER;
+ pjmedia_format_copy(&vpp.vidparam.fmt, &codec_param.dec_fmt);
+ vpp.vidparam.fmt.det.vid.size = play_port->info.fmt.det.vid.size;
+ vpp.vidparam.fmt.det.vid.fps = play_port->info.fmt.det.vid.fps;
+ vpp.vidparam.disp_size = vpp.vidparam.fmt.det.vid.size;
+
+ status = pjmedia_vid_port_create(pool, &vpp, &renderer);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ status = pjmedia_vid_port_start(renderer);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+#endif
+
+ /* Init play file data */
+ play_file.play_port = play_port;
+ play_file.stream_port = enc_port;
+ play_file.decoder = play_decoder;
+ if (renderer) {
+ play_file.renderer = pjmedia_vid_port_get_passive_port(renderer);
+ }
+
+ status = pjmedia_clock_start(play_clock);
+ if (status != PJ_SUCCESS)
+ goto on_exit;
+ }
+
+ /* Done */
+
+ if (dir == PJMEDIA_DIR_DECODING)
+ printf("Stream is active, dir is recv-only, local port is %d\n",
+ local_port);
+ else if (dir == PJMEDIA_DIR_ENCODING)
+ printf("Stream is active, dir is send-only, sending to %s:%d\n",
+ pj_inet_ntoa(remote_addr.sin_addr),
+ pj_ntohs(remote_addr.sin_port));
+ else
+ printf("Stream is active, send/recv, local port is %d, "
+ "sending to %s:%d\n",
+ local_port,
+ pj_inet_ntoa(remote_addr.sin_addr),
+ pj_ntohs(remote_addr.sin_port));
+
+ if (dir & PJMEDIA_DIR_ENCODING)
+ PJ_LOG(2, (THIS_FILE, "Sending %dx%d %.*s @%.2ffps",
+ codec_param.enc_fmt.det.vid.size.w,
+ codec_param.enc_fmt.det.vid.size.h,
+ codec_info->encoding_name.slen,
+ codec_info->encoding_name.ptr,
+ (1.0*codec_param.enc_fmt.det.vid.fps.num/
+ codec_param.enc_fmt.det.vid.fps.denum)));
+
+ for (;;) {
+ char tmp[10];
+
+ puts("");
+ puts("Commands:");
+ puts(" q Quit");
+ puts("");
+
+ printf("Command: "); fflush(stdout);
+
+ if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
+ puts("EOF while reading stdin, will quit now..");
+ break;
+ }
+
+ if (tmp[0] == 'q')
+ break;
+
+ }
+
+
+
+ /* Start deinitialization: */
+on_exit:
+
+ /* Stop and destroy file clock */
+ if (play_clock) {
+ pjmedia_clock_stop(play_clock);
+ pjmedia_clock_destroy(play_clock);
+ }
+
+ /* Destroy file reader/player */
+ if (play_port)
+ pjmedia_port_destroy(play_port);
+
+ /* Destroy file decoder */
+ if (play_decoder) {
+ play_decoder->op->close(play_decoder);
+ pjmedia_vid_codec_mgr_dealloc_codec(NULL, play_decoder);
+ }
+
+ /* Destroy video devices */
+ if (capture)
+ pjmedia_vid_port_destroy(capture);
+ if (renderer)
+ pjmedia_vid_port_destroy(renderer);
+
+ /* Destroy stream */
+ if (stream) {
+ pjmedia_transport *tp;
+
+ tp = pjmedia_vid_stream_get_transport(stream);
+ pjmedia_vid_stream_destroy(stream);
+
+ pjmedia_transport_close(tp);
+ }
+
+ /* Deinit codecs */
+ deinit_codecs();
+
+ /* Shutdown video subsystem */
+ pjmedia_vid_dev_subsys_shutdown();
+
+ /* Release application pool */
+ pj_pool_release( pool );
+
+ /* Destroy media endpoint. */
+ pjmedia_endpt_destroy( med_endpt );
+
+ /* Destroy pool factory */
+ pj_caching_pool_destroy( &cp );
+
+ /* Shutdown PJLIB */
+ pj_shutdown();
+
+ return (status == PJ_SUCCESS) ? 0 : 1;
+}