source: roaraudio/roard/codecfilter_speex.c @ 2310:c5f2de11bee3

Last change on this file since 2310:c5f2de11bee3 was 2310:c5f2de11bee3, checked in by phi, 15 years ago

added stereo support for encoder half

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