source: roaraudio/roard/codecfilter_speex.c @ 3215:13678c1774be

Last change on this file since 3215:13678c1774be was 2975:5ea4bfd9167f, checked in by phi, 15 years ago

support for some common codec options

File size: 11.1 KB
RevLine 
[371]1//codecfilter_speex.c:
2
[668]3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
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, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
[371]25#include "roard.h"
26#ifdef ROAR_HAVE_LIBSPEEX
27
[620]28/*
29 Format:
30 (all numbers are in network byte order)
31
32 MAGIC of site MAGIC_LEN
33 MODE NUMMBER of size 2 Byte
34 { // frames
35   FRAME LENGTH of size 2 Byte
36   FRAME DATA of size FRAME LENGTH Byte
37 }
38*/
39
[2308]40#define _FS (_16BIT * (self->stereo ? 2 : 1))
41
[2975]42#define _HAVE_CCFG(x) (self->codec_config != NULL && (self->codec_config->para_set & (x)))
43
[373]44int cf_speex_open(CODECFILTER_USERDATA_T * inst, int codec,
45                                            struct roar_stream_server * info,
46                                            struct roar_codecfilter   * filter) {
[391]47 struct codecfilter_speex_inst * self = malloc(sizeof(struct codecfilter_speex_inst));
[609]48 struct roar_stream * s = ROAR_STREAM(info);
[391]49
[373]50 *inst = NULL;
[391]51
52 if (!self)
53  return -1;
54
[2308]55 s->info.codec    = ROAR_CODEC_DEFAULT;
56 s->info.bits     = 16; // speex hardcoded
57
58 switch (s->info.channels) {
59  case 1: self->stereo = 0; break;
60  case 2: self->stereo = 1; break;
61  default:
62    free(self);
63    return -1;
64 }
65
66 // do as much to preper the startup of stereo encoder as possible
67 if ( self->stereo ) {
68  self->stereo_callback.callback_id = SPEEX_INBAND_STEREO;
69  self->stereo_callback.func        = speex_std_stereo_request_handler;
70  self->stereo_callback.data       = &(self->stereo_state);
71 }
72
[392]73 self->encoder = NULL;
74 self->decoder = NULL;
75
[393]76 self->stream  = info;
77
[395]78 self->cd      = NULL;
79
80 self->i_rest  = NULL;
81 self->fi_rest = 0;
[617]82 self->o_rest  = NULL;
83 self->fo_rest = 0;
[395]84
[2973]85 self->codec_config = roar_libroar_config_codec_get(ROAR_CODEC_ROAR_SPEEX, 0);
86
[392]87 speex_bits_init(&(self->bits));
88
[391]89 *inst = (void*) self;
90
91 return 0;
[373]92}
93
94int cf_speex_close(CODECFILTER_USERDATA_T   inst) {
[391]95 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
96
97 if (!self)
98  return -1;
99
[392]100 if ( self->encoder )
[616]101  speex_encoder_destroy(self->encoder);
[392]102
103 self->encoder = NULL;
104
105 if ( self->decoder )
106  speex_decoder_destroy(self->decoder);
107
108 self->decoder = NULL;
109
110 speex_bits_destroy(&(self->bits));
111
[395]112 if ( self->cd )
113  free(self->cd);
114
115 if ( self->i_rest )
116  free(self->i_rest);
117
[391]118 free((void*)self);
119
120 return 0;
[373]121}
122
123int cf_speex_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
[391]124 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
[393]125 int mode;
126 uint16_t ui;
[395]127 int tmp;
[2308]128 int still_todo = len / _FS;
[395]129 int ret = 0;
[2308]130 int fs2; // = self->frame_size * _16BIT * channels;
[614]131 char magic[ROAR_SPEEX_MAGIC_LEN];
[2308]132 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
[393]133
[614]134 ROAR_DBG("cf_speex_read(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
[396]135
[393]136 if ( ! self->decoder ) {
[395]137  ROAR_DBG("cf_speex_read(*): no decoder, starting one!");
[614]138
139  if ( stream_vio_s_read(self->stream, magic, ROAR_SPEEX_MAGIC_LEN) != ROAR_SPEEX_MAGIC_LEN )
140   return 0;
141
142  if ( memcmp(magic, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN) != 0 )
143   return -1;
144
[608]145  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
[393]146   return 0;
147
[2309]148  mode = ROAR_NET2HOST16(ui);
[393]149
[2967]150  switch (mode) {
151   case ROAR_SPEEX_MODE_NB:  self->decoder = speex_decoder_init(&speex_nb_mode);  break;
152   case ROAR_SPEEX_MODE_WB:  self->decoder = speex_decoder_init(&speex_wb_mode);  break;
153   case ROAR_SPEEX_MODE_UWB: self->decoder = speex_decoder_init(&speex_uwb_mode); break;
154   default: return 0;
[393]155  }
[395]156
157  tmp=1;
158  speex_decoder_ctl(self->decoder, SPEEX_SET_ENH, &tmp);
159
[2308]160  if ( self->stereo ) {
161   memcpy(&(self->stereo_state), &stereo, sizeof(self->stereo_state));
162   speex_decoder_ctl(self->decoder, SPEEX_SET_HANDLER, &(self->stereo_callback));
163  }
164
165
[395]166  speex_decoder_ctl(self->decoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
167
[2308]168  fs2 = self->frame_size * _FS;
[395]169
[614]170  ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
[395]171
172  if ( !self->cd ) {
[614]173   self->cd = malloc(fs2);
[395]174   if ( !self->cd )
175    return 0;
176  }
177
178  if ( !self->i_rest ) {
[614]179   self->i_rest = malloc(fs2);
[395]180   if ( !self->i_rest )
181    return 0;
182  }
[393]183 }
[2308]184 fs2 = self->frame_size * _FS;
[391]185
[396]186 ROAR_DBG("cf_speex_read(*): Have a working decoder!");
[395]187
[614]188 ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
[396]189 ROAR_DBG("cf_speex_read(*): i_rest is %i bytes after cd", ((void*)self->i_rest - (void*)self->cd));
[395]190
191
192 if ( self->fi_rest ) {
[2308]193  if ( self->fi_rest > (still_todo*_FS) ) {
[614]194   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i (no need to read new data)", self->fi_rest);
[2308]195   still_todo *= _FS; // we will set this to zero one way or another,
196                         // so we don't need to care about soring a 'wrong' value here.
[614]197   memcpy(buf, self->i_rest, still_todo);
198   memmove(self->i_rest, self->i_rest + still_todo, self->fi_rest - still_todo);
199   self->fi_rest -= still_todo;
200   ret += still_todo;
201   still_todo = 0;
[395]202  } else {
[614]203   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i", self->fi_rest);
[395]204   memcpy(buf, self->i_rest, self->fi_rest);
205   buf += self->fi_rest;
[2308]206   still_todo -= self->fi_rest/_FS;
[396]207   ret += self->fi_rest;
[395]208   self->fi_rest = 0;
209  }
210 }
211
212 while (still_todo) {
[614]213  ROAR_DBG("cf_speex_read(*): we sill need %i frames", still_todo);
[608]214  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
[395]215   return -1;
216
[2309]217  ui = ROAR_NET2HOST16(ui);
[395]218
219  if ( ui > ROAR_SPEEX_MAX_CC )
220   return 0;
221
[608]222  if ( stream_vio_s_read(self->stream, self->cc, ui) != ui )
[395]223   break;
224
225  speex_bits_read_from(&(self->bits), self->cc, ui);
226
227  speex_decode_int(self->decoder, &(self->bits), self->cd);
228
[2308]229  if ( self->stereo) {
230   speex_decode_stereo_int(self->cd, self->frame_size, &(self->stereo_state));
231  }
232
[395]233  if ( self->frame_size > still_todo ) {
[2308]234   memcpy(buf, self->cd, still_todo*_FS);
235   ret += still_todo*_FS;
236   self->fi_rest = (self->frame_size - still_todo)*_FS;
237   ROAR_DBG("cf_speex_read(*): self->fi_rest=%i, off=%i", self->fi_rest, still_todo*_FS);
238   memcpy(self->i_rest, (self->cd)+(still_todo*_FS), self->fi_rest);
[395]239   still_todo = 0;
240  } else {
[614]241   memcpy(buf, self->cd, fs2);
242   buf        += fs2;
243   ret        += fs2;
[395]244   still_todo -= self->frame_size;
245  }
246 }
247
[396]248 if ( still_todo ) {
[2308]249  ROAR_DBG("cf_speex_read(*): could not read all reqquested data, returning %i byte less", still_todo*_FS);
[396]250 }
251
[614]252 ROAR_DBG("cf_speex_read(*) = %i", ret);
[396]253
[395]254 return ret;
[373]255}
[393]256
[373]257int cf_speex_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
[391]258 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
[615]259 uint16_t mode = ROAR_SPEEX_MODE_UWB;
260 int tmp;
[617]261 int fs2;
262 int ret = 0;
263 int need_extra;
[2816]264 int sid;
265 void * prethru;
[615]266
[620]267/*
268 TODO: Befor this realy works there must be a working way to set the number of channels and bits
269       for monetoring clients. Else this will produce some thing stange as a 'mono' file that realy
270       contains stereo.
271*/
272
[619]273 ROAR_DBG("cf_speex_write(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
274
[615]275 if ( ! self->encoder ) {
[2816]276  sid = ROAR_STREAM(self->stream)->id;
277
278  if ( stream_prethru_destroy(sid) == -1 ) {
279   return -1;
280  }
281
282  if ( stream_prethru_add_data(sid, &prethru, ROAR_SPEEX_MAGIC_LEN) == -1 ) {
283   return -1;
284  }
285
286  memcpy(prethru, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN);
287
[615]288  if ( stream_vio_s_write(self->stream, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN) != ROAR_SPEEX_MAGIC_LEN )
289   return -1;
290
[2972]291  switch (mode) {
292   case ROAR_SPEEX_MODE_NB:  self->encoder = speex_encoder_init(&speex_nb_mode);  break;
293   case ROAR_SPEEX_MODE_WB:  self->encoder = speex_encoder_init(&speex_wb_mode);  break;
294   case ROAR_SPEEX_MODE_UWB: self->encoder = speex_encoder_init(&speex_uwb_mode); break;
295   default: return -1;
[615]296  }
297
298  mode = ROAR_HOST2NET16(mode);
299
[2816]300  if ( stream_prethru_add_data(sid, &prethru, 2) == -1 ) {
301   return -1;
302  }
303
304  *(uint16_t*)prethru = mode;
305
[615]306  if ( stream_vio_s_write(self->stream, &mode, 2) != 2 )
307   return -1;
308
[2975]309  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_COMPLEXITY) ) {
310   tmp = self->codec_config->complexity / 256;
311  } else {
312   tmp = 8;
313  }
314  speex_encoder_ctl(self->encoder, SPEEX_SET_COMPLEXITY,    &tmp);
315
316  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_Q) ) {
317   tmp = self->codec_config->q / 256;
318   speex_encoder_ctl(self->encoder, SPEEX_SET_QUALITY,      &tmp);
319  }
320
321  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_VBR) ) {
322   tmp = self->codec_config->vbr ? 1 : 0;
323   speex_encoder_ctl(self->encoder, SPEEX_SET_VBR,          &tmp);
324  }
325
326  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_DTX) ) {
327   tmp = self->codec_config->dtx ? 1 : 0;
328   speex_encoder_ctl(self->encoder, SPEEX_SET_DTX,          &tmp);
329  }
330
[615]331  speex_encoder_ctl(self->encoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
332
[2310]333  fs2 = self->frame_size * _FS;
[617]334
335  if ( !self->cd ) {
[2901]336   self->cd = malloc(fs2 + 2);
[617]337   if ( !self->cd )
338    return 0;
339  }
340
341  if ( !self->o_rest ) {
342   self->o_rest = malloc(fs2);
343   if ( !self->o_rest )
344    return 0;
345  }
[615]346 }
[391]347
[2310]348 fs2 = self->frame_size * _FS;
[617]349
350 if ( self->fo_rest ) { // ignore the rest for the moment
351  if ( (self->fo_rest + len) > fs2 ) {
352   need_extra = fs2 - self->fo_rest;
353   memcpy(self->o_rest + self->fo_rest, buf, need_extra);
354
355   speex_bits_reset(&(self->bits));
356
[2310]357   if ( self->stereo )
358    speex_encode_stereo_int((spx_int16_t *) self->o_rest, self->frame_size, &(self->bits));
359
[617]360   speex_encode_int(self->encoder, (spx_int16_t *) self->o_rest, &(self->bits));
361
[2901]362   tmp = mode = speex_bits_write(&(self->bits), self->cd + 2, fs2);
[617]363
[618]364   mode = ROAR_HOST2NET16(mode);
[2901]365   *(uint16_t*)(self->cd) = mode;
366   if ( stream_vio_s_write(self->stream, self->cd, tmp + 2) != (tmp + 2) )
[617]367    return -1;
368
369   buf += need_extra;
370   ret += need_extra;
371   len -= need_extra;
372   self->fo_rest = 0;
373  } else { // just add the data to o_rest
374   memcpy(self->o_rest + self->fo_rest, buf, len);
375   self->fo_rest += len;
376   return len;
377  }
378 }
379
380 // TODO: do we realy need such a loop?
381 while (len > fs2) {
[619]382//  ROAR_WARN("cf_speex_write(*): Discarding a full block of data as non-o_rest encoding is not supported!");
383//  ROAR_WARN("cf_speex_write(*): Block info: len=%i, fs2=%i", len, fs2);
384
385  speex_bits_reset(&(self->bits));
386
[2310]387  if ( self->stereo )
388   speex_encode_stereo_int((spx_int16_t *) buf, self->frame_size, &(self->bits));
389
[619]390  speex_encode_int(self->encoder, (spx_int16_t *) buf, &(self->bits));
391
[2901]392  tmp = mode = speex_bits_write(&(self->bits), self->cd + 2, fs2);
[619]393
394  mode = ROAR_HOST2NET16(mode);
395
[2901]396  *(uint16_t*)(self->cd) = mode;
[619]397
[2901]398  if ( stream_vio_s_write(self->stream, self->cd, tmp + 2) != (tmp + 2) )
[619]399   return -1;
400
[617]401  len -= fs2;
402  buf += fs2;
403  ret += fs2;
404 }
405
406 if ( len ) { // we still have some data, add this to o_rest
407  memcpy(self->o_rest, buf, len);
408  self->fo_rest = len;
409  ret += len;
410 }
411
412 return ret;
[373]413}
414
[371]415#endif
416
417//ll
Note: See TracBrowser for help on using the repository browser.