1 /* Icecast
2  *
3  *  This program is distributed under the GNU General Public License, version 2.
4  *  A copy of this license is included with this source.
5  *
6  * Copyright 2000-2004, Jack Moffitt <jack@xiph.org>,
7  *                      Michael Smith <msmith@xiph.org>,
8  *                      oddsock <oddsock@xiph.org>,
9  *                      Karl Heyes <karl@xiph.org>
10  *                      and others (see AUTHORS for details).
11  */
12 
13 
14 /* Ogg codec handler for speex streams */
15 
16 #ifdef HAVE_CONFIG_H
17 #include <config.h>
18 #endif
19 
20 #include <stdlib.h>
21 #include <ogg/ogg.h>
22 #include <speex/speex_header.h>
23 
24 typedef struct source_tag source_t;
25 
26 #include "format_speex.h"
27 #include "refbuf.h"
28 #include "client.h"
29 
30 #define CATMODULE "format-speex"
31 #include "logging.h"
32 
speex_codec_free(ogg_state_t * ogg_info,ogg_codec_t * codec)33 static void speex_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec)
34 {
35     ogg_stream_clear (&codec->os);
36     free (codec);
37 }
38 
39 
process_speex_page(ogg_state_t * ogg_info,ogg_codec_t * codec,ogg_page * page)40 static refbuf_t *process_speex_page (ogg_state_t *ogg_info,
41         ogg_codec_t *codec, ogg_page *page)
42 {
43     refbuf_t *refbuf;
44 
45     if (codec->headers < 2)
46     {
47         ogg_packet packet;
48 
49         ogg_stream_pagein (&codec->os, page);
50         while (ogg_stream_packetout (&codec->os, &packet) > 0)
51         {
52            /* first time around (normal case) yields comments */
53            codec->headers++;
54         }
55         /* add header page to associated list */
56         format_ogg_attach_header (ogg_info, page);
57         return NULL;
58     }
59     refbuf = make_refbuf_with_page (page);
60     return refbuf;
61 }
62 
63 
initial_speex_page(format_plugin_t * plugin,ogg_page * page)64 ogg_codec_t *initial_speex_page (format_plugin_t *plugin, ogg_page *page)
65 {
66     ogg_state_t *ogg_info = plugin->_state;
67     ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t));
68     ogg_packet packet;
69     SpeexHeader *header;
70 
71     ogg_stream_init (&codec->os, ogg_page_serialno (page));
72     ogg_stream_pagein (&codec->os, page);
73 
74     ogg_stream_packetout (&codec->os, &packet);
75 
76     /* Check for te first packet to be at least of the minimal size for a Speex header.
77      * The header size is 80 bytes as per specs. You can find the specs here:
78      * https://speex.org/docs/manual/speex-manual/node8.html#SECTION00830000000000000000
79      *
80      * speex_packet_to_header() will also check the header size for us. However
81      * that function generates noise on stderr in case the header is too short.
82      * This is dangerous as we may have closed stderr already and the handle may be use
83      * again for something else.
84      */
85     if (packet.bytes < 80) {
86         return NULL;
87     }
88 
89     ICECAST_LOG_DEBUG("checking for speex codec");
90     header = speex_packet_to_header ((char*)packet.packet, packet.bytes);
91     if (header == NULL)
92     {
93         ogg_stream_clear (&codec->os);
94         free (header);
95         free (codec);
96         return NULL;
97     }
98     ICECAST_LOG_INFO("seen initial speex header");
99     codec->process_page = process_speex_page;
100     codec->codec_free = speex_codec_free;
101     codec->headers = 1;
102     format_ogg_attach_header (ogg_info, page);
103     free (header);
104     return codec;
105 }
106