linphone-iphone/linphone/mediastreamer2/src/msfileplayer.c
smorlat 4cafb80672 internationalization of mediastreamer2 (thanks to Petr Pisar)
git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@208 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
2008-12-17 21:42:02 +00:00

304 lines
6.9 KiB
C

/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.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 "mediastreamer2/msfileplayer.h"
#include "mediastreamer2/waveheader.h"
#include "mediastreamer2/msticker.h"
static int player_close(MSFilter *f, void *arg);
typedef enum {
CLOSED,
STARTED,
STOPPED
} PlayerState;
struct _PlayerData{
int fd;
PlayerState state;
int rate;
int nchannels;
int hsize;
int loop_after;
int pause_time;
bool_t swap;
};
typedef struct _PlayerData PlayerData;
static void player_init(MSFilter *f){
PlayerData *d=ms_new(PlayerData,1);
d->fd=-1;
d->state=CLOSED;
d->swap=FALSE;
d->rate=8000;
d->nchannels=1;
d->hsize=0;
d->loop_after=-1; /*by default, don't loop*/
d->pause_time=0;
f->data=d;
}
static int read_wav_header(PlayerData *d){
char header1[sizeof(riff_t)];
char header2[sizeof(format_t)];
char header3[sizeof(data_t)];
int count;
riff_t *riff_chunk=(riff_t*)header1;
format_t *format_chunk=(format_t*)header2;
data_t *data_chunk=(data_t*)header3;
unsigned long len=0;
len = read(d->fd, header1, sizeof(header1)) ;
if (len != sizeof(header1)){
ms_warning("Wrong wav header: cannot read file");
return -1;
}
if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){
ms_warning("Wrong wav header (not RIFF/WAV)");
return -1;
}
len = read(d->fd, header2, sizeof(header2)) ;
if (len != sizeof(header2)){
ms_warning("Wrong wav header: cannot read file");
return -1;
}
d->rate=le_uint32(format_chunk->rate);
d->nchannels=le_uint16(format_chunk->channel);
if (format_chunk->len-0x10>0)
{
lseek(d->fd,(format_chunk->len-0x10),SEEK_CUR);
}
d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len;
len = read(d->fd, header3, sizeof(header3)) ;
if (len != sizeof(header3)){
ms_warning("Wrong wav header: cannot read file");
return -1;
}
count=0;
while (strncmp(data_chunk->data, "data", 4)!=0 && count<30)
{
ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len);
lseek(d->fd,data_chunk->len,SEEK_CUR);
count++;
d->hsize=d->hsize+len+data_chunk->len;
len = read(d->fd, header3, sizeof(header3)) ;
if (len != sizeof(header3)){
ms_warning("Wrong wav header: cannot read file");
return -1;
}
}
#ifdef WORDS_BIGENDIAN
if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2)
d->swap=TRUE;
#endif
return 0;
}
static int player_open(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
int fd;
const char *file=(const char*)arg;
if (d->fd>=0){
player_close(f,NULL);
}
if ((fd=open(file,O_RDONLY))==-1){
ms_warning("Failed to open %s",file);
return -1;
}
d->state=STOPPED;
d->fd=fd;
if (strstr(file,".wav")!=NULL) read_wav_header(d);
ms_message("%s opened: rate=%i,channel=%i",file,d->rate,d->nchannels);
return 0;
}
static int player_start(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
if (d->state==STOPPED)
d->state=STARTED;
return 0;
}
static int player_stop(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
ms_filter_lock(f);
if (d->state==STARTED){
d->state=STOPPED;
lseek(d->fd,d->hsize,SEEK_SET);
}
ms_filter_unlock(f);
return 0;
}
static int player_close(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
player_stop(f,NULL);
if (d->fd>=0) close(d->fd);
d->fd=-1;
d->state=CLOSED;
return 0;
}
static void player_uninit(MSFilter *f){
PlayerData *d=(PlayerData*)f->data;
if (d->fd>=0) player_close(f,NULL);
ms_free(d);
}
static void swap_bytes(unsigned char *bytes, int len){
int i;
unsigned char tmp;
for(i=0;i<len;i+=2){
tmp=bytes[i];
bytes[i]=bytes[i+1];
bytes[i+1]=tmp;
}
}
static void player_process(MSFilter *f){
PlayerData *d=(PlayerData*)f->data;
int bytes=2*(f->ticker->interval*d->rate*d->nchannels)/1000;
ms_filter_lock(f);
if (d->state==STARTED){
int err;
mblk_t *om=allocb(bytes,0);
if (d->pause_time>0){
err=bytes;
memset(om->b_wptr,0,bytes);
d->pause_time-=f->ticker->interval;
}else{
err=read(d->fd,om->b_wptr,bytes);
if (d->swap) swap_bytes(om->b_wptr,bytes);
}
if (err>=0){
if (err!=0){
om->b_wptr+=bytes;
ms_queue_put(f->outputs[0],om);
}else freemsg(om);
if (err<bytes){
ms_filter_notify_no_arg(f,MS_FILE_PLAYER_EOF);
lseek(d->fd,d->hsize,SEEK_SET);
/* special value for playing file only once */
if (d->loop_after==-2)
{
d->state=STOPPED;
ms_filter_unlock(f);
return;
}
if (d->loop_after>=0){
d->pause_time=d->loop_after;
}
}
}else{
ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno));
}
}
ms_filter_unlock(f);
}
static int player_get_sr(MSFilter *f, void*arg){
PlayerData *d=(PlayerData*)f->data;
*((int*)arg)=d->rate;
return 0;
}
static int player_loop(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
d->loop_after=*((int*)arg);
return 0;
}
static int player_eof(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
if (d->fd<0 && d->state==CLOSED)
*((int*)arg) = TRUE; /* 1 */
else
*((int*)arg) = FALSE; /* 0 */
return 0;
}
static int player_get_nch(MSFilter *f, void *arg){
PlayerData *d=(PlayerData*)f->data;
*((int*)arg)=d->nchannels;
return 0;
}
static MSFilterMethod player_methods[]={
{ MS_FILE_PLAYER_OPEN, player_open },
{ MS_FILE_PLAYER_START, player_start },
{ MS_FILE_PLAYER_STOP, player_stop },
{ MS_FILE_PLAYER_CLOSE, player_close },
{ MS_FILTER_GET_SAMPLE_RATE, player_get_sr},
{ MS_FILTER_GET_NCHANNELS, player_get_nch },
{ MS_FILE_PLAYER_LOOP, player_loop },
{ MS_FILE_PLAYER_DONE, player_eof },
{ 0, NULL }
};
#ifdef WIN32
MSFilterDesc ms_file_player_desc={
MS_FILE_PLAYER_ID,
"MSFilePlayer",
N_("Raw files and wav reader"),
MS_FILTER_OTHER,
NULL,
0,
1,
player_init,
NULL,
player_process,
NULL,
player_uninit,
player_methods
};
#else
MSFilterDesc ms_file_player_desc={
.id=MS_FILE_PLAYER_ID,
.name="MSFilePlayer",
.text=N_("Raw files and wav reader"),
.category=MS_FILTER_OTHER,
.ninputs=0,
.noutputs=1,
.init=player_init,
.process=player_process,
.uninit=player_uninit,
.methods=player_methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_file_player_desc)