2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "mediastreamer2/msfileplayer.h"
21 #include "mediastreamer2/waveheader.h"
22 #include "mediastreamer2/msticker.h"
25 static int player_close(MSFilter *f, void *arg);
45 typedef struct _PlayerData PlayerData;
47 static void player_init(MSFilter *f){
48 PlayerData *d=ms_new(PlayerData,1);
55 d->loop_after=-1; /*by default, don't loop*/
61 static int read_wav_header(PlayerData *d){
62 char header1[sizeof(riff_t)];
63 char header2[sizeof(format_t)];
64 char header3[sizeof(data_t)];
67 riff_t *riff_chunk=(riff_t*)header1;
68 format_t *format_chunk=(format_t*)header2;
69 data_t *data_chunk=(data_t*)header3;
73 len = read(d->fd, header1, sizeof(header1)) ;
74 if (len != sizeof(header1)){
78 if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){
82 len = read(d->fd, header2, sizeof(header2)) ;
83 if (len != sizeof(header2)){
84 ms_warning("Wrong wav header: cannot read file");
88 d->rate=le_uint32(format_chunk->rate);
89 d->nchannels=le_uint16(format_chunk->channel);
91 if (format_chunk->len-0x10>0)
93 lseek(d->fd,(format_chunk->len-0x10),SEEK_CUR);
96 d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len;
98 len = read(d->fd, header3, sizeof(header3)) ;
99 if (len != sizeof(header3)){
100 ms_warning("Wrong wav header: cannot read file");
104 while (strncmp(data_chunk->data, "data", 4)!=0 && count<30)
106 ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len);
107 lseek(d->fd,data_chunk->len,SEEK_CUR);
109 d->hsize=d->hsize+len+data_chunk->len;
111 len = read(d->fd, header3, sizeof(header3)) ;
112 if (len != sizeof(header3)){
113 ms_warning("Wrong wav header: cannot read file");
117 #ifdef WORDS_BIGENDIAN
118 if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2)
125 lseek(d->fd,0,SEEK_SET);
130 static int player_open(MSFilter *f, void *arg){
131 PlayerData *d=(PlayerData*)f->data;
133 const char *file=(const char*)arg;
136 player_close(f,NULL);
138 if ((fd=open(file,O_RDONLY))==-1){
139 ms_warning("Failed to open %s",file);
144 if (read_wav_header(d)!=0 && strstr(file,".wav")){
145 ms_warning("File %s has .wav extension but wav header could be found.",file);
147 ms_message("%s opened: rate=%i,channel=%i",file,d->rate,d->nchannels);
151 static int player_start(MSFilter *f, void *arg){
152 PlayerData *d=(PlayerData*)f->data;
153 if (d->state==STOPPED)
158 static int player_stop(MSFilter *f, void *arg){
159 PlayerData *d=(PlayerData*)f->data;
161 if (d->state==STARTED){
163 lseek(d->fd,d->hsize,SEEK_SET);
169 static int player_close(MSFilter *f, void *arg){
170 PlayerData *d=(PlayerData*)f->data;
172 if (d->fd>=0) close(d->fd);
178 static void player_uninit(MSFilter *f){
179 PlayerData *d=(PlayerData*)f->data;
180 if (d->fd>=0) player_close(f,NULL);
184 static void swap_bytes(unsigned char *bytes, int len){
194 static void player_process(MSFilter *f){
195 PlayerData *d=(PlayerData*)f->data;
196 int nsamples=(f->ticker->interval*d->rate*d->nchannels)/1000;
198 /*send an even number of samples each tick. At 22050Hz the number of samples per 10 ms chunk is odd.
199 Odd size buffer of samples cause troubles to alsa. Fixing in alsa is difficult, so workaround here.
201 if (nsamples & 0x1 ) { //odd number of samples
210 if (d->state==STARTED){
212 mblk_t *om=allocb(bytes,0);
213 if (d->pause_time>0){
215 memset(om->b_wptr,0,bytes);
216 d->pause_time-=f->ticker->interval;
218 err=read(d->fd,om->b_wptr,bytes);
219 if (d->swap) swap_bytes(om->b_wptr,bytes);
224 memset(om->b_wptr+err,0,bytes-err);
226 ms_queue_put(f->outputs[0],om);
229 ms_filter_notify_no_arg(f,MS_FILE_PLAYER_EOF);
230 lseek(d->fd,d->hsize,SEEK_SET);
232 /* special value for playing file only once */
233 if (d->loop_after==-2)
240 if (d->loop_after>=0){
241 d->pause_time=d->loop_after;
245 ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno));
251 static int player_get_sr(MSFilter *f, void*arg){
252 PlayerData *d=(PlayerData*)f->data;
253 *((int*)arg)=d->rate;
257 static int player_loop(MSFilter *f, void *arg){
258 PlayerData *d=(PlayerData*)f->data;
259 d->loop_after=*((int*)arg);
263 static int player_eof(MSFilter *f, void *arg){
264 PlayerData *d=(PlayerData*)f->data;
265 if (d->fd<0 && d->state==CLOSED)
266 *((int*)arg) = TRUE; /* 1 */
268 *((int*)arg) = FALSE; /* 0 */
272 static int player_get_nch(MSFilter *f, void *arg){
273 PlayerData *d=(PlayerData*)f->data;
274 *((int*)arg)=d->nchannels;
278 static MSFilterMethod player_methods[]={
279 { MS_FILE_PLAYER_OPEN, player_open },
280 { MS_FILE_PLAYER_START, player_start },
281 { MS_FILE_PLAYER_STOP, player_stop },
282 { MS_FILE_PLAYER_CLOSE, player_close },
283 { MS_FILTER_GET_SAMPLE_RATE, player_get_sr},
284 { MS_FILTER_GET_NCHANNELS, player_get_nch },
285 { MS_FILE_PLAYER_LOOP, player_loop },
286 { MS_FILE_PLAYER_DONE, player_eof },
292 MSFilterDesc ms_file_player_desc={
295 N_("Raw files and wav reader"),
310 MSFilterDesc ms_file_player_desc={
311 .id=MS_FILE_PLAYER_ID,
312 .name="MSFilePlayer",
313 .text=N_("Raw files and wav reader"),
314 .category=MS_FILTER_OTHER,
318 .process=player_process,
319 .uninit=player_uninit,
320 .methods=player_methods
325 MS_FILTER_DESC_EXPORT(ms_file_player_desc)