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