summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pjmedia/build/pjmedia.dsp12
-rw-r--r--pjmedia/include/pjmedia.h2
-rw-r--r--pjmedia/include/pjmedia/conference.h23
-rw-r--r--pjmedia/include/pjmedia/errno.h19
-rw-r--r--pjmedia/include/pjmedia/file_port.h47
-rw-r--r--pjmedia/include/pjmedia/vad.h2
-rw-r--r--pjmedia/include/pjmedia/wave.h80
-rw-r--r--pjmedia/src/pjmedia/conference.c22
-rw-r--r--pjmedia/src/pjmedia/errno.c5
-rw-r--r--pjmedia/src/pjmedia/file_port.c261
-rw-r--r--pjsip/src/pjsua/main.c31
-rw-r--r--pjsip/src/pjsua/pjsua.h3
-rw-r--r--pjsip/src/pjsua/pjsua_core.c36
-rw-r--r--pjsip/src/pjsua/pjsua_opt.c9
14 files changed, 540 insertions, 12 deletions
diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp
index 97f4b5ca..963a85b8 100644
--- a/pjmedia/build/pjmedia.dsp
+++ b/pjmedia/build/pjmedia.dsp
@@ -108,6 +108,10 @@ SOURCE=..\src\pjmedia\errno.c
# End Source File
# Begin Source File
+SOURCE=..\src\pjmedia\file_port.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjmedia\g711.c
# End Source File
# Begin Source File
@@ -193,6 +197,10 @@ SOURCE=..\include\pjmedia\errno.h
# End Source File
# Begin Source File
+SOURCE=..\include\pjmedia\file_port.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjmedia\jbuf.h
# End Source File
# Begin Source File
@@ -243,6 +251,10 @@ SOURCE=..\include\pjmedia\types.h
SOURCE=..\include\pjmedia\vad.h
# End Source File
+# Begin Source File
+
+SOURCE=..\include\pjmedia\wave.h
+# End Source File
# End Group
# Begin Group "PortAudio"
diff --git a/pjmedia/include/pjmedia.h b/pjmedia/include/pjmedia.h
index 66ba4e0c..b59ca2ab 100644
--- a/pjmedia/include/pjmedia.h
+++ b/pjmedia/include/pjmedia.h
@@ -29,6 +29,7 @@
#include <pjmedia/conference.h>
#include <pjmedia/endpoint.h>
#include <pjmedia/errno.h>
+#include <pjmedia/file_port.h>
#include <pjmedia/jbuf.h>
#include <pjmedia/port.h>
#include <pjmedia/rtcp.h>
@@ -37,6 +38,7 @@
#include <pjmedia/sdp_neg.h>
#include <pjmedia/session.h>
#include <pjmedia/sound.h>
+#include <pjmedia/wave.h>
#endif /* __PJMEDIA_H__ */
diff --git a/pjmedia/include/pjmedia/conference.h b/pjmedia/include/pjmedia/conference.h
index ffa44371..775e2ff7 100644
--- a/pjmedia/include/pjmedia/conference.h
+++ b/pjmedia/include/pjmedia/conference.h
@@ -40,6 +40,7 @@ typedef struct pjmedia_conf pjmedia_conf;
*/
typedef struct pjmedia_conf_port_info
{
+ unsigned slot;
pj_str_t name;
pjmedia_port_op tx_setting;
pjmedia_port_op rx_setting;
@@ -150,12 +151,34 @@ PJ_DECL(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf,
/**
* Get port info.
+ *
+ * @param conf The conference bridge.
+ * @param slot Port index.
+ * @param info Pointer to receive the info.
+ *
+ * @return PJ_SUCCESS on success.
*/
PJ_DECL(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
unsigned slot,
pjmedia_conf_port_info *info);
+/**
+ * Get occupied ports info.
+ *
+ * @param conf The conference bridge.
+ * @param size On input, contains maximum number of infos
+ * to be retrieved. On output, contains the actual
+ * number of infos that have been copied.
+ * @param info Array of info.
+ *
+ * @return PJ_SUCCESS on success.
+ */
+PJ_DECL(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf,
+ unsigned *size,
+ pjmedia_conf_port_info info[]);
+
+
PJ_END_DECL
diff --git a/pjmedia/include/pjmedia/errno.h b/pjmedia/include/pjmedia/errno.h
index accf3fd1..354383b2 100644
--- a/pjmedia/include/pjmedia/errno.h
+++ b/pjmedia/include/pjmedia/errno.h
@@ -406,6 +406,25 @@ PJ_BEGIN_DECL
#define PJMEDIA_ENCBYTES (PJMEDIA_ERRNO_START+165) /* 220165 */
+/************************************************************
+ * FILE ERRORS
+ ***********************************************************/
+/**
+ * @hideinitializer
+ * Not a valid WAVE file.
+ */
+#define PJMEDIA_ENOTVALIDWAVE (PJMEDIA_ERRNO_START+180) /* 220180 */
+/**
+ * @hideinitializer
+ * Unsupported WAVE file.
+ */
+#define PJMEDIA_EWAVEUNSUPP (PJMEDIA_ERRNO_START+181) /* 220181 */
+/**
+ * @hideinitializer
+ * Wave file too short.
+ */
+#define PJMEDIA_EWAVETOOSHORT (PJMEDIA_ERRNO_START+182) /* 220182 */
+
PJ_END_DECL
diff --git a/pjmedia/include/pjmedia/file_port.h b/pjmedia/include/pjmedia/file_port.h
new file mode 100644
index 00000000..75482c70
--- /dev/null
+++ b/pjmedia/include/pjmedia/file_port.h
@@ -0,0 +1,47 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * 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
+ */
+#ifndef __PJMEDIA_FILE_PORT_H__
+#define __PJMEDIA_FILE_PORT_H__
+
+/**
+ * @file file_port.h
+ * @brief File player and recorder.
+ */
+#include <pjmedia/port.h>
+
+
+PJ_BEGIN_DECL
+
+
+/**
+ * Create file player port.
+ */
+PJ_DECL(pj_status_t) pjmedia_file_player_port_create( pj_pool_t *pool,
+ const char *filename,
+ unsigned flags,
+ pj_ssize_t buff_size,
+ void *user_data,
+ pjmedia_port **p_port );
+
+
+
+PJ_END_DECL
+
+
+#endif /* __PJMEDIA_FILE_PORT_H__ */
diff --git a/pjmedia/include/pjmedia/vad.h b/pjmedia/include/pjmedia/vad.h
index a7da42d2..fc7f3b2f 100644
--- a/pjmedia/include/pjmedia/vad.h
+++ b/pjmedia/include/pjmedia/vad.h
@@ -22,7 +22,7 @@
/**
* @file vad.h
- * @brief Voice Activity Detector.
+ * @brief Simple, adaptive silence detector.
*/
#include <pjmedia/types.h>
diff --git a/pjmedia/include/pjmedia/wave.h b/pjmedia/include/pjmedia/wave.h
new file mode 100644
index 00000000..b42206fa
--- /dev/null
+++ b/pjmedia/include/pjmedia/wave.h
@@ -0,0 +1,80 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * 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
+ */
+#ifndef __PJMEDIA_WAVE_H__
+#define __PJMEDIA_WAVE_H__
+
+
+/**
+ * @file wave.h
+ * @brief WAVE file manipulation.
+ */
+#include <pjmedia/types.h>
+
+
+PJ_BEGIN_DECL
+
+#if PJ_IS_BIG_ENDIAN
+# define PJMEDIA_RIFF_TAG ('R'<<24|'I'<<16|'F'<<8|'F')
+# define PJMEDIA_WAVE_TAG ('W'<<24|'A'<<16|'V'<<8|'E')
+# define PJMEDIA_FMT_TAG ('f'<<24|'m'<<16|'t'<<8|' ')
+#else
+# define PJMEDIA_RIFF_TAG ('F'<<24|'F'<<16|'I'<<8|'R')
+# define PJMEDIA_WAVE_TAG ('E'<<24|'V'<<16|'A'<<8|'W')
+# define PJMEDIA_FMT_TAG (' '<<24|'t'<<16|'m'<<8|'f')
+#endif
+
+
+/**
+ * This file describes the simpler/canonical version of a WAVE file.
+ * It does not support the full RIFF format specification.
+ */
+struct pjmedia_wave_hdr
+{
+ struct {
+ pj_uint32_t riff;
+ pj_uint32_t file_len;
+ pj_uint32_t wave;
+ } riff_hdr;
+
+ struct {
+ pj_uint32_t fmt;
+ pj_uint32_t len;
+ pj_uint16_t fmt_tag;
+ pj_uint16_t nchan;
+ pj_uint32_t sample_rate;
+ pj_uint32_t bytes_per_sec;
+ pj_uint16_t block_align;
+ pj_uint16_t bits_per_sample;
+ } fmt_hdr;
+
+ struct {
+ pj_uint32_t data;
+ pj_uint32_t len;
+ } data_hdr;
+};
+
+/**
+ * @see pjmedia_wave_hdr
+ */
+typedef struct pjmedia_wave_hdr pjmedia_wave_hdr;
+
+
+PJ_END_DECL
+
+#endif /* __PJMEDIA_WAVE_H__ */
diff --git a/pjmedia/src/pjmedia/conference.c b/pjmedia/src/pjmedia/conference.c
index 538dfa5e..8d2d28dc 100644
--- a/pjmedia/src/pjmedia/conference.c
+++ b/pjmedia/src/pjmedia/conference.c
@@ -599,6 +599,7 @@ PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
conf_port = conf->ports[slot];
+ info->slot = slot;
info->name = conf_port->name;
info->tx_setting = conf_port->tx_setting;
info->rx_setting = conf_port->rx_setting;
@@ -608,6 +609,27 @@ PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf,
}
+PJ_DEF(pj_status_t) pjmedia_conf_get_ports_info(pjmedia_conf *conf,
+ unsigned *size,
+ pjmedia_conf_port_info info[])
+{
+ unsigned i, count=0;
+
+ PJ_ASSERT_RETURN(conf && size && info, PJ_EINVAL);
+
+ for (i=0; i<conf->max_ports && count<*size; ++i) {
+ if (!conf->ports[i])
+ continue;
+
+ pjmedia_conf_get_port_info(conf, i, &info[count]);
+ ++count;
+ }
+
+ *size = count;
+ return PJ_SUCCESS;
+}
+
+
/* Convert signed 16bit pcm sample to unsigned 16bit sample */
static pj_uint16_t pcm2unsigned(pj_int32_t pcm)
{
diff --git a/pjmedia/src/pjmedia/errno.c b/pjmedia/src/pjmedia/errno.c
index 3a91deff..37d5e261 100644
--- a/pjmedia/src/pjmedia/errno.c
+++ b/pjmedia/src/pjmedia/errno.c
@@ -112,6 +112,11 @@ static const struct
{ PJMEDIA_ENCTYPE, "Media ports have incompatible media type" },
{ PJMEDIA_ENCBITS, "Media ports have incompatible bits per sample" },
{ PJMEDIA_ENCBYTES, "Media ports have incompatible bytes per frame" },
+
+ /* Media file errors: */
+ { PJMEDIA_ENOTVALIDWAVE, "Not a valid WAVE file" },
+ { PJMEDIA_EWAVEUNSUPP, "Unsupported WAVE file format" },
+ { PJMEDIA_EWAVETOOSHORT, "WAVE file too short" },
};
diff --git a/pjmedia/src/pjmedia/file_port.c b/pjmedia/src/pjmedia/file_port.c
new file mode 100644
index 00000000..1d7e9872
--- /dev/null
+++ b/pjmedia/src/pjmedia/file_port.c
@@ -0,0 +1,261 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
+ *
+ * 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/file_port.h>
+#include <pjmedia/errno.h>
+#include <pjmedia/wave.h>
+#include <pj/assert.h>
+#include <pj/file_access.h>
+#include <pj/file_io.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+#define SIGNATURE ('F'<<24|'I'<<16|'L'<<8|'E')
+#define BUF_SIZE (320*10)
+
+struct file_port
+{
+ pjmedia_port base;
+ pj_size_t bufsize;
+ char *buf;
+ char *readpos;
+};
+
+
+static pj_status_t file_put_frame(pjmedia_port *this_port,
+ const pjmedia_frame *frame);
+static pj_status_t file_get_frame(pjmedia_port *this_port,
+ pjmedia_frame *frame);
+static pj_status_t file_on_destroy(pjmedia_port *this_port);
+static pj_status_t read_buffer(struct file_port *port);
+
+static struct file_port *create_file_port(pj_pool_t *pool)
+{
+ struct file_port *port;
+
+ port = pj_pool_zalloc(pool, sizeof(struct file_port));
+ if (!port)
+ return NULL;
+
+ port->base.info.name = pj_str("file");
+ port->base.info.signature = SIGNATURE;
+ port->base.info.type = PJMEDIA_TYPE_AUDIO;
+ port->base.info.has_info = PJ_TRUE;
+ port->base.info.need_info = PJ_FALSE;
+ port->base.info.pt = 0xFF;
+ port->base.info.encoding_name = pj_str("pcm");
+ port->base.info.sample_rate = 8000;
+ port->base.info.bits_per_sample = 16;
+ port->base.info.samples_per_frame = 160;
+ port->base.info.bytes_per_frame = 320;
+
+ port->base.put_frame = &file_put_frame;
+ port->base.get_frame = &file_get_frame;
+ port->base.on_destroy = &file_on_destroy;
+
+ return port;
+}
+
+/*
+ * Create WAVE player port.
+ */
+PJ_DEF(pj_status_t) pjmedia_file_player_port_create( pj_pool_t *pool,
+ const char *filename,
+ unsigned flags,
+ pj_ssize_t buff_size,
+ void *user_data,
+ pjmedia_port **p_port )
+{
+ pj_off_t file_size;
+ pj_oshandle_t fd = NULL;
+ pjmedia_wave_hdr wave_hdr;
+ pj_ssize_t size_read;
+ struct file_port *file_port;
+ pj_status_t status;
+
+
+ PJ_UNUSED_ARG(flags);
+ PJ_UNUSED_ARG(buff_size);
+
+ /* Check arguments. */
+ PJ_ASSERT_RETURN(pool && filename && p_port, PJ_EINVAL);
+
+ /* Check the file really exists. */
+ if (!pj_file_exists(filename)) {
+ return PJ_ENOTFOUND;
+ }
+
+ /* Get the file size. */
+ file_size = pj_file_size(filename);
+
+ /* Size must be more than WAVE header size */
+ if (file_size <= sizeof(pjmedia_wave_hdr)) {
+ return PJMEDIA_ENOTVALIDWAVE;
+ }
+
+ /* Open file. */
+ status = pj_file_open( pool, filename, PJ_O_RDONLY, &fd);
+ if (status != PJ_SUCCESS)
+ return status;
+
+ /* Read the WAVE header. */
+ size_read = sizeof(wave_hdr);
+ status = pj_file_read( fd, &wave_hdr, &size_read);
+ if (status != PJ_SUCCESS) {
+ pj_file_close(fd);
+ return status;
+ }
+ if (size_read != sizeof(wave_hdr)) {
+ pj_file_close(fd);
+ return PJMEDIA_ENOTVALIDWAVE;
+ }
+
+ /* Validate WAVE file. */
+ if (wave_hdr.riff_hdr.riff != PJMEDIA_RIFF_TAG ||
+ wave_hdr.riff_hdr.wave != PJMEDIA_WAVE_TAG ||
+ wave_hdr.fmt_hdr.fmt != PJMEDIA_FMT_TAG)
+ {
+ pj_file_close(fd);
+ return PJMEDIA_ENOTVALIDWAVE;
+ }
+
+ if (wave_hdr.fmt_hdr.fmt_tag != 1 ||
+ wave_hdr.fmt_hdr.nchan != 1 ||
+ wave_hdr.fmt_hdr.sample_rate != 8000 ||
+ wave_hdr.fmt_hdr.bytes_per_sec != 16000 ||
+ wave_hdr.fmt_hdr.block_align != 2 ||
+ wave_hdr.fmt_hdr.bits_per_sample != 16)
+ {
+ pj_file_close(fd);
+ return PJMEDIA_EWAVEUNSUPP;
+ }
+
+ /* Validate length. */
+ if (wave_hdr.data_hdr.len != file_size-sizeof(pjmedia_wave_hdr)) {
+ pj_file_close(fd);
+ return PJMEDIA_EWAVEUNSUPP;
+ }
+ if (wave_hdr.data_hdr.len < 400) {
+ pj_file_close(fd);
+ return PJMEDIA_EWAVETOOSHORT;
+ }
+
+ /* It seems like we have a valid WAVE file. */
+
+ /* Create file_port instance. */
+ file_port = create_file_port(pool);
+ if (!file_port) {
+ pj_file_close(fd);
+ return PJ_ENOMEM;
+ }
+
+ /* Initialize */
+ file_port->base.user_data = user_data;
+
+ /* For this version, we only support reading the whole
+ * contents of the file.
+ */
+ file_port->bufsize = wave_hdr.data_hdr.len - 8;
+
+ /* Create buffer. */
+ file_port->buf = pj_pool_alloc(pool, file_port->bufsize);
+ if (!file_port->buf) {
+ pj_file_close(fd);
+ return PJ_ENOMEM;
+ }
+
+ file_port->readpos = file_port->buf;
+
+ /* Read the the file. */
+ size_read = file_port->bufsize;
+ status = pj_file_read(fd, file_port->buf, &size_read);
+ if (status != PJ_SUCCESS) {
+ pj_file_close(fd);
+ return status;
+ }
+
+ if (size_read != (pj_ssize_t)file_port->bufsize) {
+ pj_file_close(fd);
+ return PJMEDIA_ENOTVALIDWAVE;
+ }
+
+
+ /* Done. */
+ pj_file_close(fd);
+
+ *p_port = &file_port->base;
+
+ return PJ_SUCCESS;
+}
+
+
+/*
+ * Put frame to file.
+ */
+static pj_status_t file_put_frame(pjmedia_port *this_port,
+ const pjmedia_frame *frame)
+{
+ PJ_UNUSED_ARG(this_port);
+ PJ_UNUSED_ARG(frame);
+ return PJ_EINVALIDOP;
+}
+
+/*
+ * Get frame from file.
+ */
+static pj_status_t file_get_frame(pjmedia_port *this_port,
+ pjmedia_frame *frame)
+{
+ struct file_port *port = (struct file_port*)this_port;
+
+ pj_assert(port->base.info.signature == SIGNATURE);
+
+ /* Copy frame from buffer. */
+ frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
+ frame->size = 320;
+ frame->timestamp.u64 = 0;
+
+ if (port->readpos + 320 <= port->buf + port->bufsize) {
+ pj_memcpy(frame->buf, port->readpos, 320);
+ port->readpos += 320;
+ if (port->readpos == port->buf + port->bufsize)
+ port->readpos = port->buf;
+ } else {
+ unsigned endread;
+
+ endread = (port->buf+port->bufsize) - port->readpos;
+ pj_memcpy(frame->buf, port->readpos, endread);
+ pj_memcpy(((char*)frame->buf)+endread, port->buf, 320-endread);
+ port->readpos = port->buf + (320-endread);
+ }
+
+ return PJ_SUCCESS;
+}
+
+/*
+ *
+ */
+static pj_status_t file_on_destroy(pjmedia_port *this_port)
+{
+ PJ_UNUSED_ARG(this_port);
+
+ pj_assert(this_port->info.signature == SIGNATURE);
+
+ return PJ_SUCCESS;
+}
diff --git a/pjsip/src/pjsua/main.c b/pjsip/src/pjsua/main.c
index 5508e069..5218c7cd 100644
--- a/pjsip/src/pjsua/main.c
+++ b/pjsip/src/pjsua/main.c
@@ -261,21 +261,34 @@ static void ui_input_url(const char *title, char *buf, int len,
static void conf_list(void)
{
- pjmedia_conf_port_info info;
- struct pjsua_inv_data *inv_data;
+ unsigned i, count;
+ pjmedia_conf_port_info info[16];
printf("Conference ports:\n");
- inv_data = pjsua.inv_list.next;
- while (inv_data != &pjsua.inv_list) {
+ count = PJ_ARRAY_SIZE(info);
+ pjmedia_conf_get_ports_info(pjsua.mconf, &count, info);
+ for (i=0; i<count; ++i) {
+ char txlist[80];
+ unsigned j;
+ pjmedia_conf_port_info *port_info = &info[i];
- pjmedia_conf_get_port_info(pjsua.mconf, inv_data->conf_slot, &info);
-
- printf("Port %2d %.*s\n", inv_data->conf_slot,
- (int)info.name.slen, info.name.ptr);
+ txlist[0] = '\0';
+ for (j=0; j<pjsua.max_ports; ++j) {
+ char s[10];
+ if (port_info->listener[j]) {
+ pj_sprintf(s, "#%d ", j);
+ pj_ansi_strcat(txlist, s);
+ }
+ }
+ printf("Port #%02d %20.*s tx to: %s\n",
+ port_info->slot,
+ (int)port_info->name.slen,
+ port_info->name.ptr,
+ txlist);
- inv_data = inv_data->next;
}
+ puts("");
}
diff --git a/pjsip/src/pjsua/pjsua.h b/pjsip/src/pjsua/pjsua.h
index e731b4e4..81927821 100644
--- a/pjsip/src/pjsua/pjsua.h
+++ b/pjsip/src/pjsua/pjsua.h
@@ -115,8 +115,11 @@ struct pjsua
/* Media: */
pjmedia_endpt *med_endpt; /**< Media endpoint. */
+ unsigned max_ports; /**< Max ports in conf. */
pjmedia_conf *mconf; /**< Media conference. */
pj_bool_t null_audio; /**< Null audio flag. */
+ char *wav_file; /**< WAV file name to play. */
+ unsigned wav_slot; /**< WAV player slot in bridge */
/* Since we support simultaneous calls, we need to have multiple
diff --git a/pjsip/src/pjsua/pjsua_core.c b/pjsip/src/pjsua/pjsua_core.c
index 77b6631a..56a29063 100644
--- a/pjsip/src/pjsua/pjsua_core.c
+++ b/pjsip/src/pjsua/pjsua_core.c
@@ -76,6 +76,10 @@ void pjsua_default(void)
pjsua.reg_timeout = 55;
+ /* Default maximum conference ports: */
+
+ pjsua.max_ports = 8;
+
/* Init route set list: */
pj_list_init(&pjsua.route_set);
@@ -517,7 +521,8 @@ pj_status_t pjsua_init(void)
/* Init conference bridge. */
- status = pjmedia_conf_create(pjsua.pool, 8, 8000, 160, 16, &pjsua.mconf);
+ status = pjmedia_conf_create(pjsua.pool, pjsua.max_ports,
+ 8000, 160, 16, &pjsua.mconf);
if (status != PJ_SUCCESS) {
pj_caching_pool_destroy(&pjsua.cp);
pjsua_perror(THIS_FILE,
@@ -554,6 +559,35 @@ pj_status_t pjsua_start(void)
pjsip_transport *udp_transport;
pj_status_t status = PJ_SUCCESS;
+ /* Create WAV file player if required: */
+
+ if (pjsua.wav_file) {
+ pjmedia_port *port;
+ pj_str_t port_name;
+
+ /* Create the file player port. */
+ status = pjmedia_file_player_port_create( pjsua.pool, pjsua.wav_file,
+ 0, -1, NULL, &port);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Error playing media file",
+ status);
+ return status;
+ }
+
+ /* Add port to conference bridge: */
+ status = pjmedia_conf_add_port(pjsua.mconf, pjsua.pool, port,
+ pj_cstr(&port_name, pjsua.wav_file),
+ &pjsua.wav_slot);
+ if (status != PJ_SUCCESS) {
+ pjsua_perror(THIS_FILE,
+ "Unable to add file player to conference bridge",
+ status);
+ return status;
+ }
+ }
+
+
/* Init sockets (STUN etc): */
for (i=0; i<PJ_ARRAY_SIZE(pjsua.med_sock_info); ++i) {
status = init_sockets(i==0, &pjsua.med_sock_info[i]);
diff --git a/pjsip/src/pjsua/pjsua_opt.c b/pjsip/src/pjsua/pjsua_opt.c
index 5ec1a56a..d40f1de1 100644
--- a/pjsip/src/pjsua/pjsua_opt.c
+++ b/pjsip/src/pjsua/pjsua_opt.c
@@ -55,6 +55,8 @@ static void usage(void)
puts("");
puts("Media options:");
puts(" --null-audio Use NULL audio device");
+ puts(" --wav-file=file Play WAV file in conference bridge");
+ puts("");
//puts("");
//puts("User Agent options:");
//puts(" --auto-answer=sec Auto-answer all incoming calls after sec seconds.");
@@ -196,7 +198,7 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
OPT_REALM, OPT_USERNAME, OPT_PASSWORD,
OPT_USE_STUN1, OPT_USE_STUN2,
OPT_ADD_BUDDY, OPT_OFFER_X_MS_MSG, OPT_NO_PRESENCE,
- OPT_AUTO_ANSWER, OPT_AUTO_HANGUP};
+ OPT_AUTO_ANSWER, OPT_AUTO_HANGUP, OPT_WAV_FILE};
struct option long_options[] = {
{ "config-file",1, 0, OPT_CONFIG_FILE},
{ "log-file", 1, 0, OPT_LOG_FILE},
@@ -222,6 +224,7 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
{ "no-presence", 0, 0, OPT_NO_PRESENCE},
{ "auto-answer",1, 0, OPT_AUTO_ANSWER},
{ "auto-hangup",1, 0, OPT_AUTO_HANGUP},
+ { "wav-file", 1, 0, OPT_WAV_FILE},
{ NULL, 0, 0, 0}
};
pj_status_t status;
@@ -405,6 +408,10 @@ pj_status_t pjsua_parse_args(int argc, char *argv[])
}
pjsua.buddies[pjsua.buddy_cnt++].uri = pj_str(optarg);
break;
+
+ case OPT_WAV_FILE:
+ pjsua.wav_file = optarg;
+ break;
}
}