source: roaraudio/roard/codecfilter_speex.c @ 620:d612617809a5

Last change on this file since 620:d612617809a5 was 620:d612617809a5, checked in by phi, 16 years ago

added a bit docs

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