source: roaraudio/roard/codecfilter_speex.c @ 5823:f9f70dbaa376

Last change on this file since 5823:f9f70dbaa376 was 5823:f9f70dbaa376, checked in by phi, 11 years ago

updated copyright

File size: 11.3 KB
Line 
1//codecfilter_speex.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008-2013
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#include "roard.h"
27#ifdef ROAR_HAVE_LIBSPEEX
28
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
41#define _FS (_16BIT * (self->stereo ? 2 : 1))
42
43#define _HAVE_CCFG(x) (self->codec_config != NULL && (self->codec_config->para_set & (x)))
44
45int cf_speex_open(CODECFILTER_USERDATA_T * inst, int codec,
46                                            struct roar_stream_server * info,
47                                            struct roar_codecfilter   * filter) {
48 struct codecfilter_speex_inst * self = roar_mm_malloc(sizeof(struct codecfilter_speex_inst));
49 struct roar_stream * s = ROAR_STREAM(info);
50
51 *inst = NULL;
52
53 if (!self)
54  return -1;
55
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:
63    roar_mm_free(self);
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
74 self->encoder = NULL;
75 self->decoder = NULL;
76
77 self->stream  = info;
78
79 self->cd      = NULL;
80
81 self->i_rest  = NULL;
82 self->fi_rest = 0;
83 self->o_rest  = NULL;
84 self->fo_rest = 0;
85
86 self->codec_config = roar_libroar_config_codec_get(ROAR_CODEC_ROAR_SPEEX, 0);
87
88 speex_bits_init(&(self->bits));
89
90 *inst = (void*) self;
91
92 return 0;
93}
94
95int cf_speex_close(CODECFILTER_USERDATA_T   inst) {
96 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
97
98 if (!self)
99  return -1;
100
101 if ( self->encoder )
102  speex_encoder_destroy(self->encoder);
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
113 if ( self->cd != NULL )
114  roar_mm_free(self->cd);
115
116 if ( self->i_rest != NULL )
117  roar_mm_free(self->i_rest);
118
119 roar_mm_free((void*)self);
120
121 return 0;
122}
123
124int cf_speex_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
125 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
126 int mode;
127 uint16_t ui;
128 int tmp;
129 int still_todo = len / _FS;
130 int ret = 0;
131 int fs2; // = self->frame_size * _16BIT * channels;
132 char magic[ROAR_SPEEX_MAGIC_LEN];
133 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
134
135 ROAR_DBG("cf_speex_read(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
136
137 if ( ! self->decoder ) {
138  ROAR_DBG("cf_speex_read(*): no decoder, starting one!");
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
146  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
147   return 0;
148
149  mode = ROAR_NET2HOST16(ui);
150
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;
156  }
157
158  tmp=1;
159  speex_decoder_ctl(self->decoder, SPEEX_SET_ENH, &tmp);
160
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
167  speex_decoder_ctl(self->decoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
168
169  fs2 = self->frame_size * _FS;
170
171  ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
172
173  if ( self->cd == NULL ) {
174   self->cd = roar_mm_malloc(fs2);
175   if ( self->cd == NULL )
176    return 0;
177  }
178
179  if ( self->i_rest == NULL ) {
180   self->i_rest = roar_mm_malloc(fs2);
181   if ( self->i_rest == NULL )
182    return 0;
183  }
184 }
185 fs2 = self->frame_size * _FS;
186
187 ROAR_DBG("cf_speex_read(*): Have a working decoder!");
188
189 ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
190 ROAR_DBG("cf_speex_read(*): i_rest is %i bytes after cd", ((void*)self->i_rest - (void*)self->cd));
191
192
193 if ( self->fi_rest ) {
194  if ( self->fi_rest > (still_todo*_FS) ) {
195   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i (no need to read new data)", self->fi_rest);
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.
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;
203  } else {
204   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i", self->fi_rest);
205   memcpy(buf, self->i_rest, self->fi_rest);
206   buf += self->fi_rest;
207   still_todo -= self->fi_rest/_FS;
208   ret += self->fi_rest;
209   self->fi_rest = 0;
210  }
211 }
212
213 while (still_todo) {
214  ROAR_DBG("cf_speex_read(*): we sill need %i frames", still_todo);
215  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
216   return -1;
217
218  ui = ROAR_NET2HOST16(ui);
219
220  if ( ui > ROAR_SPEEX_MAX_CC )
221   return 0;
222
223  if ( stream_vio_s_read(self->stream, self->cc, ui) != ui )
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
230  if ( self->stereo) {
231   speex_decode_stereo_int(self->cd, self->frame_size, &(self->stereo_state));
232  }
233
234  if ( self->frame_size > still_todo ) {
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);
240   still_todo = 0;
241  } else {
242   memcpy(buf, self->cd, fs2);
243   buf        += fs2;
244   ret        += fs2;
245   still_todo -= self->frame_size;
246  }
247 }
248
249 if ( still_todo ) {
250  ROAR_DBG("cf_speex_read(*): could not read all reqquested data, returning %i byte less", still_todo*_FS);
251 }
252
253 ROAR_DBG("cf_speex_read(*) = %i", ret);
254
255 return ret;
256}
257
258int cf_speex_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
259 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
260 uint16_t mode = ROAR_SPEEX_MODE_UWB;
261 int tmp;
262 int fs2;
263 int ret = 0;
264 int need_extra;
265 int sid;
266 void * prethru;
267
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
274 ROAR_DBG("cf_speex_write(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
275
276 if ( ! self->encoder ) {
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
289  if ( stream_vio_s_write(self->stream, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN) != ROAR_SPEEX_MAGIC_LEN )
290   return -1;
291
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;
297  }
298
299  mode = ROAR_HOST2NET16(mode);
300
301  if ( stream_prethru_add_data(sid, &prethru, 2) == -1 ) {
302   return -1;
303  }
304
305  *(uint16_t*)prethru = mode;
306
307  if ( stream_vio_s_write(self->stream, &mode, 2) != 2 )
308   return -1;
309
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
332  speex_encoder_ctl(self->encoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
333
334  fs2 = self->frame_size * _FS;
335
336  if ( self->cd == NULL ) {
337   self->cd = roar_mm_malloc(fs2 + 2);
338   if ( self->cd == NULL )
339    return 0;
340  }
341
342  if ( self->o_rest == NULL ) {
343   self->o_rest = roar_mm_malloc(fs2);
344   if ( self->o_rest == NULL )
345    return 0;
346  }
347 }
348
349 fs2 = self->frame_size * _FS;
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
358   if ( self->stereo )
359    speex_encode_stereo_int((spx_int16_t *) self->o_rest, self->frame_size, &(self->bits));
360
361   speex_encode_int(self->encoder, (spx_int16_t *) self->o_rest, &(self->bits));
362
363   tmp = mode = speex_bits_write(&(self->bits), self->cd + 2, fs2);
364
365   mode = ROAR_HOST2NET16(mode);
366   *(uint16_t*)(self->cd) = mode;
367   if ( stream_vio_s_write(self->stream, self->cd, tmp + 2) != (tmp + 2) )
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) {
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
388  if ( self->stereo )
389   speex_encode_stereo_int((spx_int16_t *) buf, self->frame_size, &(self->bits));
390
391  speex_encode_int(self->encoder, (spx_int16_t *) buf, &(self->bits));
392
393  tmp = mode = speex_bits_write(&(self->bits), self->cd + 2, fs2);
394
395  mode = ROAR_HOST2NET16(mode);
396
397  *(uint16_t*)(self->cd) = mode;
398
399  if ( stream_vio_s_write(self->stream, self->cd, tmp + 2) != (tmp + 2) )
400   return -1;
401
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;
414}
415
416#endif
417
418//ll
Note: See TracBrowser for help on using the repository browser.