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
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
42int cf_speex_open(CODECFILTER_USERDATA_T * inst, int codec,
43                                            struct roar_stream_server * info,
44                                            struct roar_codecfilter   * filter) {
45 struct codecfilter_speex_inst * self = malloc(sizeof(struct codecfilter_speex_inst));
46 struct roar_stream * s = ROAR_STREAM(info);
47
48 *inst = NULL;
49
50 if (!self)
51  return -1;
52
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
71 self->encoder = NULL;
72 self->decoder = NULL;
73
74 self->stream  = info;
75
76 self->cd      = NULL;
77
78 self->i_rest  = NULL;
79 self->fi_rest = 0;
80 self->o_rest  = NULL;
81 self->fo_rest = 0;
82
83 speex_bits_init(&(self->bits));
84
85 *inst = (void*) self;
86
87 return 0;
88}
89
90int cf_speex_close(CODECFILTER_USERDATA_T   inst) {
91 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
92
93 if (!self)
94  return -1;
95
96 if ( self->encoder )
97  speex_encoder_destroy(self->encoder);
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
108 if ( self->cd )
109  free(self->cd);
110
111 if ( self->i_rest )
112  free(self->i_rest);
113
114 free((void*)self);
115
116 return 0;
117}
118
119int cf_speex_read(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
120 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
121 int mode;
122 uint16_t ui;
123 int tmp;
124 int still_todo = len / _FS;
125 int ret = 0;
126 int fs2; // = self->frame_size * _16BIT * channels;
127 char magic[ROAR_SPEEX_MAGIC_LEN];
128 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
129
130 ROAR_DBG("cf_speex_read(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
131
132 if ( ! self->decoder ) {
133  ROAR_DBG("cf_speex_read(*): no decoder, starting one!");
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
141  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
142   return 0;
143
144  mode = ROAR_NET2HOST16(ui);
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  }
155
156  tmp=1;
157  speex_decoder_ctl(self->decoder, SPEEX_SET_ENH, &tmp);
158
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
165  speex_decoder_ctl(self->decoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
166
167  fs2 = self->frame_size * _FS;
168
169  ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
170
171  if ( !self->cd ) {
172   self->cd = malloc(fs2);
173   if ( !self->cd )
174    return 0;
175  }
176
177  if ( !self->i_rest ) {
178   self->i_rest = malloc(fs2);
179   if ( !self->i_rest )
180    return 0;
181  }
182 }
183 fs2 = self->frame_size * _FS;
184
185 ROAR_DBG("cf_speex_read(*): Have a working decoder!");
186
187 ROAR_DBG("cf_speex_read(*): frame_size=%i (%i bytes)", self->frame_size, fs2);
188 ROAR_DBG("cf_speex_read(*): i_rest is %i bytes after cd", ((void*)self->i_rest - (void*)self->cd));
189
190
191 if ( self->fi_rest ) {
192  if ( self->fi_rest > (still_todo*_FS) ) {
193   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i (no need to read new data)", self->fi_rest);
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.
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;
201  } else {
202   ROAR_DBG("cf_speex_read(*): using data from input rest buffer: len=%i", self->fi_rest);
203   memcpy(buf, self->i_rest, self->fi_rest);
204   buf += self->fi_rest;
205   still_todo -= self->fi_rest/_FS;
206   ret += self->fi_rest;
207   self->fi_rest = 0;
208  }
209 }
210
211 while (still_todo) {
212  ROAR_DBG("cf_speex_read(*): we sill need %i frames", still_todo);
213  if ( stream_vio_s_read(self->stream, &ui, 2) != 2 )
214   return -1;
215
216  ui = ROAR_NET2HOST16(ui);
217
218  if ( ui > ROAR_SPEEX_MAX_CC )
219   return 0;
220
221  if ( stream_vio_s_read(self->stream, self->cc, ui) != ui )
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
228  if ( self->stereo) {
229   speex_decode_stereo_int(self->cd, self->frame_size, &(self->stereo_state));
230  }
231
232  if ( self->frame_size > still_todo ) {
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);
238   still_todo = 0;
239  } else {
240   memcpy(buf, self->cd, fs2);
241   buf        += fs2;
242   ret        += fs2;
243   still_todo -= self->frame_size;
244  }
245 }
246
247 if ( still_todo ) {
248  ROAR_DBG("cf_speex_read(*): could not read all reqquested data, returning %i byte less", still_todo*_FS);
249 }
250
251 ROAR_DBG("cf_speex_read(*) = %i", ret);
252
253 return ret;
254}
255
256int cf_speex_write(CODECFILTER_USERDATA_T   inst, char * buf, int len) {
257 struct codecfilter_speex_inst * self = (struct codecfilter_speex_inst *) inst;
258 uint16_t mode = ROAR_SPEEX_MODE_UWB;
259 int tmp;
260 int fs2;
261 int ret = 0;
262 int need_extra;
263
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
270 ROAR_DBG("cf_speex_write(inst=%p, buf=%p, len=%i) = ?", inst, buf, len);
271
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
293  fs2 = self->frame_size * _FS;
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  }
306 }
307
308 fs2 = self->frame_size * _FS;
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
317   if ( self->stereo )
318    speex_encode_stereo_int((spx_int16_t *) self->o_rest, self->frame_size, &(self->bits));
319
320   speex_encode_int(self->encoder, (spx_int16_t *) self->o_rest, &(self->bits));
321
322   tmp = mode = speex_bits_write(&(self->bits), self->cd, fs2);
323
324   mode = ROAR_HOST2NET16(mode);
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) {
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
347  if ( self->stereo )
348   speex_encode_stereo_int((spx_int16_t *) buf, self->frame_size, &(self->bits));
349
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
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}
374
375#endif
376
377//ll
Note: See TracBrowser for help on using the repository browser.