source: roaraudio/libroardsp/transcode_speex.c @ 2974:c0a12639565a

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

set the correct option

File size: 9.4 KB
Line 
1//transcode_speex.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2009
5 *
6 *  This file is part of libroardsp 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 *  libroardsp 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 "libroardsp.h"
26
27#ifdef ROAR_HAVE_LIBSPEEX
28
29#define _16BIT (16/8)
30#define _SIZE_LEN 2
31
32#define _HAVE_CCFG(x) (self->codec_config != NULL && (self->codec_config->para_set & (x)))
33
34int roar_xcoder_speex_init       (struct roar_xcoder * state) {
35 struct roar_xcoder_speex * self = malloc(sizeof(struct roar_xcoder_speex));
36 struct roar_audio_info  * info = &(state->info.pcm);
37 int tmp;
38
39 ROAR_DBG("roar_xcoder_speex_init(*): sizeof(*self) = %lu", (unsigned long)sizeof(*self));
40
41 if ( self == NULL )
42  return -1;
43
44 // curruntly only 16 bit mode is supported
45 if ( info->bits != 16 ) {
46  free(self);
47  return -1;
48 }
49
50 // only mono/stereo mode is supported
51 switch (info->channels) {
52  case 1: self->stereo = 0; break;
53  case 2: self->stereo = 1; break;
54  default:
55    free(self);
56    return -1;
57 }
58
59 memset(self, 0, sizeof(struct roar_xcoder_speex));
60
61 state->inst = self;
62
63 self->mode  = ROAR_SPEEX_MODE_UWB;
64
65 if (state->encode) {
66  self->codec_config = roar_libroar_config_codec_get(ROAR_CODEC_ROAR_SPEEX, 0);
67  self->max_cc = ROAR_SPEEX_MAX_CC;
68
69  ROAR_DBG("roar_xcoder_speex_init(*): self->codec_config=%p", self->codec_config);
70
71  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_MAX_CC) ) {
72   self->max_cc = self->codec_config->max_cc;
73  }
74
75  if ( info->rate < 12000 ) {
76   self->mode = ROAR_SPEEX_MODE_NB;  // optimized for 8kHz
77  } else if ( info->rate < 24000 ) {
78   self->mode = ROAR_SPEEX_MODE_WB;  // optimized for 16kHz
79  } else {
80   self->mode = ROAR_SPEEX_MODE_UWB; // optimized for 32kHz
81  }
82
83  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_MODE) ) {
84   // NB, WB and UWB mode numbers are the same for Speex and codec config.
85   self->mode   = self->codec_config->mode;
86  }
87
88  switch (self->mode) {
89   case ROAR_SPEEX_MODE_NB:  self->xcoder = speex_encoder_init(&speex_nb_mode);  break;
90   case ROAR_SPEEX_MODE_WB:  self->xcoder = speex_encoder_init(&speex_wb_mode);  break;
91   case ROAR_SPEEX_MODE_UWB: self->xcoder = speex_encoder_init(&speex_uwb_mode); break;
92   default: return -1;
93  }
94
95  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_COMPLEXITY) ) {
96   tmp = self->codec_config->complexity / 256;
97  } else {
98   tmp = 8;
99  }
100  speex_encoder_ctl(self->xcoder, SPEEX_SET_COMPLEXITY,    &tmp);
101
102  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_Q) ) {
103   tmp = self->codec_config->q / 256;
104   speex_encoder_ctl(self->xcoder, SPEEX_SET_QUALITY,      &tmp);
105  }
106
107  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_VBR) ) {
108   tmp = self->codec_config->vbr ? 1 : 0;
109   speex_encoder_ctl(self->xcoder, SPEEX_SET_VBR,          &tmp);
110  }
111
112  if ( _HAVE_CCFG(ROAR_LIBROAR_CONFIG_PSET_DTX) ) {
113   tmp = self->codec_config->dtx ? 1 : 0;
114   speex_encoder_ctl(self->xcoder, SPEEX_SET_DTX,          &tmp);
115  }
116
117  tmp = info->rate;
118  speex_encoder_ctl(self->xcoder, SPEEX_SET_SAMPLING_RATE, &tmp);
119  speex_encoder_ctl(self->xcoder, SPEEX_GET_FRAME_SIZE,    &(self->frame_size));
120 } else {
121  self->xcoder = NULL;
122 }
123
124 speex_bits_init(&(self->bits));
125
126 return 0;
127}
128
129int roar_xcoder_speex_uninit     (struct roar_xcoder * state) {
130 struct roar_xcoder_speex * self = state->inst;
131
132 if ( self->xcoder != NULL ) {
133  if (state->encode) {
134   speex_encoder_destroy(self->xcoder);
135  } else {
136   speex_decoder_destroy(self->xcoder);
137  }
138 }
139
140 speex_bits_destroy(&(self->bits));
141
142 free(self);
143
144 return 0;
145}
146
147int roar_xcoder_speex_packet_size(struct roar_xcoder * state, int samples) {
148 struct roar_xcoder_speex * self = state->inst;
149
150 if (!state->encode)
151  if (state->stage != ROAR_XCODER_STAGE_OPENED)
152   return -1;
153
154 return _16BIT * self->frame_size * (self->stereo ? 2 : 1);
155}
156
157int roar_xcoder_speex_proc_header(struct roar_xcoder * state) {
158 struct roar_xcoder_speex * self = state->inst;
159 uint16_t tmp_net;
160 int tmp;
161 SpeexStereoState stereo = SPEEX_STEREO_STATE_INIT;
162 SpeexCallback callback;
163 char magic[ROAR_SPEEX_MAGIC_LEN];
164
165 // we do allready open streams not considder an error.
166 if ( state->stage == ROAR_XCODER_STAGE_OPENED )
167  return 0;
168
169 // everything else expected an INITED stream (OPENING, MAGIC,..)
170 // is an error...
171 if ( state->stage != ROAR_XCODER_STAGE_INITED )
172  return -1;
173
174 if ( state->encode ) {
175  if ( roar_vio_write(state->backend, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN) != ROAR_SPEEX_MAGIC_LEN )
176   return -1;
177  state->stage = ROAR_XCODER_STAGE_MAGIC;
178  ROAR_DBG("roar_xcoder_speex_encode(*): Wrote MAGIC");
179
180  state->stage = ROAR_XCODER_STAGE_OPENING;
181
182  tmp_net = ROAR_HOST2NET16(self->mode);
183  if ( roar_vio_write(state->backend, &tmp_net, 2) != 2 )
184   return -1;
185
186  state->stage = ROAR_XCODER_STAGE_OPENED;
187 } else {
188  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): state->stage = INITED", state, buf, (unsigned long)len);
189  if ( roar_vio_read(state->backend, magic, ROAR_SPEEX_MAGIC_LEN) != ROAR_SPEEX_MAGIC_LEN )
190   return -1;
191
192  if ( memcmp(magic, ROAR_SPEEX_MAGIC, ROAR_SPEEX_MAGIC_LEN) != 0 )
193   return -1;
194
195  state->stage = ROAR_XCODER_STAGE_MAGIC;
196  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): state->stage = MAGIC", state, buf, (unsigned long)len);
197
198  if ( roar_vio_read(state->backend, &tmp_net, 2) != 2 )
199   return -1;
200
201  self->mode = ROAR_NET2HOST16(tmp_net);
202
203  state->stage = ROAR_XCODER_STAGE_OPENING;
204  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): state->stage = OPENING", state, buf, (unsigned long)len);
205
206  switch (self->mode) {
207   case ROAR_SPEEX_MODE_NB:  self->xcoder = speex_decoder_init(&speex_nb_mode);  break;
208   case ROAR_SPEEX_MODE_WB:  self->xcoder = speex_decoder_init(&speex_wb_mode);  break;
209   case ROAR_SPEEX_MODE_UWB: self->xcoder = speex_decoder_init(&speex_uwb_mode); break;
210   default: return -1;
211  }
212
213  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): opened decoder state", state, buf, (unsigned long)len);
214
215  tmp=1;
216  speex_decoder_ctl(self->xcoder, SPEEX_SET_ENH, &tmp);
217  tmp = state->info.pcm.rate;
218  speex_decoder_ctl(self->xcoder, SPEEX_SET_SAMPLING_RATE, &tmp);
219  speex_decoder_ctl(self->xcoder, SPEEX_GET_FRAME_SIZE, &(self->frame_size));
220
221  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): self->stereo = %i", state, buf, (unsigned long)len, self->stereo);
222
223  if ( self->stereo ) {
224   memcpy(&(self->stereo_state), &stereo, sizeof(self->stereo_state));
225
226   callback.callback_id = SPEEX_INBAND_STEREO;
227   callback.func = speex_std_stereo_request_handler;
228   callback.data = &(self->stereo_state);
229
230   speex_decoder_ctl(self->xcoder, SPEEX_SET_HANDLER, &callback);
231  }
232
233  state->stage = ROAR_XCODER_STAGE_OPENED;
234  ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): state->stage = OPENED", state, buf, (unsigned long)len);
235 }
236
237 // on no error...
238 return 0;
239}
240
241int roar_xcoder_speex_encode     (struct roar_xcoder * state, void * buf, size_t len) {
242 struct roar_xcoder_speex * self = state->inst;
243 int pkg_len;
244
245 if (!state->encode)
246  return -1;
247
248 ROAR_DBG("roar_xcoder_speex_encode(*): Encoding...");
249
250 if ( state->stage == ROAR_XCODER_STAGE_INITED )
251  if ( roar_xcoder_speex_proc_header(state) == -1 )
252   return -1;
253
254 speex_bits_reset(&(self->bits));
255
256 if ( self->stereo )
257  speex_encode_stereo_int((spx_int16_t *) buf, self->frame_size, &(self->bits));
258
259 speex_encode_int(self->xcoder, (spx_int16_t *) buf, &(self->bits));
260
261 pkg_len = speex_bits_write(&(self->bits), self->cc + 2, self->max_cc);
262
263 *((uint16_t*)self->cc) = ROAR_HOST2NET16(pkg_len);
264
265 if ( roar_vio_write(state->backend, self->cc, pkg_len + 2) != (pkg_len + 2) )
266   return -1;
267
268 return 0;
269}
270
271// TODO: move all the init thingys into a seperate function
272int roar_xcoder_speex_decode     (struct roar_xcoder * state, void * buf, size_t len) {
273 struct roar_xcoder_speex * self = state->inst;
274 uint16_t tmp_net;
275 int pkg_len;
276
277 ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu) = ?", state, buf, (unsigned long)len);
278
279 if ( state->stage == ROAR_XCODER_STAGE_INITED )
280  if ( roar_xcoder_speex_proc_header(state) == -1 )
281   return -1;
282
283 ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu): state->stage = %s", state, buf, (unsigned long)len,
284          state->stage == ROAR_XCODER_STAGE_OPENED ? "OPENED" : "???"
285         );
286
287 if ( roar_vio_read(state->backend, &tmp_net, 2) != 2 )
288  return -1;
289
290 pkg_len = ROAR_NET2HOST16(tmp_net);
291
292 if ( pkg_len > ROAR_SPEEX_MAX_CC )
293  return -1;
294
295 ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu) = ?", state, buf, (unsigned long)len);
296
297 if ( roar_vio_read(state->backend, self->cc, pkg_len) != pkg_len )
298  return -1;
299
300 speex_bits_read_from(&(self->bits), self->cc, pkg_len);
301
302 speex_decode_int(self->xcoder, &(self->bits), buf);
303
304 if ( self->stereo ) {
305  speex_decode_stereo_int(buf, self->frame_size, &(self->stereo_state));
306 }
307
308 ROAR_DBG("roar_xcoder_speex_decode(state=%p, buf=%p, len=%lu) = 0", state, buf, (unsigned long)len);
309 return 0;
310}
311
312#endif
313
314//ll
Note: See TracBrowser for help on using the repository browser.