blob: a9b333b9a6087da17ff82c211ed3c3598f304674 [file] [log] [blame]
Dan Evertonebc58c92007-02-09 10:06:53 +00001/**************************************************************************
Dan Evertonebc58c92007-02-09 10:06:53 +00002 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 * Copyright (C) 2006 Frederik M.J. Vestre
10 * Based on vorbis.c codec interface:
11 * Copyright (C) 2002 Bjrn Stenberg
12 *
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
15 *
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
18 *
19 ***************************************************************************/
Dave Chapman0abfe9f2007-02-09 18:10:24 +000020
Dan Evertonebc58c92007-02-09 10:06:53 +000021#include "libspeex/speex/ogg.h"
22#include "libspeex/speex/speex.h"
Dan Everton7bf62e82007-02-10 11:44:26 +000023#include "libspeex/speex/speex_callbacks.h"
Dan Evertonebc58c92007-02-09 10:06:53 +000024#include "libspeex/speex/speex_header.h"
25#include "libspeex/speex/speex_stereo.h"
Magnus Holmgren2c7030b2007-02-10 13:33:29 +000026#include "libspeex/speex/speex_config_types.h"
Dan Evertonebc58c92007-02-09 10:06:53 +000027#include "codeclib.h"
Dave Chapman0abfe9f2007-02-09 18:10:24 +000028
Dan Evertonebc58c92007-02-09 10:06:53 +000029#define MAX_FRAME_SIZE 2000
30#define CHUNKSIZE 10000 /*2kb*/
31#define SEEK_CHUNKSIZE 7*CHUNKSIZE
Dan Evertonebc58c92007-02-09 10:06:53 +000032
33//#define LOGF(...)
34
35CODEC_HEADER
36
37struct codec_api *rb;
38
Dave Chapman0abfe9f2007-02-09 18:10:24 +000039int get_more_data(spx_ogg_sync_state *oy,struct codec_api *rb)
40{
Dan Evertonebc58c92007-02-09 10:06:53 +000041 int bytes;
42 char *buffer;
Dave Chapman0abfe9f2007-02-09 18:10:24 +000043
44 buffer = (char *)spx_ogg_sync_buffer(oy,CHUNKSIZE);
45
46 bytes = rb->read_filebuf(buffer, sizeof(char)*CHUNKSIZE);
47
Dan Evertonebc58c92007-02-09 10:06:53 +000048 spx_ogg_sync_wrote(oy,bytes);
Dave Chapman0abfe9f2007-02-09 18:10:24 +000049
Dan Evertonebc58c92007-02-09 10:06:53 +000050 return bytes;
51}
Dave Chapman0abfe9f2007-02-09 18:10:24 +000052
Dan Evertonebc58c92007-02-09 10:06:53 +000053/* The read/seek functions track absolute position within the stream */
54
55static spx_int64_t get_next_page(spx_ogg_sync_state *oy,spx_ogg_page *og,
Dave Chapman0abfe9f2007-02-09 18:10:24 +000056 spx_int64_t boundary,struct codec_api *rb)
57{
58 spx_int64_t localoffset = rb->curpos;
59 long more;
60 long ret;
61
62 if (boundary > 0)
63 boundary += rb->curpos;
64
65 while (1) {
66 more = spx_ogg_sync_pageseek(oy,og);
67
68 if (more < 0) {
Dan Evertonebc58c92007-02-09 10:06:53 +000069 /* skipped n bytes */
70 localoffset-=more;
Dave Chapman0abfe9f2007-02-09 18:10:24 +000071 } else {
72 if (more == 0) {
Dan Evertonebc58c92007-02-09 10:06:53 +000073 /* send more paramedics */
74 if(!boundary)return(-1);
75 {
Dave Chapman0abfe9f2007-02-09 18:10:24 +000076 ret = get_more_data(oy,rb);
77 if (ret == 0)
Dan Evertonebc58c92007-02-09 10:06:53 +000078 return(-2);
Dave Chapman0abfe9f2007-02-09 18:10:24 +000079
80 if (ret < 0)
Dan Evertonebc58c92007-02-09 10:06:53 +000081 return(-3);
82 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +000083 } else {
Dan Evertonebc58c92007-02-09 10:06:53 +000084 /* got a page. Return the offset at the page beginning,
Dave Chapman0abfe9f2007-02-09 18:10:24 +000085 advance the internal offset past the page end */
86
Dan Evertonebc58c92007-02-09 10:06:53 +000087 spx_int64_t ret=localoffset;
Dave Chapman0abfe9f2007-02-09 18:10:24 +000088
Dan Evertonebc58c92007-02-09 10:06:53 +000089 return(ret);
90 }
91 }
92 }
93}
94
Dave Chapman0abfe9f2007-02-09 18:10:24 +000095static spx_int64_t seek_backwards(spx_ogg_sync_state *oy, spx_ogg_page *og,
96 spx_int64_t wantedpos,
97 struct codec_api *rb)
98{
Dan Evertonebc58c92007-02-09 10:06:53 +000099 spx_int64_t crofs;
100 spx_int64_t *curoffset=&crofs;
101 *curoffset=rb->curpos;
102 spx_int64_t begin=*curoffset;
103 spx_int64_t end=begin;
104 spx_int64_t ret;
105 spx_int64_t offset=-1;
106 spx_int64_t avgpagelen=-1;
107 spx_int64_t lastgranule=-1;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000108
109 short time = -1;
110
111 while (offset == -1) {
112
113 begin -= SEEK_CHUNKSIZE;
114
115 if (begin < 0) {
116 if (time < 0) {
117 begin = 0;
Dan Evertonebc58c92007-02-09 10:06:53 +0000118 time++;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000119 } else {
Dan Evertonebc58c92007-02-09 10:06:53 +0000120 LOGF("Can't seek that early:%d\n",begin);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000121 return -3; /* too early */
Dan Evertonebc58c92007-02-09 10:06:53 +0000122 }
123 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000124
125 *curoffset = begin;
126
Dan Evertonebc58c92007-02-09 10:06:53 +0000127 rb->seek_buffer(*curoffset);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000128
Dan Evertonebc58c92007-02-09 10:06:53 +0000129 spx_ogg_sync_reset(oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000130
131 lastgranule = -1;
132
133 while (*curoffset < end) {
134 ret = get_next_page(oy,og,end-*curoffset,rb);
135
136 if (ret > 0) {
137 if (lastgranule != -1) {
138 if (avgpagelen < 0)
139 avgpagelen = (spx_ogg_page_granulepos(og)-lastgranule);
Dan Evertonebc58c92007-02-09 10:06:53 +0000140 else
141 avgpagelen=((spx_ogg_page_granulepos(og)-lastgranule)
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000142 + avgpagelen) / 2;
Dan Evertonebc58c92007-02-09 10:06:53 +0000143 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000144
Dan Evertonebc58c92007-02-09 10:06:53 +0000145 lastgranule=spx_ogg_page_granulepos(og);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000146
147 if ((lastgranule - (avgpagelen/4)) < wantedpos &&
148 (lastgranule + avgpagelen + (avgpagelen/4)) > wantedpos) {
149
Dan Evertonebc58c92007-02-09 10:06:53 +0000150 /*wanted offset found Yeay!*/
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000151
152 /*LOGF("GnPagefound:%d,%d,%d,%d\n",ret,
153 lastgranule,wantedpos,avgpagelen);*/
154
Dan Evertonebc58c92007-02-09 10:06:53 +0000155 return ret;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000156
157 } else if (lastgranule > wantedpos) { /*too late, seek more*/
158 if (offset != -1) {
Dan Evertonebc58c92007-02-09 10:06:53 +0000159 LOGF("Toolate, returnanyway:%d,%d,%d,%d\n",
160 ret,lastgranule,wantedpos,avgpagelen);
161 return ret;
162 }
163 break;
164 } else{ /*if (spx_ogg_page_granulepos(&og)<wantedpos)*/
165 /*too early*/
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000166 offset = ret;
Dan Evertonebc58c92007-02-09 10:06:53 +0000167 continue;
168 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000169 } else if (ret == -3)
170 return(-3);
171 else if (ret<=0)
Dan Evertonebc58c92007-02-09 10:06:53 +0000172 break;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000173 else if (*curoffset < end) {
Dan Evertonebc58c92007-02-09 10:06:53 +0000174 /*this should not be possible*/
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000175
Dan Evertonebc58c92007-02-09 10:06:53 +0000176 //LOGF("Seek:get_earlier_page:Offset:not_cached by granule:"\"%d,%d,%d,%d,%d\n",*curoffset,end,begin,wantedpos,curpos);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000177
Dan Evertonebc58c92007-02-09 10:06:53 +0000178 offset=ret;
179 }
180 }
181 }
182 return -1;
183}
184
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000185int speex_seek_page_granule(spx_int64_t pos, spx_int64_t curpos,
186 spx_ogg_sync_state *oy,
187 spx_int64_t headerssize,
188 struct codec_api *rb)
189{
Dan Evertonebc58c92007-02-09 10:06:53 +0000190 /* TODO: Someone may want to try to implement seek to packet,
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000191 instead of just to page (should be more accurate, not be any
192 faster) */
193
Dan Evertonebc58c92007-02-09 10:06:53 +0000194 spx_int64_t crofs;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000195 spx_int64_t *curbyteoffset = &crofs;
196 *curbyteoffset = rb->curpos;
Dan Evertonebc58c92007-02-09 10:06:53 +0000197 spx_int64_t curoffset;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000198 curoffset = *curbyteoffset;
199 spx_int64_t offset = 0;
200 spx_ogg_page og = {0,0,0,0};
201 spx_int64_t avgpagelen = -1;
202 spx_int64_t lastgranule = -1;
203
204 if(abs(pos-curpos)>10000 && headerssize>0 && curoffset-headerssize>10000) {
205 /* if seeking for more that 10sec,
206 headersize is known & more than 10kb is played,
207 try to guess a place to seek from the number of
208 bytes playe for this position, this works best when
209 the bitrate is relativly constant.
210 */
211
212 curoffset = (int)((((float)(*curbyteoffset-(headerssize)) *
213 (float)pos)/(float)curpos)*0.98);
214
215 if (curoffset < 0)
Dan Evertonebc58c92007-02-09 10:06:53 +0000216 curoffset=0;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000217
Dan Evertonebc58c92007-02-09 10:06:53 +0000218 //spx_int64_t toffset=curoffset;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000219
Dan Evertonebc58c92007-02-09 10:06:53 +0000220 rb->seek_buffer(curoffset);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000221
Dan Evertonebc58c92007-02-09 10:06:53 +0000222 spx_ogg_sync_reset(oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000223
224 offset = get_next_page(oy,&og,-1,rb);
225
226 if (offset < 0) { /* could not find new page,use old offset */
227 LOGF("Seek/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
228 curpos,0,pos,offset,0,
229 rb->curpos,/*stream_length*/0);
230
231 curoffset = *curbyteoffset;
232
Dan Evertonebc58c92007-02-09 10:06:53 +0000233 rb->seek_buffer(curoffset);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000234
Dan Evertonebc58c92007-02-09 10:06:53 +0000235 spx_ogg_sync_reset(oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000236 } else {
237 if (spx_ogg_page_granulepos(&og) == 0 && pos > 5000) {
238 LOGF("SEEK/guess/fault:%d->-<-%d,%d:%d,%d,%d\n",
239 curpos,spx_ogg_page_granulepos(&og),pos,
240 offset,0,rb->curpos,/*stream_length*/0);
241
242 curoffset = *curbyteoffset;
243
Dan Evertonebc58c92007-02-09 10:06:53 +0000244 rb->seek_buffer(curoffset);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000245
Dan Evertonebc58c92007-02-09 10:06:53 +0000246 spx_ogg_sync_reset(oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000247 } else {
248 curoffset = offset;
249 curpos = spx_ogg_page_granulepos(&og);
Dan Evertonebc58c92007-02-09 10:06:53 +0000250 }
251 }
252 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000253
254 /* which way do we want to seek? */
255
256 if (curpos > pos) { /* backwards */
257 offset = seek_backwards(oy,&og,pos,rb);
258
259 if (offset > 0) {
260 *curbyteoffset = curoffset;
Dan Evertonebc58c92007-02-09 10:06:53 +0000261 return 1;
262 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000263 } else { /* forwards */
264
265 while ( (offset = get_next_page(oy,&og,-1,rb)) > 0) {
266 if (lastgranule != -1) {
267 if (avgpagelen < 0)
268 avgpagelen = (spx_ogg_page_granulepos(&og) - lastgranule);
269 else
270 avgpagelen = ((spx_ogg_page_granulepos(&og) - lastgranule)
271 + avgpagelen) / 2;
Dan Evertonebc58c92007-02-09 10:06:53 +0000272 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000273
274 lastgranule = spx_ogg_page_granulepos(&og);
275
276 if ( ((lastgranule - (avgpagelen/4)) < pos && ( lastgranule +
277 avgpagelen + (avgpagelen / 4)) > pos) ||
278 lastgranule > pos) {
279
Dan Evertonebc58c92007-02-09 10:06:53 +0000280 /*wanted offset found Yeay!*/
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000281
282 *curbyteoffset = offset;
283
Dan Evertonebc58c92007-02-09 10:06:53 +0000284 return offset;
285 }
286 }
287 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000288
Dan Evertonebc58c92007-02-09 10:06:53 +0000289 rb->seek_buffer(*curbyteoffset);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000290
Dan Evertonebc58c92007-02-09 10:06:53 +0000291 spx_ogg_sync_reset(oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000292
293 LOGF("Seek failed:%d\n", offset);
294
Dan Evertonebc58c92007-02-09 10:06:53 +0000295 rb->splash(HZ*2, true, "Seek failed");
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000296
Dan Evertonebc58c92007-02-09 10:06:53 +0000297 return -1;
298}
299
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000300static void *process_header(spx_ogg_packet *op,
301 int enh_enabled,
302 int *frame_size,
303 int *rate,
304 int *nframes,
305 int *channels,
306 SpeexStereoState *stereo,
307 int *extra_headers
308 )
309{
Dan Evertonebc58c92007-02-09 10:06:53 +0000310 void *st;
311 const SpeexMode *mode;
312 SpeexHeader *header;
313 int modeID;
314 SpeexCallback callback;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000315
Dan Evertonebc58c92007-02-09 10:06:53 +0000316 header = speex_packet_to_header((char*)op->packet, op->bytes);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000317
Dan Evertonebc58c92007-02-09 10:06:53 +0000318 if (!header){
319 DEBUGF ("Cannot read header\n");
320 return NULL;
321 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000322
Dan Evertonebc58c92007-02-09 10:06:53 +0000323 if (header->mode >= SPEEX_NB_MODES){
324 DEBUGF ("Mode does not exist\n");
325 return NULL;
326 }
327
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000328 modeID = header->mode;
Dan Evertonebc58c92007-02-09 10:06:53 +0000329
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000330 mode = speex_lib_get_mode (modeID);
331
332 if (header->speex_version_id > 1) {
333 DEBUGF("Undecodeable bitstream");
334 return NULL;
335 }
336
337 if (mode->bitstream_version < header->mode_bitstream_version){
338 DEBUGF("Undecodeable bitstream, newer bitstream");
339 return NULL;
340 }
341
342 if (mode->bitstream_version > header->mode_bitstream_version){
343 DEBUGF("Too old bitstream");
344 return NULL;
345 }
Dan Evertonebc58c92007-02-09 10:06:53 +0000346
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000347 st = speex_decoder_init(mode);
348 if (!st){
349 DEBUGF("Decoder init failed");
350 return NULL;
351 }
352 speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
353 speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
Dan Evertonebc58c92007-02-09 10:06:53 +0000354
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000355 if (*channels==-1)
356 *channels = header->nb_channels;
Dan Evertonebc58c92007-02-09 10:06:53 +0000357
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000358 if (!(*channels==1)){
359 callback.callback_id = SPEEX_INBAND_STEREO;
360 callback.func = speex_std_stereo_request_handler;
361 callback.data = stereo;
362 speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
363 }
364 if (!*rate)
365 *rate = header->rate;
Dan Evertonebc58c92007-02-09 10:06:53 +0000366
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000367 speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
Dan Evertonebc58c92007-02-09 10:06:53 +0000368
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000369 *nframes = header->frames_per_packet;
Dan Evertonebc58c92007-02-09 10:06:53 +0000370
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000371 if (*channels == 2) {
Michael Sevakis97f369a2007-02-10 16:34:16 +0000372 rb->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000373 } else if (*channels == 1) {
Michael Sevakis97f369a2007-02-10 16:34:16 +0000374 rb->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000375 }
Dan Evertonebc58c92007-02-09 10:06:53 +0000376
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000377 *extra_headers = header->extra_headers;
Dan Evertonebc58c92007-02-09 10:06:53 +0000378
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000379 codec_free(header);
380 return st;
Dan Evertonebc58c92007-02-09 10:06:53 +0000381}
382
Dan Evertonebc58c92007-02-09 10:06:53 +0000383/* this is the codec entry point */
Dan Evertonc22e29f2007-02-09 10:20:27 +0000384enum codec_status codec_main(void)
Dan Evertonebc58c92007-02-09 10:06:53 +0000385{
386 SpeexBits vf;
387 int error;
388 int eof;
389 spx_ogg_sync_state oy;
390 spx_ogg_page og;
391 spx_ogg_packet op;
392 spx_ogg_stream_state os;
393 spx_int64_t page_granule=0, cur_granule=0;
394 int enh_enabled;
395 int nframes=2;
396 int eos=0;
397 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
398 int channels=-1;
399 int rate=0,samplerate=0;
400 int extra_headers;
401 int stream_init=0;
402 int page_nb_packets,frame_size,packet_count=0;
403 int lookahead;
404 int headerssize=-1;
405 unsigned long strtoffset;
406 short output[MAX_FRAME_SIZE];
407 enh_enabled = 1;
408 void *st=0;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000409 int j;
Dan Evertonebc58c92007-02-09 10:06:53 +0000410 rb = ci;
411
Michael Sevakis97f369a2007-02-10 16:34:16 +0000412 //rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, CHUNKSIZE*128);
413 //rb->configure(DSP_DITHER, false);
414 rb->configure(DSP_SET_SAMPLE_DEPTH, 16);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000415
Dan Evertonebc58c92007-02-09 10:06:53 +0000416 /* We need to flush reserver memory every track load. */
417next_track:
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000418
Dan Evertonebc58c92007-02-09 10:06:53 +0000419 if (codec_init()) {
420 error = CODEC_ERROR;
421 goto exit;
422 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000423
Dan Evertonebc58c92007-02-09 10:06:53 +0000424 strtoffset=rb->id3->offset;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000425
Dan Evertonebc58c92007-02-09 10:06:53 +0000426 while (!*rb->taginfo_ready && !rb->stop_codec)
427 rb->sleep(1);
428
Dan Evertonebc58c92007-02-09 10:06:53 +0000429 spx_ogg_sync_init(&oy);
430 spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000431
432 samplerate = rb->id3->frequency;
Dan Evertonebc58c92007-02-09 10:06:53 +0000433 codec_set_replaygain(rb->id3);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000434
Dan Evertonebc58c92007-02-09 10:06:53 +0000435 speex_bits_init(&vf);
436
437 eof = 0;
438 while (!eof) {
439 rb->yield();
440 if (rb->stop_codec || rb->new_track)
441 break;
442
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000443 /*seek (seeks to the page before the position) */
444 if (rb->seek_time) {
Dan Evertonebc58c92007-02-09 10:06:53 +0000445 if(samplerate!=0&&packet_count>1){
446 LOGF("Speex seek page:%d,%d,%d,%d\n",
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000447 ((spx_int64_t)rb->seek_time/1000) *
448 (spx_int64_t)samplerate,
449 page_granule, rb->seek_time,
450 (page_granule/samplerate)*1000, samplerate);
451
452 speex_seek_page_granule(((spx_int64_t)rb->seek_time/1000) *
453 (spx_int64_t)samplerate,
454 page_granule, &oy, headerssize, rb);
Dan Evertonebc58c92007-02-09 10:06:53 +0000455 rb->seek_complete();
456 }
457 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000458
Dan Evertonebc58c92007-02-09 10:06:53 +0000459next_page:
460 /*Get the ogg buffer for writing*/
461 if(get_more_data(&oy,rb)<1){/*read error*/
462 error=CODEC_ERROR;
463 goto done;
464 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000465
466 /* Loop for all complete pages we got (most likely only one) */
467 while (spx_ogg_sync_pageout(&oy, &og) == 1) {
Dan Evertonebc58c92007-02-09 10:06:53 +0000468 int packet_no;
469 if (stream_init == 0) {
470 spx_ogg_stream_init(&os,spx_ogg_page_serialno(&og));
471 stream_init = 1;
472 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000473
474 /* Add page to the bitstream */
Dan Evertonebc58c92007-02-09 10:06:53 +0000475 spx_ogg_stream_pagein(&os, &og);
476
477 page_granule = spx_ogg_page_granulepos(&og);
478 page_nb_packets = spx_ogg_page_packets(&og);
479
480 cur_granule = page_granule;
481
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000482 /* Extract all available packets */
Dan Evertonebc58c92007-02-09 10:06:53 +0000483 packet_no=0;
484
485 while (!eos && spx_ogg_stream_packetout(&os, &op)==1){
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000486 /* If first packet, process as Speex header */
Dan Evertonebc58c92007-02-09 10:06:53 +0000487 if (packet_count==0){
488 st = process_header(&op, enh_enabled, &frame_size,
489 &samplerate,&nframes, &channels,
490 &stereo, &extra_headers);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000491
Dan Evertonebc58c92007-02-09 10:06:53 +0000492 speex_decoder_ctl(st, SPEEX_GET_LOOKAHEAD, &lookahead);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000493
Dan Evertonebc58c92007-02-09 10:06:53 +0000494 if (!nframes)
495 nframes=1;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000496
Dan Evertonebc58c92007-02-09 10:06:53 +0000497 if (!st){
498 error=CODEC_ERROR;
499 goto exit;
500 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000501
Dan Evertonebc58c92007-02-09 10:06:53 +0000502 rb->id3->vbr = true;
503 rb->id3->frequency = samplerate;
Michael Sevakis97f369a2007-02-10 16:34:16 +0000504 rb->configure(DSP_SET_FREQUENCY, rb->id3->frequency);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000505
506 /* Speex header in its own page, add the whole page
507 headersize */
508 headerssize+=og.header_len+og.body_len;
509
Dan Evertonebc58c92007-02-09 10:06:53 +0000510 } else if (packet_count<=1+extra_headers){
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000511 /* add packet to headersize */
512 headerssize += op.bytes;
513
Dan Evertonebc58c92007-02-09 10:06:53 +0000514 /* Ignore extra headers */
515 } else {
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000516 if (packet_count <= 2+extra_headers) {
Dan Evertonebc58c92007-02-09 10:06:53 +0000517 if (strtoffset) {
518 rb->seek_buffer(strtoffset);
519 spx_ogg_sync_reset(&oy);
520 packet_count++;
521 goto next_page;
522 }
523 }
524 packet_no++;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000525
526 if (op.e_o_s) /* End of stream condition */
Dan Evertonebc58c92007-02-09 10:06:53 +0000527 eos=1;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000528
529 /* Copy Ogg packet to Speex bitstream */
530
Dan Evertonebc58c92007-02-09 10:06:53 +0000531 speex_bits_read_from(&vf, (char*)op.packet, op.bytes);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000532
533 for (j = 0; j != nframes; j++){
Dan Evertonebc58c92007-02-09 10:06:53 +0000534 int ret;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000535
536 /* Decode frame */
Dan Evertonebc58c92007-02-09 10:06:53 +0000537 ret = speex_decode_int(st, &vf, output);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000538
Dan Evertonebc58c92007-02-09 10:06:53 +0000539 if (ret==-1)
540 break;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000541
Dan Evertonebc58c92007-02-09 10:06:53 +0000542 if (ret==-2)
543 break;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000544
545 if (speex_bits_remaining(&vf) < 0)
Dan Evertonebc58c92007-02-09 10:06:53 +0000546 break;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000547
Dan Everton69c40d72007-02-10 06:11:30 +0000548 if (channels == 2)
549 speex_decode_stereo_int(output, frame_size, &stereo);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000550
Dan Everton69c40d72007-02-10 06:11:30 +0000551 int new_frame_size = frame_size;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000552
Dan Everton69c40d72007-02-10 06:11:30 +0000553 if (new_frame_size>0){
554 rb->pcmbuf_insert((const char*)output, NULL,
555 new_frame_size);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000556
Dan Everton69c40d72007-02-10 06:11:30 +0000557 /* 2 bytes/sample */
558 cur_granule += new_frame_size / 2;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000559
Dan Everton69c40d72007-02-10 06:11:30 +0000560 rb->set_offset((long)rb->curpos);
561
562 rb->set_elapsed( (samplerate==0) ? 0 :
563 cur_granule*1000/samplerate);
564 }
Dan Evertonebc58c92007-02-09 10:06:53 +0000565 }
566 }
567 packet_count++;
568 }
569 }
570 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000571
Dan Evertonebc58c92007-02-09 10:06:53 +0000572done:
573 if (rb->request_next_track()) {
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000574
Dan Evertonebc58c92007-02-09 10:06:53 +0000575 /* Clean things up for the next track */
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000576
Dan Evertonebc58c92007-02-09 10:06:53 +0000577 speex_decoder_destroy(st);
578 speex_bits_reset(&vf);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000579
Dan Evertonebc58c92007-02-09 10:06:53 +0000580 if (stream_init==1)
581 spx_ogg_stream_reset(&os);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000582
Dan Evertonebc58c92007-02-09 10:06:53 +0000583 spx_ogg_sync_reset(&oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000584
585 cur_granule = stream_init = rate = samplerate = headerssize
586 = packet_count = eos = 0;
587
588 stereo.balance =stereo.smooth_left = stereo.smooth_right = 1;
Dan Evertonebc58c92007-02-09 10:06:53 +0000589 stereo.e_ratio = .5;
590 stereo.reserved1=stereo.reserved2= 0;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000591
Dan Evertonebc58c92007-02-09 10:06:53 +0000592 goto next_track;
593 }
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000594
Dan Evertonebc58c92007-02-09 10:06:53 +0000595 error = CODEC_OK;
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000596
Dan Evertonebc58c92007-02-09 10:06:53 +0000597exit:
598 speex_bits_destroy(&vf);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000599
Dan Evertonebc58c92007-02-09 10:06:53 +0000600 if (stream_init)
601 spx_ogg_stream_destroy(&os);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000602
Dan Evertonebc58c92007-02-09 10:06:53 +0000603 spx_ogg_sync_destroy(&oy);
Dave Chapman0abfe9f2007-02-09 18:10:24 +0000604
Dan Evertonebc58c92007-02-09 10:06:53 +0000605 return error;
606}