source: roaraudio/libroardsp/transcode_speex.c @ 5546:faff3e9677c4

Last change on this file since 5546:faff3e9677c4 was 5515:1bbc92b50075, checked in by phi, 12 years ago

fixed a compiler warning

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