source: roaraudio/roard/codecfilter_speex.c @ 668:71ac426690da

Last change on this file since 668:71ac426690da was 668:71ac426690da, checked in by phi, 16 years ago

added license statements

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