]> sjero.net Git - linphone/blob - linphone/mediastreamer2/src/msfileplayer.c
3ae4676177c0390c4abd3a8ad7e673abd5d544c8
[linphone] / linphone / mediastreamer2 / src / msfileplayer.c
1 /*
2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
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.
9
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.
14
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.
18 */
19
20 #include "mediastreamer2/msfileplayer.h"
21 #include "mediastreamer2/waveheader.h"
22 #include "mediastreamer2/msticker.h"
23
24
25 static int player_close(MSFilter *f, void *arg);
26
27 typedef enum {
28         CLOSED,
29         STARTED,
30         STOPPED
31 } PlayerState;
32
33 struct _PlayerData{
34         int fd;
35         PlayerState state;
36         int rate;
37         int nchannels;
38         int hsize;
39         int loop_after;
40         int pause_time;
41         int count;
42         bool_t swap;
43 };
44
45 typedef struct _PlayerData PlayerData;
46
47 static void player_init(MSFilter *f){
48         PlayerData *d=ms_new(PlayerData,1);
49         d->fd=-1;
50         d->state=CLOSED;
51         d->swap=FALSE;
52         d->rate=8000;
53         d->nchannels=1;
54         d->hsize=0;
55         d->loop_after=-1; /*by default, don't loop*/
56         d->pause_time=0;
57         d->count=0;
58         f->data=d;      
59 }
60
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)];
65         int count;
66         
67         riff_t *riff_chunk=(riff_t*)header1;
68         format_t *format_chunk=(format_t*)header2;
69         data_t *data_chunk=(data_t*)header3;
70         
71         unsigned long len=0;
72         
73         len = read(d->fd, header1, sizeof(header1)) ;
74         if (len != sizeof(header1)){
75                 goto not_a_wav;
76         }
77         
78         if (0!=strncmp(riff_chunk->riff, "RIFF", 4) || 0!=strncmp(riff_chunk->wave, "WAVE", 4)){        
79                 goto not_a_wav;
80         }
81         
82         len = read(d->fd, header2, sizeof(header2)) ;            
83         if (len != sizeof(header2)){
84                 ms_warning("Wrong wav header: cannot read file");
85                 goto not_a_wav;
86         }
87         
88         d->rate=le_uint32(format_chunk->rate);
89         d->nchannels=le_uint16(format_chunk->channel);
90         
91         if (format_chunk->len-0x10>0)
92         {
93                 lseek(d->fd,(format_chunk->len-0x10),SEEK_CUR);
94         }
95         
96         d->hsize=sizeof(wave_header_t)-0x10+format_chunk->len;
97         
98         len = read(d->fd, header3, sizeof(header3)) ;
99         if (len != sizeof(header3)){
100                 ms_warning("Wrong wav header: cannot read file");
101                 goto not_a_wav;
102         }
103         count=0;
104         while (strncmp(data_chunk->data, "data", 4)!=0 && count<30)
105         {
106                 ms_warning("skipping chunk=%s len=%i", data_chunk->data, data_chunk->len);
107                 lseek(d->fd,data_chunk->len,SEEK_CUR);
108                 count++;
109                 d->hsize=d->hsize+len+data_chunk->len;
110         
111                 len = read(d->fd, header3, sizeof(header3)) ;
112                 if (len != sizeof(header3)){
113                         ms_warning("Wrong wav header: cannot read file");
114                         goto not_a_wav;
115                 }
116         }
117         #ifdef WORDS_BIGENDIAN
118         if (le_uint16(format_chunk->blockalign)==le_uint16(format_chunk->channel) * 2)
119                 d->swap=TRUE;
120         #endif
121         return 0;
122
123         not_a_wav:
124                 /*rewind*/
125                 lseek(d->fd,0,SEEK_SET);
126                 d->hsize=0;
127                 return -1;
128 }
129
130 static int player_open(MSFilter *f, void *arg){
131         PlayerData *d=(PlayerData*)f->data;
132         int fd;
133         const char *file=(const char*)arg;
134
135         if (d->fd>=0){
136                 player_close(f,NULL);
137         }
138         if ((fd=open(file,O_RDONLY))==-1){
139                 ms_warning("Failed to open %s",file);
140                 return -1;
141         }
142         d->state=STOPPED;
143         d->fd=fd;
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);
146         }
147         ms_message("%s opened: rate=%i,channel=%i",file,d->rate,d->nchannels);
148         return 0;
149 }
150
151 static int player_start(MSFilter *f, void *arg){
152         PlayerData *d=(PlayerData*)f->data;
153         if (d->state==STOPPED)
154                 d->state=STARTED;
155         return 0;
156 }
157
158 static int player_stop(MSFilter *f, void *arg){
159         PlayerData *d=(PlayerData*)f->data;
160         ms_filter_lock(f);
161         if (d->state==STARTED){
162                 d->state=STOPPED;
163                 lseek(d->fd,d->hsize,SEEK_SET);
164         }
165         ms_filter_unlock(f);
166         return 0;
167 }
168
169 static int player_close(MSFilter *f, void *arg){
170         PlayerData *d=(PlayerData*)f->data;
171         player_stop(f,NULL);
172         if (d->fd>=0)   close(d->fd);
173         d->fd=-1;
174         d->state=CLOSED;
175         return 0;
176 }
177
178 static void player_uninit(MSFilter *f){
179         PlayerData *d=(PlayerData*)f->data;
180         if (d->fd>=0) player_close(f,NULL);
181         ms_free(d);
182 }
183
184 static void swap_bytes(unsigned char *bytes, int len){
185         int i;
186         unsigned char tmp;
187         for(i=0;i<len;i+=2){
188                 tmp=bytes[i];
189                 bytes[i]=bytes[i+1];
190                 bytes[i+1]=tmp;
191         }
192 }
193
194 static void player_process(MSFilter *f){
195         PlayerData *d=(PlayerData*)f->data;
196         int nsamples=(f->ticker->interval*d->rate*d->nchannels)/1000;
197         int bytes;
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.
200         */
201         if (nsamples & 0x1 ) { //odd number of samples
202                 if (d->count & 0x1 )
203                         nsamples++;
204                 else
205                         nsamples--;
206         }
207         bytes=2*nsamples;
208         d->count++;
209         ms_filter_lock(f);
210         if (d->state==STARTED){
211                 int err;
212                 mblk_t *om=allocb(bytes,0);
213                 if (d->pause_time>0){
214                         err=bytes;
215                         memset(om->b_wptr,0,bytes);
216                         d->pause_time-=f->ticker->interval;
217                 }else{
218                         err=read(d->fd,om->b_wptr,bytes);
219                         if (d->swap) swap_bytes(om->b_wptr,bytes);
220                 }
221                 if (err>=0){
222                         if (err!=0){
223                                 if (err<bytes)
224                                         memset(om->b_wptr+err,0,bytes-err);
225                                 om->b_wptr+=bytes;
226                                 ms_queue_put(f->outputs[0],om);
227                         }else freemsg(om);
228                         if (err<bytes){
229                                 ms_filter_notify_no_arg(f,MS_FILE_PLAYER_EOF);
230                                 lseek(d->fd,d->hsize,SEEK_SET);
231
232                                 /* special value for playing file only once */
233                                 if (d->loop_after==-2)
234                                 {
235                                         d->state=STOPPED;
236                                         ms_filter_unlock(f);
237                                         return;
238                                 }
239
240                                 if (d->loop_after>=0){
241                                         d->pause_time=d->loop_after;
242                                 }
243                         }
244                 }else{
245                         ms_warning("Fail to read %i bytes: %s",bytes,strerror(errno));
246                 }
247         }
248         ms_filter_unlock(f);
249 }
250
251 static int player_get_sr(MSFilter *f, void*arg){
252         PlayerData *d=(PlayerData*)f->data;
253         *((int*)arg)=d->rate;
254         return 0;
255 }
256
257 static int player_loop(MSFilter *f, void *arg){
258         PlayerData *d=(PlayerData*)f->data;
259         d->loop_after=*((int*)arg);
260         return 0;
261 }
262
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 */
267         else
268                 *((int*)arg) = FALSE; /* 0 */
269         return 0;
270 }
271
272 static int player_get_nch(MSFilter *f, void *arg){
273         PlayerData *d=(PlayerData*)f->data;
274         *((int*)arg)=d->nchannels;
275         return 0;
276 }
277
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      },
287         {       0,                      NULL            }
288 };
289
290 #ifdef WIN32
291
292 MSFilterDesc ms_file_player_desc={
293         MS_FILE_PLAYER_ID,
294         "MSFilePlayer",
295         N_("Raw files and wav reader"),
296         MS_FILTER_OTHER,
297         NULL,
298     0,
299         1,
300         player_init,
301         NULL,
302     player_process,
303         NULL,
304     player_uninit,
305         player_methods
306 };
307
308 #else
309
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,
315         .ninputs=0,
316         .noutputs=1,
317         .init=player_init,
318         .process=player_process,
319         .uninit=player_uninit,
320         .methods=player_methods
321 };
322
323 #endif
324
325 MS_FILTER_DESC_EXPORT(ms_file_player_desc)