1 /* -*- c-basic-offset: 8; -*- */
2 /* vorbis.c: Ogg Vorbis data handlers for libshout
3  * $Id$
4  *
5  *  Copyright (C) 2002-2004 the Icecast team <team@icecast.org>
6  *  Copyright (C) 2015-2019 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Library General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Library General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Library General Public
19  *  License along with this library; if not, write to the Free
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #   include <config.h>
25 #endif
26 
27 #ifdef HAVE_INTTYPES_H
28 #   include <inttypes.h>
29 #endif
30 #include <stdlib.h>
31 
32 #include <vorbis/codec.h>
33 
34 #include "shout_private.h"
35 #include "format_ogg.h"
36 
37 /* -- local data structures -- */
38 typedef struct {
39     vorbis_info     vi;
40     vorbis_comment  vc;
41     int             prevW;
42 } vorbis_data_t;
43 
44 /* -- local prototypes -- */
45 static int  read_vorbis_page(ogg_codec_t *codec, ogg_page *page);
46 static void free_vorbis_data(void *codec_data);
47 static int  vorbis_blocksize(vorbis_data_t *vd, ogg_packet *p);
48 
49 /* -- vorbis functions -- */
_shout_open_vorbis(ogg_codec_t * codec,ogg_page * page)50 int _shout_open_vorbis(ogg_codec_t *codec, ogg_page *page)
51 {
52     vorbis_data_t *vorbis_data = calloc(1, sizeof(vorbis_data_t));
53     ogg_packet packet;
54 
55     (void)page;
56 
57 	if (!vorbis_data)
58         return SHOUTERR_MALLOC;
59 
60     vorbis_info_init(&vorbis_data->vi);
61     vorbis_comment_init(&vorbis_data->vc);
62 
63     ogg_stream_packetout(&codec->os, &packet);
64 
65     if (vorbis_synthesis_headerin(&vorbis_data->vi, &vorbis_data->vc, &packet) < 0) {
66         free_vorbis_data(vorbis_data);
67         return SHOUTERR_UNSUPPORTED;
68     }
69 
70     codec->codec_data   = vorbis_data;
71     codec->read_page    = read_vorbis_page;
72     codec->free_data    = free_vorbis_data;
73 
74     return SHOUTERR_SUCCESS;
75 }
76 
read_vorbis_page(ogg_codec_t * codec,ogg_page * page)77 static int read_vorbis_page(ogg_codec_t *codec, ogg_page *page)
78 {
79     ogg_packet      packet;
80     vorbis_data_t  *vorbis_data = codec->codec_data;
81     uint64_t        samples = 0;
82     (void)          page;
83 
84     if (codec->headers < 3) {
85         while (ogg_stream_packetout(&codec->os, &packet) > 0) {
86 			if (vorbis_synthesis_headerin(&vorbis_data->vi, &vorbis_data->vc, &packet) < 0)
87                 return SHOUTERR_INSANE;
88             codec->headers++;
89         }
90 
91         return SHOUTERR_SUCCESS;
92     }
93 
94     while (ogg_stream_packetout(&codec->os, &packet) > 0) {
95         samples += vorbis_blocksize(vorbis_data, &packet);
96     }
97 
98     codec->senttime += ((samples * 1000000) / vorbis_data->vi.rate);
99 
100     return SHOUTERR_SUCCESS;
101 }
102 
free_vorbis_data(void * codec_data)103 static void free_vorbis_data(void *codec_data)
104 {
105     vorbis_data_t *vorbis_data = (vorbis_data_t*)codec_data;
106 
107     vorbis_info_clear(&vorbis_data->vi);
108     vorbis_comment_clear(&vorbis_data->vc);
109     free(vorbis_data);
110 }
111 
vorbis_blocksize(vorbis_data_t * vd,ogg_packet * p)112 static int vorbis_blocksize(vorbis_data_t *vd, ogg_packet *p)
113 {
114     int this = vorbis_packet_blocksize(&vd->vi, p);
115     int ret  = (this + vd->prevW) / 4;
116 
117     if (!vd->prevW) {
118         vd->prevW = this;
119         return 0;
120     }
121 
122     vd->prevW = this;
123     return ret;
124 }
125