source: roaraudio/roard/codecfilter_speex.c @ 6052:d48765b2475e

Last change on this file since 6052:d48765b2475e was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

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