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