summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2006-09-18 23:33:44 +0000
committerBenny Prijono <bennylp@teluu.com>2006-09-18 23:33:44 +0000
commit6f0c45ca34575b68017a174e63014bcf18a99763 (patch)
tree1343b06363ead620c56f3b261b39ef90646a5390
parent2f0bd9f3cacc40aaafc784788030c6f244588e3f (diff)
Support for reading non-canonical WAV file in WAV file player port.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@727 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r--pjmedia/include/pjmedia/wave.h24
-rw-r--r--pjmedia/src/pjmedia/wav_player.c70
2 files changed, 82 insertions, 12 deletions
diff --git a/pjmedia/include/pjmedia/wave.h b/pjmedia/include/pjmedia/wave.h
index 9727a9bd..0de40e29 100644
--- a/pjmedia/include/pjmedia/wave.h
+++ b/pjmedia/include/pjmedia/wave.h
@@ -96,6 +96,30 @@ struct pjmedia_wave_hdr
*/
typedef struct pjmedia_wave_hdr pjmedia_wave_hdr;
+/**
+ * This structure describes generic RIFF subchunk header.
+ */
+typedef struct pjmedia_wave_subchunk
+{
+ pj_uint32_t id; /**< Subchunk ASCII tag. */
+ pj_uint32_t len; /**< Length following this field */
+} pjmedia_wave_subchunk;
+
+
+/**
+ * Normalize subchunk header from little endian (the representation of
+ * RIFF file) into host's endian.
+ */
+#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
+# define PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(ch) \
+ do { \
+ (ch)->id = pj_swap32((ch)->id); \
+ (ch)->len = pj_swap32((ch)->len); \
+ } while (0)
+#else
+# define PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(ch)
+#endif
+
/**
* On big-endian hosts, this function swaps the byte order of the values
diff --git a/pjmedia/src/pjmedia/wav_player.c b/pjmedia/src/pjmedia/wav_player.c
index d2e7204b..79d1209d 100644
--- a/pjmedia/src/pjmedia/wav_player.c
+++ b/pjmedia/src/pjmedia/wav_player.c
@@ -62,6 +62,7 @@ struct file_port
char *readpos;
pj_off_t fsize;
+ unsigned start_data;
pj_off_t fpos;
pj_oshandle_t fd;
@@ -164,7 +165,7 @@ static pj_status_t fill_buffer(struct file_port *fport)
PJ_LOG(5,(THIS_FILE, "File port %.*s EOF, rewinding..",
(int)fport->base.info.name.slen,
fport->base.info.name.ptr));
- fport->fpos = sizeof(struct pjmedia_wave_hdr);
+ fport->fpos = fport->start_data;
pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
}
}
@@ -188,8 +189,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
pjmedia_port **p_port )
{
pjmedia_wave_hdr wave_hdr;
- pj_ssize_t size_read;
+ pj_ssize_t size_to_read, size_read;
struct file_port *fport;
+ pj_off_t pos;
pj_status_t status;
@@ -225,14 +227,14 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
if (status != PJ_SUCCESS)
return status;
- /* Read the WAVE header. */
- size_read = sizeof(wave_hdr);
+ /* Read the file header plus fmt header only. */
+ size_read = size_to_read = sizeof(wave_hdr) - 8;
status = pj_file_read( fport->fd, &wave_hdr, &size_read);
if (status != PJ_SUCCESS) {
pj_file_close(fport->fd);
return status;
}
- if (size_read != sizeof(wave_hdr)) {
+ if (size_read != size_to_read) {
pj_file_close(fport->fd);
return PJMEDIA_ENOTVALIDWAVE;
}
@@ -270,8 +272,53 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
return PJMEDIA_EWAVEUNSUPP;
}
+ /* If length of fmt_header is greater than 16, skip the remaining
+ * fmt header data.
+ */
+ if (wave_hdr.fmt_hdr.len > 16) {
+ size_to_read = wave_hdr.fmt_hdr.len - 16;
+ status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
+ if (status != PJ_SUCCESS) {
+ pj_file_close(fport->fd);
+ return status;
+ }
+ }
+
+ /* Repeat reading the WAVE file until we have 'data' chunk */
+ for (;;) {
+ pjmedia_wave_subchunk subchunk;
+ size_read = 8;
+ status = pj_file_read(fport->fd, &subchunk, &size_read);
+ if (status != PJ_SUCCESS || size_read != 8) {
+ pj_file_close(fport->fd);
+ return PJMEDIA_EWAVETOOSHORT;
+ }
+
+ /* Normalize endianness */
+ PJMEDIA_WAVE_NORMALIZE_SUBCHUNK(&subchunk);
+
+ /* Break if this is "data" chunk */
+ if (subchunk.id == PJMEDIA_DATA_TAG) {
+ wave_hdr.data_hdr.data = PJMEDIA_DATA_TAG;
+ wave_hdr.data_hdr.len = subchunk.len;
+ break;
+ }
+
+ /* Otherwise skip the chunk contents */
+ size_to_read = subchunk.len;
+ status = pj_file_setpos(fport->fd, size_to_read, PJ_SEEK_CUR);
+ if (status != PJ_SUCCESS) {
+ pj_file_close(fport->fd);
+ return status;
+ }
+ }
+
+ /* Current file position now points to start of data */
+ status = pj_file_getpos(fport->fd, &pos);
+ fport->start_data = (unsigned)pos;
+
/* Validate length. */
- if (wave_hdr.data_hdr.len != fport->fsize-sizeof(pjmedia_wave_hdr)) {
+ if (wave_hdr.data_hdr.len != fport->fsize - fport->start_data) {
pj_file_close(fport->fd);
return PJMEDIA_EWAVEUNSUPP;
}
@@ -310,11 +357,11 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_create( pj_pool_t *pool,
pj_file_close(fport->fd);
return PJ_ENOMEM;
}
-
+
fport->readpos = fport->buf;
/* Set initial position of the file. */
- fport->fpos = sizeof(struct pjmedia_wave_hdr);
+ fport->fpos = fport->start_data;
/* Fill up the buffer. */
status = fill_buffer(fport);
@@ -359,10 +406,9 @@ PJ_DEF(pj_status_t) pjmedia_wav_player_port_set_pos(pjmedia_port *port,
fport = (struct file_port*) port;
- PJ_ASSERT_RETURN(bytes < fport->fsize - sizeof(pjmedia_wave_hdr),
- PJ_EINVAL);
+ PJ_ASSERT_RETURN(bytes < fport->fsize - fport->start_data, PJ_EINVAL);
- fport->fpos = sizeof(struct pjmedia_wave_hdr) + bytes;
+ fport->fpos = fport->start_data + bytes;
pj_file_setpos( fport->fd, fport->fpos, PJ_SEEK_SET);
fport->eof = PJ_FALSE;
@@ -386,7 +432,7 @@ PJ_DEF(pj_ssize_t) pjmedia_wav_player_port_get_pos( pjmedia_port *port )
fport = (struct file_port*) port;
- payload_pos = (pj_size_t)(fport->fpos - sizeof(pjmedia_wave_hdr));
+ payload_pos = (pj_size_t)(fport->fpos - fport->start_data);
if (payload_pos >= fport->bufsize)
return payload_pos - fport->bufsize + (fport->readpos - fport->buf);
else