Added support for playing WAV file
git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@222 74dad513-b988-da41-8d7b-12977e46ad98
This commit is contained in:
parent
ed1056c859
commit
3987915f25
|
@ -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"
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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__ */
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
/**
|
||||
* @file vad.h
|
||||
* @brief Voice Activity Detector.
|
||||
* @brief Simple, adaptive silence detector.
|
||||
*/
|
||||
#include <pjmedia/types.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__ */
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
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);
|
||||
|
||||
printf("Port %2d %.*s\n", inv_data->conf_slot,
|
||||
(int)info.name.slen, info.name.ptr);
|
||||
|
||||
inv_data = inv_data->next;
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue