source: roaraudio/roard/codecfilter_speex.c @ 3234:33163b08ad79

Last change on this file since 3234:33163b08ad79 was 2975:5ea4bfd9167f, checked in by phi, 15 years ago

support for some common codec options

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