remove extraneous svn:executable properties
[asterisk/asterisk.git] / formats / format_ogg_vorbis.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005, Jeff Ollie
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief OGG/Vorbis streams.
20  * \arg File name extension: ogg
21  * \ingroup formats
22  */
23  
24 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <stdlib.h>
28 #include <sys/time.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <string.h>
33
34 #include <vorbis/codec.h>
35 #include <vorbis/vorbisenc.h>
36
37 #ifdef _WIN32
38 #include <io.h>
39 #include <fcntl.h>
40 #endif
41
42 #include "asterisk.h"
43
44 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
45
46 #include "asterisk/lock.h"
47 #include "asterisk/channel.h"
48 #include "asterisk/file.h"
49 #include "asterisk/logger.h"
50 #include "asterisk/module.h"
51
52 #define SAMPLES_MAX 160
53 #define BLOCK_SIZE 4096
54
55
56 struct ast_filestream {
57         void *reserved[AST_RESERVED_POINTERS];
58
59         FILE *f;
60
61         /* structures for handling the Ogg container */
62         ogg_sync_state   oy;
63         ogg_stream_state os;
64         ogg_page         og;
65         ogg_packet       op;
66         
67         /* structures for handling Vorbis audio data */
68         vorbis_info      vi;
69         vorbis_comment   vc;
70         vorbis_dsp_state vd;
71         vorbis_block     vb;
72         
73         /*! \brief Indicates whether this filestream is set up for reading or writing. */
74         int writing;
75
76         /*! \brief Indicates whether an End of Stream condition has been detected. */
77         int eos;
78
79         /*! \brief Buffer to hold audio data. */
80         short buffer[SAMPLES_MAX];
81
82         /*! \brief Asterisk frame object. */
83         struct ast_frame fr;
84         char waste[AST_FRIENDLY_OFFSET];
85         char empty;
86 };
87
88 AST_MUTEX_DEFINE_STATIC(ogg_vorbis_lock);
89 static int glistcnt = 0;
90
91 static char *name = "ogg_vorbis";
92 static char *desc = "OGG/Vorbis audio";
93 static char *exts = "ogg";
94
95 /*!
96  * \brief Create a new OGG/Vorbis filestream and set it up for reading.
97  * \param f File that points to on disk storage of the OGG/Vorbis data.
98  * \return The new filestream.
99  */
100 static struct ast_filestream *ogg_vorbis_open(FILE *f)
101 {
102         int i;
103         int bytes;
104         int result;
105         char **ptr;
106         char *buffer;
107
108         struct ast_filestream *tmp;
109
110         if((tmp = malloc(sizeof(struct ast_filestream)))) {
111                 memset(tmp, 0, sizeof(struct ast_filestream));
112
113                 tmp->writing = 0;
114                 tmp->f = f;
115
116                 ogg_sync_init(&tmp->oy);
117
118                 buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
119                 bytes = fread(buffer, 1, BLOCK_SIZE, f);
120                 ogg_sync_wrote(&tmp->oy, bytes);
121
122                 result = ogg_sync_pageout(&tmp->oy, &tmp->og);
123                 if(result != 1) {
124                         if(bytes < BLOCK_SIZE) {
125                                 ast_log(LOG_ERROR, "Run out of data...\n");
126                         } else {
127                                 ast_log(LOG_ERROR, "Input does not appear to be an Ogg bitstream.\n");
128                         }
129                         fclose(f);
130                         ogg_sync_clear(&tmp->oy);
131                         free(tmp);
132                         return NULL;
133                 }
134                 
135                 ogg_stream_init(&tmp->os, ogg_page_serialno(&tmp->og));
136                 vorbis_info_init(&tmp->vi);
137                 vorbis_comment_init(&tmp->vc);
138
139                 if(ogg_stream_pagein(&tmp->os, &tmp->og) < 0) { 
140                         ast_log(LOG_ERROR, "Error reading first page of Ogg bitstream data.\n");
141                         fclose(f);
142                         ogg_stream_clear(&tmp->os);
143                         vorbis_comment_clear(&tmp->vc);
144                         vorbis_info_clear(&tmp->vi);
145                         ogg_sync_clear(&tmp->oy);
146                         free(tmp);
147                         return NULL;
148                 }
149                 
150                 if(ogg_stream_packetout(&tmp->os, &tmp->op) != 1) { 
151                         ast_log(LOG_ERROR, "Error reading initial header packet.\n");
152                         fclose(f);
153                         ogg_stream_clear(&tmp->os);
154                         vorbis_comment_clear(&tmp->vc);
155                         vorbis_info_clear(&tmp->vi);
156                         ogg_sync_clear(&tmp->oy);
157                         free(tmp);
158                         return NULL;
159                 }
160                 
161                 if(vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op) < 0) { 
162                         ast_log(LOG_ERROR, "This Ogg bitstream does not contain Vorbis audio data.\n");
163                         fclose(f);
164                         ogg_stream_clear(&tmp->os);
165                         vorbis_comment_clear(&tmp->vc);
166                         vorbis_info_clear(&tmp->vi);
167                         ogg_sync_clear(&tmp->oy);
168                         free(tmp);
169                         return NULL;
170                 }
171                 
172                 i = 0;
173                 while(i < 2) {
174                         while(i < 2){
175                                 result = ogg_sync_pageout(&tmp->oy, &tmp->og);
176                                 if(result == 0)
177                                         break;
178                                 if(result == 1) {
179                                         ogg_stream_pagein(&tmp->os, &tmp->og);
180                                         while(i < 2) {
181                                                 result = ogg_stream_packetout(&tmp->os,&tmp->op);
182                                                 if(result == 0)
183                                                         break;
184                                                 if(result < 0) {
185                                                         ast_log(LOG_ERROR, "Corrupt secondary header.  Exiting.\n");
186                                                         fclose(f);
187                                                         ogg_stream_clear(&tmp->os);
188                                                         vorbis_comment_clear(&tmp->vc);
189                                                         vorbis_info_clear(&tmp->vi);
190                                                         ogg_sync_clear(&tmp->oy);
191                                                         free(tmp);
192                                                         return NULL;
193                                                 }
194                                                 vorbis_synthesis_headerin(&tmp->vi, &tmp->vc, &tmp->op);
195                                                 i++;
196                                         }
197                                 }
198                         }
199
200                         buffer = ogg_sync_buffer(&tmp->oy, BLOCK_SIZE);
201                         bytes = fread(buffer, 1, BLOCK_SIZE, f);
202                         if(bytes == 0 && i < 2) {
203                                 ast_log(LOG_ERROR, "End of file before finding all Vorbis headers!\n");
204                                 fclose(f);
205                                 ogg_stream_clear(&tmp->os);
206                                 vorbis_comment_clear(&tmp->vc);
207                                 vorbis_info_clear(&tmp->vi);
208                                 ogg_sync_clear(&tmp->oy);
209                                 free(tmp);
210                                 return NULL;
211                         }
212                         ogg_sync_wrote(&tmp->oy, bytes);
213                 }
214                 
215                 ptr = tmp->vc.user_comments;
216                 while(*ptr){
217                         ast_log(LOG_DEBUG, "OGG/Vorbis comment: %s\n", *ptr);
218                         ++ptr;
219                 }
220                 ast_log(LOG_DEBUG, "OGG/Vorbis bitstream is %d channel, %ldHz\n", tmp->vi.channels, tmp->vi.rate);
221                 ast_log(LOG_DEBUG, "OGG/Vorbis file encoded by: %s\n", tmp->vc.vendor);
222
223                 if(tmp->vi.channels != 1) {
224                         ast_log(LOG_ERROR, "Only monophonic OGG/Vorbis files are currently supported!\n");
225                         ogg_stream_clear(&tmp->os);
226                         vorbis_comment_clear(&tmp->vc);
227                         vorbis_info_clear(&tmp->vi);
228                         ogg_sync_clear(&tmp->oy);
229                         free(tmp);
230                         return NULL;
231                 }
232                 
233
234                 if(tmp->vi.rate != 8000) {
235                         ast_log(LOG_ERROR, "Only 8000Hz OGG/Vorbis files are currently supported!\n");
236                         fclose(f);
237                         ogg_stream_clear(&tmp->os);
238                         vorbis_block_clear(&tmp->vb);
239                         vorbis_dsp_clear(&tmp->vd);
240                         vorbis_comment_clear(&tmp->vc);
241                         vorbis_info_clear(&tmp->vi);
242                         ogg_sync_clear(&tmp->oy);
243                         free(tmp);
244                         return NULL;
245                 }
246                 
247                 vorbis_synthesis_init(&tmp->vd, &tmp->vi);
248                 vorbis_block_init(&tmp->vd, &tmp->vb);
249
250                 if(ast_mutex_lock(&ogg_vorbis_lock)) {
251                         ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
252                         fclose(f);
253                         ogg_stream_clear(&tmp->os);
254                         vorbis_block_clear(&tmp->vb);
255                         vorbis_dsp_clear(&tmp->vd);
256                         vorbis_comment_clear(&tmp->vc);
257                         vorbis_info_clear(&tmp->vi);
258                         ogg_sync_clear(&tmp->oy);
259                         free(tmp);
260                         return NULL;
261                 }
262                 glistcnt++;
263                 ast_mutex_unlock(&ogg_vorbis_lock);
264                 ast_update_use_count();
265         }
266         return tmp;
267 }
268
269 /*!
270  * \brief Create a new OGG/Vorbis filestream and set it up for writing.
271  * \param f File pointer that points to on-disk storage.
272  * \param comment Comment that should be embedded in the OGG/Vorbis file.
273  * \return A new filestream.
274  */
275 static struct ast_filestream *ogg_vorbis_rewrite(FILE *f, const char *comment)
276 {
277         ogg_packet header;
278         ogg_packet header_comm;
279         ogg_packet header_code;
280
281         struct ast_filestream *tmp;
282
283         if((tmp = malloc(sizeof(struct ast_filestream)))) {
284                 memset(tmp, 0, sizeof(struct ast_filestream));
285
286                 tmp->writing = 1;
287                 tmp->f = f;
288
289                 vorbis_info_init(&tmp->vi);
290
291                 if(vorbis_encode_init_vbr(&tmp->vi, 1, 8000, 0.4)) {
292                         ast_log(LOG_ERROR, "Unable to initialize Vorbis encoder!\n");
293                         free(tmp);
294                         return NULL;
295                 }
296
297                 vorbis_comment_init(&tmp->vc);
298                 vorbis_comment_add_tag(&tmp->vc, "ENCODER", "Asterisk PBX");
299                 if(comment)
300                         vorbis_comment_add_tag(&tmp->vc, "COMMENT", (char *) comment);
301
302                 vorbis_analysis_init(&tmp->vd, &tmp->vi);
303                 vorbis_block_init(&tmp->vd, &tmp->vb);
304
305                 ogg_stream_init(&tmp->os, rand());
306
307                 vorbis_analysis_headerout(&tmp->vd, &tmp->vc, &header, &header_comm, &header_code);
308                 ogg_stream_packetin(&tmp->os, &header);                                                 
309                 ogg_stream_packetin(&tmp->os, &header_comm);
310                 ogg_stream_packetin(&tmp->os, &header_code);
311
312                 while(!tmp->eos) {
313                         if(ogg_stream_flush(&tmp->os, &tmp->og) == 0)
314                                 break;
315                         fwrite(tmp->og.header, 1, tmp->og.header_len, tmp->f);
316                         fwrite(tmp->og.body, 1, tmp->og.body_len, tmp->f);
317                         if(ogg_page_eos(&tmp->og))
318                                 tmp->eos = 1;
319                 }
320
321                 if(ast_mutex_lock(&ogg_vorbis_lock)) {
322                         ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
323                         fclose(f);
324                         ogg_stream_clear(&tmp->os);
325                         vorbis_block_clear(&tmp->vb);
326                         vorbis_dsp_clear(&tmp->vd);
327                         vorbis_comment_clear(&tmp->vc);
328                         vorbis_info_clear(&tmp->vi);
329                         free(tmp);
330                         return NULL;
331                 }
332                 glistcnt++;
333                 ast_mutex_unlock(&ogg_vorbis_lock);
334                 ast_update_use_count();
335         }
336         return tmp;
337 }
338
339 /*!
340  * \brief Write out any pending encoded data.
341  * \param s A OGG/Vorbis filestream.
342  */
343 static void write_stream(struct ast_filestream *s)
344 {
345         while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) {
346                 vorbis_analysis(&s->vb, NULL);
347                 vorbis_bitrate_addblock(&s->vb);
348                 
349                 while (vorbis_bitrate_flushpacket(&s->vd, &s->op)) {
350                         ogg_stream_packetin(&s->os, &s->op);
351                         while (!s->eos) {
352                                 if(ogg_stream_pageout(&s->os, &s->og) == 0) {
353                                         break;
354                                 }
355                                 fwrite(s->og.header, 1, s->og.header_len, s->f);
356                                 fwrite(s->og.body, 1, s->og.body_len, s->f);
357                                 if(ogg_page_eos(&s->og)) {
358                                         s->eos = 1;
359                                 }
360                         }
361                 }
362         }
363 }
364
365 /*!
366  * \brief Write audio data from a frame to an OGG/Vorbis filestream.
367  * \param s A OGG/Vorbis filestream.
368  * \param f An frame containing audio to be written to the filestream.
369  * \return -1 ifthere was an error, 0 on success.
370  */
371 static int ogg_vorbis_write(struct ast_filestream *s, struct ast_frame *f)
372 {
373         int i;
374         float **buffer;
375         short *data;
376
377         if(!s->writing) {
378                 ast_log(LOG_ERROR, "This stream is not set up for writing!\n");
379                 return -1;
380         }
381
382         if(f->frametype != AST_FRAME_VOICE) {
383                 ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
384                 return -1;
385         }
386         if(f->subclass != AST_FORMAT_SLINEAR) {
387                 ast_log(LOG_WARNING, "Asked to write non-SLINEAR frame (%d)!\n", f->subclass);
388                 return -1;
389         }
390         if(!f->datalen)
391                 return -1;
392
393         data = (short *) f->data;
394
395         buffer = vorbis_analysis_buffer(&s->vd, f->samples);
396
397         for (i = 0; i < f->samples; i++) {
398                 buffer[0][i] = data[i]/32768.f;
399         }
400
401         vorbis_analysis_wrote(&s->vd, f->samples);
402
403         write_stream(s);
404
405         return 0;
406 }
407
408 /*!
409  * \brief Close a OGG/Vorbis filestream.
410  * \param s A OGG/Vorbis filestream.
411  */
412 static void ogg_vorbis_close(struct ast_filestream *s)
413 {
414         if(ast_mutex_lock(&ogg_vorbis_lock)) {
415                 ast_log(LOG_WARNING, "Unable to lock ogg_vorbis list\n");
416                 return;
417         }
418         glistcnt--;
419         ast_mutex_unlock(&ogg_vorbis_lock);
420         ast_update_use_count();
421
422         if(s->writing) {
423                 /* Tell the Vorbis encoder that the stream is finished
424                  * and write out the rest of the data */
425                 vorbis_analysis_wrote(&s->vd, 0);
426                 write_stream(s);
427         }
428
429         ogg_stream_clear(&s->os);
430         vorbis_block_clear(&s->vb);
431         vorbis_dsp_clear(&s->vd);
432         vorbis_comment_clear(&s->vc);
433         vorbis_info_clear(&s->vi);
434
435         if(s->writing) {
436                 ogg_sync_clear(&s->oy);
437         }
438         
439         fclose(s->f);
440         free(s);
441 }
442
443 /*!
444  * \brief Get audio data.
445  * \param s An OGG/Vorbis filestream.
446  * \param pcm Pointer to a buffere to store audio data in.
447  */
448
449 static int read_samples(struct ast_filestream *s, float ***pcm)
450 {
451         int samples_in;
452         int result;
453         char *buffer;
454         int bytes;
455
456         while (1) {
457                 samples_in = vorbis_synthesis_pcmout(&s->vd, pcm);
458                 if(samples_in > 0) {
459                         return samples_in;
460                 }
461                 
462                 /* The Vorbis decoder needs more data... */
463                 /* See ifOGG has any packets in the current page for the Vorbis decoder. */
464                 result = ogg_stream_packetout(&s->os, &s->op);
465                 if(result > 0) {
466                         /* Yes OGG had some more packets for the Vorbis decoder. */
467                         if(vorbis_synthesis(&s->vb, &s->op) == 0) {
468                                 vorbis_synthesis_blockin(&s->vd, &s->vb);
469                         }
470                         
471                         continue;
472                 }
473
474                 if(result < 0)
475                         ast_log(LOG_WARNING, "Corrupt or missing data at this page position; continuing...\n");
476                 
477                 /* No more packets left in the current page... */
478
479                 if(s->eos) {
480                         /* No more pages left in the stream */
481                         return -1;
482                 }
483
484                 while (!s->eos) {
485                         /* See ifOGG has any pages in it's internal buffers */
486                         result = ogg_sync_pageout(&s->oy, &s->og);
487                         if(result > 0) {
488                                 /* Yes, OGG has more pages in it's internal buffers,
489                                    add the page to the stream state */
490                                 result = ogg_stream_pagein(&s->os, &s->og);
491                                 if(result == 0) {
492                                         /* Yes, got a new,valid page */
493                                         if(ogg_page_eos(&s->og)) {
494                                                 s->eos = 1;
495                                         }
496                                         break;
497                                 }
498                                 ast_log(LOG_WARNING, "Invalid page in the bitstream; continuing...\n");
499                         }
500                         
501                         if(result < 0)
502                                 ast_log(LOG_WARNING, "Corrupt or missing data in bitstream; continuing...\n");
503
504                         /* No, we need to read more data from the file descrptor */
505                         /* get a buffer from OGG to read the data into */
506                         buffer = ogg_sync_buffer(&s->oy, BLOCK_SIZE);
507                         /* read more data from the file descriptor */
508                         bytes = fread(buffer, 1, BLOCK_SIZE, s->f);
509                         /* Tell OGG how many bytes we actually read into the buffer */
510                         ogg_sync_wrote(&s->oy, bytes);
511                         if(bytes == 0) {
512                                 s->eos = 1;
513                         }
514                 }
515         }
516 }
517
518 /*!
519  * \brief Read a frame full of audio data from the filestream.
520  * \param s The filestream.
521  * \param whennext Number of sample times to schedule the next call.
522  * \return A pointer to a frame containing audio data or NULL ifthere is no more audio data.
523  */
524 static struct ast_frame *ogg_vorbis_read(struct ast_filestream *s, int *whennext)
525 {
526         int clipflag = 0;
527         int i;
528         int j;
529         float **pcm;
530         float *mono;
531         double accumulator[SAMPLES_MAX];
532         int val;
533         int samples_in;
534         int samples_out = 0;
535
536         while (1) {
537                 /* See ifwe have filled up an audio frame yet */
538                 if(samples_out == SAMPLES_MAX)
539                         break;
540
541                 /* See ifVorbis decoder has some audio data for us ... */
542                 samples_in = read_samples(s, &pcm);
543                 if(samples_in <= 0)
544                         break;
545
546                 /* Got some audio data from Vorbis... */
547                 /* Convert the float audio data to 16-bit signed linear */
548                 
549                 clipflag = 0;
550
551                 samples_in = samples_in < (SAMPLES_MAX - samples_out) ? samples_in : (SAMPLES_MAX - samples_out);
552   
553                 for(j = 0; j < samples_in; j++)
554                         accumulator[j] = 0.0;
555
556                 for(i = 0; i < s->vi.channels; i++) {
557                         mono = pcm[i];
558                         for (j = 0; j < samples_in; j++) {
559                                 accumulator[j] += mono[j];
560                         }
561                 }
562
563                 for (j = 0; j < samples_in; j++) {
564                         val =  accumulator[j] * 32767.0 / s->vi.channels;
565                         if(val > 32767) {
566                                 val = 32767;
567                                 clipflag = 1;
568                         }
569                         if(val < -32768) {
570                                 val = -32768;
571                                 clipflag = 1;
572                         }
573                         s->buffer[samples_out + j] = val;
574                 }
575                         
576                 if(clipflag)
577                         ast_log(LOG_WARNING, "Clipping in frame %ld\n", (long)(s->vd.sequence));
578                 
579                 /* Tell the Vorbis decoder how many samples we actually used. */
580                 vorbis_synthesis_read(&s->vd, samples_in);
581                 samples_out += samples_in;
582         }
583
584         if(samples_out > 0) {
585                 s->fr.frametype = AST_FRAME_VOICE;
586                 s->fr.subclass = AST_FORMAT_SLINEAR;
587                 s->fr.offset = AST_FRIENDLY_OFFSET;
588                 s->fr.datalen = samples_out * 2;
589                 s->fr.data = s->buffer;
590                 s->fr.src = name;
591                 s->fr.mallocd = 0;
592                 s->fr.samples = samples_out;
593                 *whennext = samples_out;
594                 
595                 return &s->fr;
596         } else {
597                 return NULL;
598         }
599 }
600
601 /*!
602  * \brief Trucate an OGG/Vorbis filestream.
603  * \param s The filestream to truncate.
604  * \return 0 on success, -1 on failure.
605  */
606
607 static int ogg_vorbis_trunc(struct ast_filestream *s)
608 {
609         ast_log(LOG_WARNING, "Truncation is not supported on OGG/Vorbis streams!\n");
610         return -1;
611 }
612
613 /*!
614  * \brief Seek to a specific position in an OGG/Vorbis filestream.
615  * \param s The filestream to truncate.
616  * \param sample_offset New position for the filestream, measured in 8KHz samples.
617  * \param whence Location to measure 
618  * \return 0 on success, -1 on failure.
619  */
620
621 static int ogg_vorbis_seek(struct ast_filestream *s, long sample_offset, int whence) {
622         ast_log(LOG_WARNING, "Seeking is not supported on OGG/Vorbis streams!\n");
623         return -1;
624 }
625
626 static long ogg_vorbis_tell(struct ast_filestream *s) {
627         ast_log(LOG_WARNING, "Telling is not supported on OGG/Vorbis streams!\n");
628         return -1;
629 }
630
631 static char *ogg_vorbis_getcomment(struct ast_filestream *s) {
632         ast_log(LOG_WARNING, "Getting comments is not supported on OGG/Vorbis streams!\n");
633         return NULL;
634 }
635
636 int load_module()
637 {
638         return ast_format_register(name, exts, AST_FORMAT_SLINEAR,
639                                    ogg_vorbis_open,
640                                    ogg_vorbis_rewrite,
641                                    ogg_vorbis_write,
642                                    ogg_vorbis_seek,
643                                    ogg_vorbis_trunc,
644                                    ogg_vorbis_tell,
645                                    ogg_vorbis_read,
646                                    ogg_vorbis_close,
647                                    ogg_vorbis_getcomment);
648 }
649
650 int unload_module()
651 {
652         return ast_format_unregister(name);
653 }       
654
655 int usecount()
656 {
657         return glistcnt;
658 }
659
660 char *description()
661 {
662         return desc;
663 }
664
665
666 char *key()
667 {
668         return ASTERISK_GPL_KEY;
669 }
670
671 /*
672 Local Variables:
673 mode: C
674 c-file-style: "linux"
675 indent-tabs-mode: t
676 End:
677 */