diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-02-23 02:09:10 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-02-23 02:09:10 +0000 |
commit | 6d68baecdefbc8b90749dc7cff8def2a5a88af30 (patch) | |
tree | 6a83cbd3ae5c1246a443293b09606e658e211342 /pjmedia/src | |
parent | 084ee2728e8ee98944c9b8525704d5937aafa3b3 (diff) |
Added support for playing WAV file
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@222 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src')
-rw-r--r-- | pjmedia/src/pjmedia/conference.c | 22 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/errno.c | 5 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/file_port.c | 261 |
3 files changed, 288 insertions, 0 deletions
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; +} |