summaryrefslogtreecommitdiff
path: root/pjmedia/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-02-23 02:09:10 +0000
committerBenny Prijono <bennylp@teluu.com>2006-02-23 02:09:10 +0000
commit6d68baecdefbc8b90749dc7cff8def2a5a88af30 (patch)
tree6a83cbd3ae5c1246a443293b09606e658e211342 /pjmedia/src
parent084ee2728e8ee98944c9b8525704d5937aafa3b3 (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.c22
-rw-r--r--pjmedia/src/pjmedia/errno.c5
-rw-r--r--pjmedia/src/pjmedia/file_port.c261
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;
+}