source: roaraudio/roard/codecfilter_vorbis.c @ 5259:dc6b4deefec8

Last change on this file since 5259:dc6b4deefec8 was 5218:772842651185, checked in by phi, 12 years ago

Do not set errno to zero in ogg_vorbis codec filter (Closes: #191)

File size: 15.8 KB
Line 
1//codecfilter_vorbis.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2011
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#define ROAR_REQUIRE_LIBVORBISFILE
27
28#include "roard.h"
29
30#ifdef ROAR_HAVE_LIBVORBISFILE
31
32#define FIFAC ((float)((uint64_t)1<<(ROAR_VORBIS_BITS-1)))
33
34int _g_cf_vorbis_vfvio_return_err (void) {
35 return -1;
36}
37
38ov_callbacks _g_cf_vorbis_vfvio = {
39  .read_func  = cf_vorbis_vfvio_read,
40  .seek_func  = (int    (*)(void *, ogg_int64_t, int      )) _g_cf_vorbis_vfvio_return_err,
41  .close_func = (int    (*)(void *                        )) _g_cf_vorbis_vfvio_return_err,
42  .tell_func  = (long   (*)(void *                        )) _g_cf_vorbis_vfvio_return_err
43};
44
45size_t cf_vorbis_vfvio_read (void *ptr, size_t size, size_t nmemb, void *datasource) {
46 ssize_t r;
47
48 r = stream_vio_s_read(ROAR_STREAM_SERVER(datasource), ptr, size*nmemb);
49
50 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p): r=%i", ptr, size, nmemb, datasource, r);
51
52 if ( r == -1 ) {
53  ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p) = 0 // roar_error=%i(%s)", ptr, size, nmemb, datasource, roar_error, roar_error2str(roar_error));
54  return 0;
55 }
56
57 if ( r > 0 ) {
58  roar_err_clear_all();
59 }
60
61 r /= size;
62 
63 ROAR_DBG("cf_vorbis_vfvio_read(ptr=%p, size=%lu, nmemb=%lu, datasource=%p) = %i", ptr, size, nmemb, datasource, r);
64 return r;
65}
66
67int cf_vorbis_open(CODECFILTER_USERDATA_T * inst, int codec,
68                                            struct roar_stream_server * info,
69                                            struct roar_codecfilter   * filter) {
70 struct codecfilter_vorbis_inst * self = roar_mm_malloc(sizeof(struct codecfilter_vorbis_inst));
71 struct roar_stream * s = ROAR_STREAM(info);
72
73 if ( !self )
74  return -1;
75
76 self->current_section      = -1;
77 self->last_section         = -1;
78 self->opened               =  0;
79 self->got_it_running       =  0;
80 self->stream               = info;
81// self->outlen               = ROAR_OUTPUT_BUFFER_SAMPLES * s->info.channels * s->info.bits / 8; // optimal size
82#ifdef ROAR_HAVE_LIBVORBISENC
83 self->encoding               = 0;
84 self->encoder.v_base_quality = 0.3;
85 self->encoder.srn            = -1;
86#endif
87
88 ROAR_DBG("cf_vorbis_open(*): info->id=%i", ROAR_STREAM(info)->id);
89
90 *inst = (CODECFILTER_USERDATA_T) self;
91
92#if ROAR_CODEC_DEFAULT == ROAR_CODEC_PCM_S_LE
93 self->bigendianp = 0;
94 s->info.codec = ROAR_CODEC_DEFAULT;
95#else
96 self->bigendianp = 1;
97 s->info.codec = ROAR_CODEC_PCM_S_BE; // force because ROAR_CODEC_DEFAULT can be something non-BE, too.
98#endif
99
100 s->info.bits  = 16;
101
102 if ( s->dir == ROAR_DIR_PLAY ) {
103  return 0;
104 } else if ( s->dir == ROAR_DIR_MONITOR || s->dir == ROAR_DIR_OUTPUT ) {
105#ifdef ROAR_HAVE_LIBVORBISENC
106  // set up the encoder here
107// this is delayed to the write function
108/*
109 if ( cf_vorbis_encode_start(self) == -1 ) {
110  roar_mm_free(self);
111  return -1;
112 }
113*/
114 s->info.bits  = ROAR_VORBIS_BITS;
115#else
116 roar_mm_free(self);
117 return -1;
118#endif
119 } else {
120  roar_mm_free(self);
121  return -1;
122 }
123
124 return 0;
125}
126
127int cf_vorbis_close(CODECFILTER_USERDATA_T   inst) {
128 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
129
130 if ( self == NULL )
131  return -1;
132
133 if ( self->got_it_running )
134  ov_clear(&(self->vf));
135
136#ifdef ROAR_HAVE_LIBVORBISENC
137 if ( self->encoding ) {
138  cf_vorbis_encode_end(self);
139 }
140#endif
141
142 roar_mm_free(self);
143 return 0;
144}
145
146int cf_vorbis_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
147#ifdef ROAR_HAVE_LIBVORBISENC
148 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
149 struct roar_stream * s = ROAR_STREAM(self->stream);
150 ogg_packet header;
151 ogg_packet header_comm;
152 ogg_packet header_code;
153 float ** encbuf;
154 int i, c;
155 int chans;
156 int end;
157 int sid;
158 void * prethrubuf;
159#if ROAR_VORBIS_BITS == 8
160 int8_t  * data = (int8_t  *) buf;
161#elif ROAR_VORBIS_BITS == 16
162 int16_t * data = (int16_t *) buf;
163#elif ROAR_VORBIS_BITS == 32
164 int32_t * data = (int32_t *) buf;
165#else
166#error value of ROAR_VORBIS_BITS not supported
167#endif
168
169 if ( ! self->opened ) {
170  if ( !self->encoding ) {
171   if ( cf_vorbis_encode_start(self) == -1 ) {
172    return -1;
173   }
174  }
175
176  sid = ROAR_STREAM(self->stream)->id;
177
178  vorbis_analysis_headerout(&(self->encoder.vd), &(self->encoder.vc), &header, &header_comm, &header_code);
179
180  ogg_stream_packetin(&(self->encoder.os), &header);
181  ogg_stream_packetin(&(self->encoder.os), &header_comm);
182  ogg_stream_packetin(&(self->encoder.os), &header_code);
183
184  stream_prethru_destroy(sid);
185
186  while (ogg_stream_flush(&(self->encoder.os), &(self->encoder.og))) {
187   if ( stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len)
188                                                                 != self->encoder.og.header_len ||
189        stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  )
190                                                                 != self->encoder.og.body_len     ) {
191    roar_mm_free(self); // TODO: do we need addional cleanup?
192    return -1;
193   }
194   // we ignore errors at the moment...
195   if ( stream_prethru_add_data(sid, &prethrubuf, self->encoder.og.header_len + self->encoder.og.body_len) != -1 ) {
196    memcpy(prethrubuf,                               self->encoder.og.header, self->encoder.og.header_len);
197    memcpy(prethrubuf + self->encoder.og.header_len, self->encoder.og.body,   self->encoder.og.body_len  );
198   }
199  }
200  self->opened = 1;
201 } else {
202  encbuf = vorbis_analysis_buffer(&(self->encoder.vd), len /* TODO: need to lookup the menaing of this */);
203  chans  = s->info.channels;
204  end    = len*8/(ROAR_VORBIS_BITS*chans);
205
206  if ( chans == 1 ) { // use optimized code
207   for (i = 0; i < end; i++)
208    encbuf[0][i] = data[i]/FIFAC;
209
210  } else if ( chans == 2 ) { // use optimized code
211   for (i = 0; i < end; i++) {
212    encbuf[0][i] = data[2*i  ]/FIFAC;
213    encbuf[1][i] = data[2*i+1]/FIFAC;
214   }
215  } else { // use generic multi channel code
216   for (i = 0; i < end; i++) {
217    for (c = 0; c < chans; c++) {
218     encbuf[c][i] = data[chans*i+c]/FIFAC;
219    }
220   }
221  }
222
223  vorbis_analysis_wrote(&(self->encoder.vd), i);
224
225  if ( cf_vorbis_encode_flushout(self) == -1 )
226   return -1;
227 }
228
229  return len; // we assume every thing was written (at least into our dsp anaylises buffer
230#else
231 roar_err_set(ROAR_ERROR_NOSYS);
232 roar_err_to_errno();
233 return -1;
234#endif
235}
236int cf_vorbis_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
237 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
238 long r;
239 long todo = len;
240 long done = 0;
241 int ret;
242
243 ROAR_DBG("cf_vorbis_read(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
244
245 self->opened++;
246 if ( self->opened == 16 ) {
247
248  ROAR_DBG("cf_vorbis_read(*): opening...");
249  if ( (ret = ov_open_callbacks((void*)self->stream, &(self->vf), NULL, 0, _g_cf_vorbis_vfvio)) < 0 ) {
250   ROAR_DBG("cf_vorbis_read(*): ret=%i", ret);
251   ROAR_DBG("cf_vorbis_read(*) = 0");
252   return 0;
253  }
254
255  ROAR_DBG("cf_vorbis_read(*) = -1 // errno=EAGAIN");
256  roar_err_set(ROAR_ERROR_AGAIN);
257  roar_err_to_errno();
258  return -1;
259 }
260
261 if ( self->opened < 16 ) {
262  ROAR_DBG("cf_vorbis_read(*) = -1 // errno=EAGAIN");
263  roar_err_set(ROAR_ERROR_AGAIN);
264  roar_err_to_errno();
265  return -1;
266 }
267
268
269 self->got_it_running = 1;
270
271 while (todo) {
272  r = ov_read(&(self->vf), buf+done, todo, self->bigendianp, 2, 1, &(self->current_section));
273  ROAR_DBG("cf_vorbis_read(*): r=%li", r);
274  if ( r == OV_HOLE ) {
275   ROAR_DBG("cf_vorbis_read(*): Hole in stream");
276  } else if ( r < 1 ) {
277   break;
278  } else {
279   if ( self->last_section != self->current_section )
280    if ( cf_vorbis_update_stream(self) == -1 )
281     return 0;
282
283   self->last_section = self->current_section;
284   todo -= r;
285   done += r;
286  }
287 }
288
289 ROAR_DBG("ov_read(*) = %i", done);
290
291 if ( done == 0 ) {
292  // do some EOF handling...
293  return 0;
294 } else {
295  return len;
296 }
297}
298
299int cf_vorbis_update_stream (struct codecfilter_vorbis_inst * self) {
300#ifdef ROAR_SUPPORT_META
301 vorbis_info *vi = ov_info(&(self->vf), -1);
302 char **ptr = ov_comment(&(self->vf), -1)->user_comments;
303 char key[ROAR_META_MAX_NAMELEN] = {0}, value[LIBROAR_BUFFER_MSGDATA] = {0};
304 struct roar_stream * s = ROAR_STREAM(self->stream);
305 int type;
306 int j, h = 0;
307 float rpg_track = 0, rpg_album = 0;
308 int meta_ok;
309
310 s->info.channels = vi->channels;
311 s->info.rate     = vi->rate;
312 s->info.bits     = 16;
313#if ROAR_CODEC_DEFAULT == ROAR_CODEC_PCM_S_LE
314 s->info.codec    = ROAR_CODEC_DEFAULT;
315#else
316 s->info.codec    = ROAR_CODEC_PCM_S_BE;
317#endif
318
319 stream_meta_clear(s->id);
320
321 while(*ptr){
322  meta_ok = 1;
323
324   for (j = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
325    if ( j == ROAR_META_MAX_NAMELEN ) {
326     ROAR_ERR("cf_vorbis_update_stream(*): invalid meta data on stream %i: meta data key too long", s->id);
327     meta_ok = 0;
328     j = 0;
329     break;
330    }
331    key[j] = (*ptr)[j];
332   }
333   key[j] = 0;
334
335   if ( meta_ok ) {
336    for (j++, h = 0; (*ptr)[j] != 0 && (*ptr)[j] != '='; j++) {
337     if ( h == LIBROAR_BUFFER_MSGDATA ) {
338      ROAR_ERR("update_stream(*): invalid meta data on stream %i: meta data value for key '%s' too long", s->id, key);
339      meta_ok = 0;
340      h = 0;
341      break;
342     }
343     value[h++] = (*ptr)[j];
344    }
345    value[h]   = 0;
346   }
347
348   if ( meta_ok ) {
349    type = roar_meta_inttype(key);
350    if ( type != -1 )
351     stream_meta_set(s->id, type, "", value);
352
353    ROAR_DBG("cf_vorbis_update_stream(*): Meta %-16s: %s", key, value);
354
355    if ( strcmp(key, "REPLAYGAIN_TRACK_PEAK") == 0 ) {
356     rpg_track = 1/atof(value);
357/*
358    } else if ( strcmp(key, "REPLAYGAIN_TRACK_GAIN") == 0 ) {
359     rpg_track = powf(10, atof(value)/20);
360*/
361    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_PEAK") == 0 ) {
362     rpg_album = 1/atof(value);
363/*
364    } else if ( strcmp(key, "REPLAYGAIN_ALBUM_GAIN") == 0 ) {
365     rpg_album = powf(10, atof(value)/20);
366*/
367    }
368   }
369
370   ptr++;
371 }
372
373 if ( rpg_album ) {
374  self->stream->mixer.rpg_div = 2718;  // = int(exp(1)*1000)
375  self->stream->mixer.rpg_mul = (float)rpg_album*2718;
376 } else if ( rpg_track ) {
377  self->stream->mixer.rpg_div = 2718;
378  self->stream->mixer.rpg_mul = (float)rpg_track*2718;
379 }
380
381 stream_meta_finalize(s->id);
382#endif
383 //printf("RPG: mul=%i, div=%i\n", self->stream->mixer.rpg_mul, self->stream->mixer.rpg_div);
384 return 0;
385}
386
387int cf_vorbis_encode_start  (struct codecfilter_vorbis_inst * self) {
388#ifdef ROAR_HAVE_LIBVORBISENC
389 int srn = self->encoder.srn; // this value is allrady inited...
390#ifdef ROAR_SUPPORT_META
391 int len = 0;
392 int i;
393 int types[ROAR_META_MAX_PER_STREAM];
394#endif
395 int sid = ROAR_STREAM(self->stream)->id;
396 float v_base_quality = self->encoder.v_base_quality;
397 char val[LIBROAR_BUFFER_MSGDATA];
398
399  val[LIBROAR_BUFFER_MSGDATA-1] = 0;
400
401  memset(&(self->encoder), 0, sizeof(self->encoder));
402
403  self->encoding = 1;
404  self->encoder.srn = srn + 1;
405  self->encoder.v_base_quality = v_base_quality;
406
407  vorbis_info_init(&(self->encoder.vi));
408  vorbis_comment_init(&(self->encoder.vc));
409  vorbis_comment_add_tag(&(self->encoder.vc), "SERVER", "RoarAudio");
410  vorbis_comment_add_tag(&(self->encoder.vc), "ENCODER", "RoarAudio Vorbis codecfilter");
411
412#ifdef ROAR_SUPPORT_META
413  if ( (len = stream_meta_list(sid, types, ROAR_META_MAX_PER_STREAM)) != -1 ) {
414   for (i = 0; i < len; i++) {
415//int stream_meta_get     (int id, int type, char * name, char * val, size_t len);
416    if ( stream_meta_get(sid, types[i], NULL, val, LIBROAR_BUFFER_MSGDATA-1) == 0 )
417     vorbis_comment_add_tag(&(self->encoder.vc), roar_meta_strtype(types[i]), val);
418   }
419  }
420#endif
421
422  ROAR_DBG("cf_vorbis_encode_start(*): q=%f", v_base_quality);
423
424  if( vorbis_encode_init_vbr(&(self->encoder.vi), (long) ROAR_STREAM(self->stream)->info.channels,
425                                                  (long) ROAR_STREAM(self->stream)->info.rate,
426                                                  v_base_quality) != 0 ) {
427   ROAR_ERR("cf_vorbis_encode_start(*): Can not vorbis_encode_init_vbr(*)!");
428   vorbis_info_clear(&(self->encoder.vi)); // TODO: do we need to free vc also?
429   return -1;
430  }
431
432  vorbis_analysis_init(&(self->encoder.vd), &(self->encoder.vi));
433  vorbis_block_init(&(self->encoder.vd), &(self->encoder.vb));
434
435  ROAR_DBG("cf_vorbis_encode_start(*): srn=%i", self->encoder.srn);
436                                     //  "RA"<<16 + PID<<8 + Stream ID
437  ogg_stream_init(&(self->encoder.os),
438                   (((0x5241 + self->encoder.srn) & 0xffff)<<16) +
439                   ( (getpid()                    & 0x00ff)<< 8) +
440                   (  sid                         & 0x00ff));
441 return 0;
442#else
443 return -1;
444#endif
445}
446
447int cf_vorbis_encode_end    (struct codecfilter_vorbis_inst * self) {
448#ifdef ROAR_HAVE_LIBVORBISENC
449 if ( self->encoding ) {
450  // try to flush up to an EOS page...
451  vorbis_analysis_buffer(&(self->encoder.vd), 2*ROAR_MAX_CHANNELS);
452  vorbis_analysis_wrote(&(self->encoder.vd), 0);
453  cf_vorbis_encode_flushout(self);
454
455  // clean up...
456  ogg_stream_clear(&(self->encoder.os));
457  vorbis_block_clear(&(self->encoder.vb));
458  vorbis_dsp_clear(&(self->encoder.vd));
459  vorbis_info_clear(&(self->encoder.vi));
460  self->opened = 0;
461 }
462
463 return 0;
464#else
465 return -1;
466#endif
467}
468
469int cf_vorbis_encode_flushout(struct codecfilter_vorbis_inst * self) {
470#ifdef ROAR_HAVE_LIBVORBISENC
471 while ( vorbis_analysis_blockout(&(self->encoder.vd), &(self->encoder.vb)) == 1 ) {
472  vorbis_analysis(&(self->encoder.vb), &(self->encoder.op));
473  vorbis_bitrate_addblock(&(self->encoder.vb));
474
475  while ( vorbis_bitrate_flushpacket(&(self->encoder.vd), &(self->encoder.op)) ) {
476   ogg_stream_packetin(&(self->encoder.os), &(self->encoder.op));
477
478   while( ogg_stream_pageout(&(self->encoder.os), &(self->encoder.og)) ) {
479    if (
480         stream_vio_s_write(self->stream, self->encoder.og.header, self->encoder.og.header_len) == -1 ||
481         stream_vio_s_write(self->stream, self->encoder.og.body,   self->encoder.og.body_len  ) == -1   ) {
482     return -1;
483    }
484   }
485  }
486 }
487
488 return 0;
489#else
490 return -1;
491#endif
492}
493
494int cf_vorbis_ctl(CODECFILTER_USERDATA_T   inst, int cmd, void * data) {
495 struct codecfilter_vorbis_inst * self = (struct codecfilter_vorbis_inst *) inst;
496 int_least32_t type = cmd & ROAR_STREAM_CTL_TYPEMASK;
497
498 cmd -= type;
499
500 switch (cmd) {
501  case ROAR_CODECFILTER_CTL2CMD(ROAR_CODECFILTER_CTL_META_UPDATE):
502    if ( type != ROAR_STREAM_CTL_TYPE_VOID )
503     return -1;
504
505    ROAR_DBG("cf_vorbis_ctl(*): stoping stream...");
506    if ( cf_vorbis_encode_end(self) == -1 )
507     return -1;
508    ROAR_DBG("cf_vorbis_ctl(*): restarting stream...");
509    if ( cf_vorbis_encode_start(self) == -1 )
510     return -1;
511
512    return 0;
513   break;
514  case ROAR_CODECFILTER_CTL2CMD(ROAR_CODECFILTER_CTL_SET_Q):
515    if ( type != ROAR_STREAM_CTL_TYPE_FLOAT )
516     return -1;
517
518    ROAR_DBG("cf_vorbis_ctl(*): setting quality to q=%f", *(float*)data);
519
520    self->encoder.v_base_quality = *(float*)data / 10;
521
522    if ( self->encoding ) {
523     ROAR_DBG("cf_vorbis_ctl(*): we are allready encoding, restart...");
524     ROAR_DBG("cf_vorbis_ctl(*): stoping stream...");
525     if ( cf_vorbis_encode_end(self) == -1 )
526      return -1;
527     ROAR_DBG("cf_vorbis_ctl(*): restarting stream...");
528     if ( cf_vorbis_encode_start(self) == -1 )
529      return -1;
530    }
531
532    return 0;
533   break;
534  default:
535    ROAR_DBG("cf_vorbis_ctl(*): Unknown command: cmd=0x%.8x, type=0x%.8x, pcmd=0x%.8x",
536                    cmd, type, ROAR_CODECFILTER_CTL2CMD(cmd));
537    return -1;
538 }
539
540 return -1;
541}
542
543#endif
544//ll
Note: See TracBrowser for help on using the repository browser.