| 1 | /* |
|---|
| 2 | mediastreamer2 library - modular sound and video processing and streaming |
|---|
| 3 | Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #include "mediastreamer2/msfilter.h" |
|---|
| 21 | #include "mediastreamer2/msticker.h" |
|---|
| 22 | |
|---|
| 23 | #include <speex/speex.h> |
|---|
| 24 | |
|---|
| 25 | #ifdef WIN32 |
|---|
| 26 | #include <malloc.h> /* for alloca */ |
|---|
| 27 | #endif |
|---|
| 28 | |
|---|
| 29 | typedef struct SpeexEncState{ |
|---|
| 30 | int rate; |
|---|
| 31 | int bitrate; |
|---|
| 32 | int maxbitrate; |
|---|
| 33 | int ptime; |
|---|
| 34 | int vbr; |
|---|
| 35 | int cng; |
|---|
| 36 | int mode; |
|---|
| 37 | int frame_size; |
|---|
| 38 | void *state; |
|---|
| 39 | uint32_t ts; |
|---|
| 40 | MSBufferizer *bufferizer; |
|---|
| 41 | } SpeexEncState; |
|---|
| 42 | |
|---|
| 43 | static void enc_init(MSFilter *f){ |
|---|
| 44 | SpeexEncState *s=(SpeexEncState *)ms_new(SpeexEncState,1); |
|---|
| 45 | s->rate=8000; |
|---|
| 46 | s->bitrate=-1; |
|---|
| 47 | s->maxbitrate=-1; |
|---|
| 48 | s->ptime=0; |
|---|
| 49 | s->mode=-1; |
|---|
| 50 | s->vbr=0; |
|---|
| 51 | s->cng=0; |
|---|
| 52 | s->frame_size=0; |
|---|
| 53 | s->state=0; |
|---|
| 54 | s->ts=0; |
|---|
| 55 | s->bufferizer=ms_bufferizer_new(); |
|---|
| 56 | f->data=s; |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | static void enc_uninit(MSFilter *f){ |
|---|
| 60 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 61 | if (s==NULL) |
|---|
| 62 | return; |
|---|
| 63 | ms_bufferizer_destroy(s->bufferizer); |
|---|
| 64 | if (s->state!=NULL) |
|---|
| 65 | speex_encoder_destroy(s->state); |
|---|
| 66 | ms_free(s); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | static void enc_preprocess(MSFilter *f){ |
|---|
| 70 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 71 | const SpeexMode *mode=NULL; |
|---|
| 72 | int _mode=0; |
|---|
| 73 | |
|---|
| 74 | switch(s->rate){ |
|---|
| 75 | case 8000: |
|---|
| 76 | _mode = SPEEX_MODEID_NB; /* rate = 8000Hz */ |
|---|
| 77 | break; |
|---|
| 78 | case 16000: |
|---|
| 79 | _mode = SPEEX_MODEID_WB; /* rate = 16000Hz */ |
|---|
| 80 | break; |
|---|
| 81 | /* should be supported in the future */ |
|---|
| 82 | case 32000: |
|---|
| 83 | _mode = SPEEX_MODEID_UWB; /* rate = 32000Hz */ |
|---|
| 84 | break; |
|---|
| 85 | default: |
|---|
| 86 | ms_error("Unsupported rate for speex encoder (back to default rate=8000)."); |
|---|
| 87 | s->rate=8000; |
|---|
| 88 | } |
|---|
| 89 | /* warning: speex_lib_get_mode() is not available on speex<1.1.12 */ |
|---|
| 90 | mode = speex_lib_get_mode(_mode); |
|---|
| 91 | |
|---|
| 92 | if (mode==NULL) |
|---|
| 93 | return; |
|---|
| 94 | s->state=speex_encoder_init(mode); |
|---|
| 95 | |
|---|
| 96 | if (s->vbr==1) |
|---|
| 97 | { |
|---|
| 98 | if (speex_encoder_ctl(s->state,SPEEX_SET_VBR,&s->vbr)!=0){ |
|---|
| 99 | ms_error("Could not set vbr mode to speex encoder."); |
|---|
| 100 | } |
|---|
| 101 | /* implicit VAD */ |
|---|
| 102 | speex_encoder_ctl (s->state, SPEEX_SET_DTX, &s->vbr); |
|---|
| 103 | } |
|---|
| 104 | else if (s->vbr==2) |
|---|
| 105 | { |
|---|
| 106 | int vad=1; |
|---|
| 107 | /* VAD */ |
|---|
| 108 | speex_encoder_ctl (s->state, SPEEX_SET_VAD, &vad); |
|---|
| 109 | speex_encoder_ctl (s->state, SPEEX_SET_DTX, &vad); |
|---|
| 110 | } |
|---|
| 111 | else if (s->cng==1) |
|---|
| 112 | { |
|---|
| 113 | speex_encoder_ctl (s->state, SPEEX_SET_VAD, &s->cng); |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | if (s->rate==8000){ |
|---|
| 117 | //+------+---------------+-------------+ |
|---|
| 118 | //| mode | Speex quality | bit-rate | |
|---|
| 119 | //+------+---------------+-------------+ |
|---|
| 120 | //| 1 | 0 | 2.15 kbit/s | |
|---|
| 121 | //| 2 | 2 | 5.95 kbit/s | |
|---|
| 122 | //| 3 | 3 or 4 | 8.00 kbit/s | |
|---|
| 123 | //| 4 | 5 or 6 | 11.0 kbit/s | |
|---|
| 124 | //| 5 | 7 or 8 | 15.0 kbit/s | |
|---|
| 125 | //| 6 | 9 | 18.2 kbit/s | |
|---|
| 126 | //| 7 | 10 | 24.6 kbit/s | |
|---|
| 127 | //| 8 | 1 | 3.95 kbit/s | |
|---|
| 128 | //+------+---------------+-------------+ |
|---|
| 129 | if (s->mode<=0 || s->mode>8) |
|---|
| 130 | s->mode = 3; /* default mode */ |
|---|
| 131 | |
|---|
| 132 | if (s->mode==1) |
|---|
| 133 | s->bitrate = 2150; |
|---|
| 134 | else if (s->mode==2) |
|---|
| 135 | s->bitrate = 5950; |
|---|
| 136 | else if (s->mode==3) |
|---|
| 137 | s->bitrate = 8000; |
|---|
| 138 | else if (s->mode==4) |
|---|
| 139 | s->bitrate = 11000; |
|---|
| 140 | else if (s->mode==5) |
|---|
| 141 | s->bitrate = 15000; |
|---|
| 142 | else if (s->mode==6) |
|---|
| 143 | s->bitrate = 18200; |
|---|
| 144 | else if (s->mode==7) |
|---|
| 145 | s->bitrate = 24600; |
|---|
| 146 | else if (s->mode==8) |
|---|
| 147 | s->bitrate = 3950; |
|---|
| 148 | |
|---|
| 149 | if (s->bitrate!=-1){ |
|---|
| 150 | if (speex_encoder_ctl(s->state,SPEEX_SET_BITRATE,&s->bitrate)!=0){ |
|---|
| 151 | ms_error("Could not set bitrate %i to speex encoder.",s->bitrate); |
|---|
| 152 | } |
|---|
| 153 | } |
|---|
| 154 | } |
|---|
| 155 | else if (s->rate==16000 || s->rate==32000){ |
|---|
| 156 | //+------+---------------+-------------------+------------------------+ |
|---|
| 157 | //| mode | Speex quality | wideband bit-rate | ultra wideband | |
|---|
| 158 | //| | | | bit-rate | |
|---|
| 159 | //+------+---------------+-------------------+------------------------+ |
|---|
| 160 | //| 0 | 0 | 3.95 kbit/s | 5.75 kbit/s | |
|---|
| 161 | //| 1 | 1 | 5.75 kbit/s | 7.55 kbit/s | |
|---|
| 162 | //| 2 | 2 | 7.75 kbit/s | 9.55 kbit/s | |
|---|
| 163 | //| 3 | 3 | 9.80 kbit/s | 11.6 kbit/s | |
|---|
| 164 | //| 4 | 4 | 12.8 kbit/s | 14.6 kbit/s | |
|---|
| 165 | //| 5 | 5 | 16.8 kbit/s | 18.6 kbit/s | |
|---|
| 166 | //| 6 | 6 | 20.6 kbit/s | 22.4 kbit/s | |
|---|
| 167 | //| 7 | 7 | 23.8 kbit/s | 25.6 kbit/s | |
|---|
| 168 | //| 8 | 8 | 27.8 kbit/s | 29.6 kbit/s | |
|---|
| 169 | //| 9 | 9 | 34.2 kbit/s | 36.0 kbit/s | |
|---|
| 170 | //| 10 | 10 | 42.2 kbit/s | 44.0 kbit/s | |
|---|
| 171 | //+------+---------------+-------------------+------------------------+ |
|---|
| 172 | int q=0; |
|---|
| 173 | if (s->mode<0 || s->mode>10) |
|---|
| 174 | s->mode = 8; /* default mode */ |
|---|
| 175 | q=s->mode; |
|---|
| 176 | if (speex_encoder_ctl(s->state,SPEEX_SET_QUALITY,&q)!=0){ |
|---|
| 177 | ms_error("Could not set quality %i to speex encoder.",q); |
|---|
| 178 | } |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | if (s->maxbitrate>0){ |
|---|
| 182 | /* convert from network bitrate to codec bitrate:*/ |
|---|
| 183 | /* ((nbr/(50*8)) -20-12-8)*50*8*/ |
|---|
| 184 | int cbr=(int)( ((((float)s->maxbitrate)/(50.0*8))-20-12-8)*50*8); |
|---|
| 185 | ms_message("Setting maxbitrate=%i to speex encoder.",cbr); |
|---|
| 186 | if (speex_encoder_ctl(s->state,SPEEX_SET_BITRATE,&cbr)!=0){ |
|---|
| 187 | ms_error("Could not set maxbitrate %i to speex encoder.",s->bitrate); |
|---|
| 188 | } |
|---|
| 189 | } |
|---|
| 190 | if (speex_encoder_ctl(s->state,SPEEX_GET_BITRATE,&s->bitrate)!=0){ |
|---|
| 191 | ms_error("Could not get bitrate %i to speex encoder.",s->bitrate); |
|---|
| 192 | } |
|---|
| 193 | else ms_message("Using bitrate %i for speex encoder.",s->bitrate); |
|---|
| 194 | |
|---|
| 195 | speex_mode_query(mode,SPEEX_MODE_FRAME_SIZE,&s->frame_size); |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | static void enc_process(MSFilter *f){ |
|---|
| 199 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 200 | mblk_t *im; |
|---|
| 201 | int nbytes; |
|---|
| 202 | uint8_t *buf; |
|---|
| 203 | int frame_per_packet=1; |
|---|
| 204 | |
|---|
| 205 | if (s->frame_size<=0) |
|---|
| 206 | return; |
|---|
| 207 | |
|---|
| 208 | if (s->ptime>=20) |
|---|
| 209 | { |
|---|
| 210 | frame_per_packet = s->ptime/20; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | if (frame_per_packet<=0) |
|---|
| 214 | frame_per_packet=1; |
|---|
| 215 | if (frame_per_packet>7) /* 7*20 == 140 ms max */ |
|---|
| 216 | frame_per_packet=7; |
|---|
| 217 | |
|---|
| 218 | nbytes=s->frame_size*2; |
|---|
| 219 | buf=(uint8_t*)alloca(nbytes*frame_per_packet); |
|---|
| 220 | |
|---|
| 221 | while((im=ms_queue_get(f->inputs[0]))!=NULL){ |
|---|
| 222 | ms_bufferizer_put(s->bufferizer,im); |
|---|
| 223 | } |
|---|
| 224 | while(ms_bufferizer_read(s->bufferizer,buf,nbytes*frame_per_packet)==nbytes*frame_per_packet){ |
|---|
| 225 | mblk_t *om=allocb(nbytes*frame_per_packet,0);//too large... |
|---|
| 226 | int k; |
|---|
| 227 | SpeexBits bits; |
|---|
| 228 | speex_bits_init(&bits); |
|---|
| 229 | for (k=0;k<frame_per_packet;k++) |
|---|
| 230 | { |
|---|
| 231 | speex_encode_int(s->state,(int16_t*)(buf + (k*s->frame_size*2)),&bits); |
|---|
| 232 | s->ts+=s->frame_size; |
|---|
| 233 | } |
|---|
| 234 | speex_bits_insert_terminator(&bits); |
|---|
| 235 | k=speex_bits_write(&bits, (char*)om->b_wptr, nbytes*frame_per_packet); |
|---|
| 236 | om->b_wptr+=k; |
|---|
| 237 | |
|---|
| 238 | mblk_set_timestamp_info(om,s->ts-s->frame_size); |
|---|
| 239 | ms_queue_put(f->outputs[0],om); |
|---|
| 240 | speex_bits_destroy(&bits); |
|---|
| 241 | } |
|---|
| 242 | } |
|---|
| 243 | |
|---|
| 244 | static void enc_postprocess(MSFilter *f){ |
|---|
| 245 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 246 | speex_encoder_destroy(s->state); |
|---|
| 247 | s->state=NULL; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | static int enc_set_sr(MSFilter *f, void *arg){ |
|---|
| 251 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 252 | /* TODO: should be done with fmtp parameter */ |
|---|
| 253 | s->rate=((int*)arg)[0]; |
|---|
| 254 | return 0; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | static int enc_set_br(MSFilter *f, void *arg){ |
|---|
| 258 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 259 | s->maxbitrate=((int*)arg)[0]; |
|---|
| 260 | return 0; |
|---|
| 261 | } |
|---|
| 262 | |
|---|
| 263 | static int enc_add_fmtp(MSFilter *f, void *arg){ |
|---|
| 264 | char buf[64]; |
|---|
| 265 | const char *fmtp=(const char *)arg; |
|---|
| 266 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 267 | |
|---|
| 268 | memset(buf, '\0', sizeof(buf)); |
|---|
| 269 | fmtp_get_value(fmtp, "vbr", buf, sizeof(buf)); |
|---|
| 270 | if (buf[0]=='\0'){ |
|---|
| 271 | } |
|---|
| 272 | else if (strstr(buf,"off")!=NULL){ |
|---|
| 273 | s->vbr=0; |
|---|
| 274 | } |
|---|
| 275 | else if (strstr(buf,"on")!=NULL){ |
|---|
| 276 | s->vbr=1; |
|---|
| 277 | } |
|---|
| 278 | else if (strstr(buf,"vad")!=NULL){ |
|---|
| 279 | s->vbr=2; |
|---|
| 280 | } |
|---|
| 281 | |
|---|
| 282 | memset(buf, '\0', sizeof(buf)); |
|---|
| 283 | fmtp_get_value(fmtp, "cng", buf, sizeof(buf)); |
|---|
| 284 | if (buf[0]=='\0'){ |
|---|
| 285 | } |
|---|
| 286 | else if (strstr(buf,"off")!=NULL){ |
|---|
| 287 | s->cng=0; |
|---|
| 288 | } |
|---|
| 289 | else if (strstr(buf,"on")!=NULL){ |
|---|
| 290 | s->cng=1; |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | memset(buf, '\0', sizeof(buf)); |
|---|
| 294 | fmtp_get_value(fmtp, "mode", buf, sizeof(buf)); |
|---|
| 295 | if (buf[0]=='\0' || buf[1]=='\0'){ |
|---|
| 296 | } |
|---|
| 297 | else if (buf[0]=='0' || (buf[0]=='"' && buf[1]=='0')){ |
|---|
| 298 | s->mode=0; |
|---|
| 299 | } |
|---|
| 300 | else if (buf[0]=='"' && atoi(buf+1)>=0){ |
|---|
| 301 | s->mode=atoi(buf+1); |
|---|
| 302 | } |
|---|
| 303 | else if (buf[0]!='"' && atoi(buf)>=0){ |
|---|
| 304 | s->mode=atoi(buf); |
|---|
| 305 | } |
|---|
| 306 | else { |
|---|
| 307 | s->mode = -1; /* deault mode */ |
|---|
| 308 | } |
|---|
| 309 | return 0; |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | static int enc_add_attr(MSFilter *f, void *arg){ |
|---|
| 313 | const char *fmtp=(const char *)arg; |
|---|
| 314 | SpeexEncState *s=(SpeexEncState*)f->data; |
|---|
| 315 | if (strstr(fmtp,"ptime:10")!=NULL){ |
|---|
| 316 | s->ptime=20; |
|---|
| 317 | }else if (strstr(fmtp,"ptime:20")!=NULL){ |
|---|
| 318 | s->ptime=20; |
|---|
| 319 | }else if (strstr(fmtp,"ptime:30")!=NULL){ |
|---|
| 320 | s->ptime=40; |
|---|
| 321 | }else if (strstr(fmtp,"ptime:40")!=NULL){ |
|---|
| 322 | s->ptime=40; |
|---|
| 323 | }else if (strstr(fmtp,"ptime:50")!=NULL){ |
|---|
| 324 | s->ptime=60; |
|---|
| 325 | }else if (strstr(fmtp,"ptime:60")!=NULL){ |
|---|
| 326 | s->ptime=60; |
|---|
| 327 | }else if (strstr(fmtp,"ptime:70")!=NULL){ |
|---|
| 328 | s->ptime=80; |
|---|
| 329 | }else if (strstr(fmtp,"ptime:80")!=NULL){ |
|---|
| 330 | s->ptime=80; |
|---|
| 331 | }else if (strstr(fmtp,"ptime:90")!=NULL){ |
|---|
| 332 | s->ptime=100; /* not allowed */ |
|---|
| 333 | }else if (strstr(fmtp,"ptime:100")!=NULL){ |
|---|
| 334 | s->ptime=100; |
|---|
| 335 | }else if (strstr(fmtp,"ptime:110")!=NULL){ |
|---|
| 336 | s->ptime=120; |
|---|
| 337 | }else if (strstr(fmtp,"ptime:120")!=NULL){ |
|---|
| 338 | s->ptime=120; |
|---|
| 339 | }else if (strstr(fmtp,"ptime:130")!=NULL){ |
|---|
| 340 | s->ptime=140; |
|---|
| 341 | }else if (strstr(fmtp,"ptime:140")!=NULL){ |
|---|
| 342 | s->ptime=140; |
|---|
| 343 | } |
|---|
| 344 | return 0; |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | static MSFilterMethod enc_methods[]={ |
|---|
| 348 | { MS_FILTER_SET_SAMPLE_RATE , enc_set_sr }, |
|---|
| 349 | { MS_FILTER_SET_BITRATE , enc_set_br }, |
|---|
| 350 | { MS_FILTER_ADD_FMTP , enc_add_fmtp }, |
|---|
| 351 | { MS_FILTER_ADD_ATTR , enc_add_attr}, |
|---|
| 352 | { 0 , NULL } |
|---|
| 353 | }; |
|---|
| 354 | |
|---|
| 355 | #ifdef _MSC_VER |
|---|
| 356 | |
|---|
| 357 | MSFilterDesc ms_speex_enc_desc={ |
|---|
| 358 | MS_SPEEX_ENC_ID, |
|---|
| 359 | "MSSpeexEnc", |
|---|
| 360 | N_("The free and wonderful speex codec"), |
|---|
| 361 | MS_FILTER_ENCODER, |
|---|
| 362 | "speex", |
|---|
| 363 | 1, |
|---|
| 364 | 1, |
|---|
| 365 | enc_init, |
|---|
| 366 | enc_preprocess, |
|---|
| 367 | enc_process, |
|---|
| 368 | enc_postprocess, |
|---|
| 369 | enc_uninit, |
|---|
| 370 | enc_methods |
|---|
| 371 | }; |
|---|
| 372 | |
|---|
| 373 | #else |
|---|
| 374 | |
|---|
| 375 | MSFilterDesc ms_speex_enc_desc={ |
|---|
| 376 | .id=MS_SPEEX_ENC_ID, |
|---|
| 377 | .name="MSSpeexEnc", |
|---|
| 378 | .text=N_("The free and wonderful speex codec"), |
|---|
| 379 | .category=MS_FILTER_ENCODER, |
|---|
| 380 | .enc_fmt="speex", |
|---|
| 381 | .ninputs=1, |
|---|
| 382 | .noutputs=1, |
|---|
| 383 | .init=enc_init, |
|---|
| 384 | .preprocess=enc_preprocess, |
|---|
| 385 | .postprocess=enc_postprocess, |
|---|
| 386 | .process=enc_process, |
|---|
| 387 | .uninit=enc_uninit, |
|---|
| 388 | .methods=enc_methods |
|---|
| 389 | }; |
|---|
| 390 | |
|---|
| 391 | #endif |
|---|
| 392 | |
|---|
| 393 | typedef struct DecState{ |
|---|
| 394 | int rate; |
|---|
| 395 | int penh; |
|---|
| 396 | int frsz; |
|---|
| 397 | uint64_t sample_time; |
|---|
| 398 | void *state; |
|---|
| 399 | } DecState; |
|---|
| 400 | |
|---|
| 401 | static void dec_init(MSFilter *f){ |
|---|
| 402 | DecState *s=(DecState *)ms_new(DecState,1); |
|---|
| 403 | s->rate=8000; |
|---|
| 404 | s->frsz=0; |
|---|
| 405 | s->state=NULL; |
|---|
| 406 | s->penh=1; |
|---|
| 407 | s->sample_time=0; |
|---|
| 408 | f->data=s; |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | static void dec_uninit(MSFilter *f){ |
|---|
| 412 | DecState *s=(DecState*)f->data; |
|---|
| 413 | if (s==NULL) |
|---|
| 414 | return; |
|---|
| 415 | if (s->state!=NULL) |
|---|
| 416 | speex_decoder_destroy(s->state); |
|---|
| 417 | ms_free(s); |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | static void dec_preprocess(MSFilter *f){ |
|---|
| 421 | DecState *s=(DecState*)f->data; |
|---|
| 422 | const SpeexMode *mode=NULL; |
|---|
| 423 | int modeid; |
|---|
| 424 | switch(s->rate){ |
|---|
| 425 | case 8000: |
|---|
| 426 | modeid = SPEEX_MODEID_NB; /* rate = 8000Hz */ |
|---|
| 427 | break; |
|---|
| 428 | case 16000: |
|---|
| 429 | modeid = SPEEX_MODEID_WB; /* rate = 16000Hz */ |
|---|
| 430 | break; |
|---|
| 431 | /* should be supported in the future */ |
|---|
| 432 | case 32000: |
|---|
| 433 | modeid = SPEEX_MODEID_UWB; /* rate = 32000Hz */ |
|---|
| 434 | break; |
|---|
| 435 | default: |
|---|
| 436 | ms_error("Unsupported rate for speex decoder (back to default rate=8000)."); |
|---|
| 437 | modeid=SPEEX_MODEID_NB; |
|---|
| 438 | } |
|---|
| 439 | /* warning: speex_lib_get_mode() is not available on speex<1.1.12 */ |
|---|
| 440 | mode = speex_lib_get_mode(modeid); |
|---|
| 441 | s->state=speex_decoder_init(mode); |
|---|
| 442 | speex_mode_query(mode,SPEEX_MODE_FRAME_SIZE,&s->frsz); |
|---|
| 443 | if (s->penh==1) |
|---|
| 444 | speex_decoder_ctl (s->state, SPEEX_SET_ENH, &s->penh); |
|---|
| 445 | s->sample_time=0; |
|---|
| 446 | } |
|---|
| 447 | |
|---|
| 448 | static void dec_postprocess(MSFilter *f){ |
|---|
| 449 | DecState *s=(DecState*)f->data; |
|---|
| 450 | speex_decoder_destroy(s->state); |
|---|
| 451 | s->state=NULL; |
|---|
| 452 | } |
|---|
| 453 | |
|---|
| 454 | static int dec_set_sr(MSFilter *f, void *arg){ |
|---|
| 455 | DecState *s=(DecState*)f->data; |
|---|
| 456 | s->rate=((int*)arg)[0]; |
|---|
| 457 | return 0; |
|---|
| 458 | } |
|---|
| 459 | |
|---|
| 460 | static void dec_process(MSFilter *f){ |
|---|
| 461 | DecState *s=(DecState*)f->data; |
|---|
| 462 | mblk_t *im; |
|---|
| 463 | mblk_t *om; |
|---|
| 464 | int err=-2; |
|---|
| 465 | SpeexBits bits; |
|---|
| 466 | int bytes=s->frsz*2; |
|---|
| 467 | bool_t bits_initd=FALSE; |
|---|
| 468 | |
|---|
| 469 | while((im=ms_queue_get(f->inputs[0]))!=NULL){ |
|---|
| 470 | int rem_bits=(im->b_wptr-im->b_rptr)*8; |
|---|
| 471 | |
|---|
| 472 | if (s->sample_time==0){ |
|---|
| 473 | s->sample_time=f->ticker->time; |
|---|
| 474 | } |
|---|
| 475 | |
|---|
| 476 | if (!bits_initd) { |
|---|
| 477 | speex_bits_init(&bits); |
|---|
| 478 | bits_initd=TRUE; |
|---|
| 479 | }else speex_bits_reset(&bits); |
|---|
| 480 | |
|---|
| 481 | speex_bits_read_from(&bits,(char*)im->b_rptr,im->b_wptr-im->b_rptr); |
|---|
| 482 | |
|---|
| 483 | /* support for multiple frame in one RTP packet */ |
|---|
| 484 | do{ |
|---|
| 485 | om=allocb(bytes,0); |
|---|
| 486 | err=speex_decode_int(s->state,&bits,(int16_t*)om->b_wptr); |
|---|
| 487 | om->b_wptr+=bytes; |
|---|
| 488 | |
|---|
| 489 | if (err==0){ |
|---|
| 490 | ms_queue_put(f->outputs[0],om); |
|---|
| 491 | s->sample_time+=20; |
|---|
| 492 | }else { |
|---|
| 493 | if (err==-1) |
|---|
| 494 | ms_warning("speex end of stream"); |
|---|
| 495 | else if (err==-2) |
|---|
| 496 | ms_warning("speex corrupted stream"); |
|---|
| 497 | freemsg(om); |
|---|
| 498 | } |
|---|
| 499 | }while((rem_bits= speex_bits_remaining(&bits))>10); |
|---|
| 500 | freemsg(im); |
|---|
| 501 | } |
|---|
| 502 | if (s->sample_time!=0 && f->ticker->time>s->sample_time){ |
|---|
| 503 | /* we should output a frame but no packet were decoded |
|---|
| 504 | thus do packet loss concealment*/ |
|---|
| 505 | om=allocb(bytes,0); |
|---|
| 506 | err=speex_decode_int(s->state,NULL,(int16_t*)om->b_wptr); |
|---|
| 507 | om->b_wptr+=bytes; |
|---|
| 508 | ms_queue_put(f->outputs[0],om); |
|---|
| 509 | ms_warning("Doing speex packet loss concealment."); |
|---|
| 510 | s->sample_time+=20; |
|---|
| 511 | } |
|---|
| 512 | if (bits_initd) speex_bits_destroy(&bits); |
|---|
| 513 | } |
|---|
| 514 | |
|---|
| 515 | static MSFilterMethod dec_methods[]={ |
|---|
| 516 | { MS_FILTER_SET_SAMPLE_RATE , dec_set_sr }, |
|---|
| 517 | { 0 , NULL } |
|---|
| 518 | }; |
|---|
| 519 | |
|---|
| 520 | #ifdef _MSC_VER |
|---|
| 521 | |
|---|
| 522 | MSFilterDesc ms_speex_dec_desc={ |
|---|
| 523 | MS_SPEEX_DEC_ID, |
|---|
| 524 | "MSSpeexDec", |
|---|
| 525 | N_("The free and wonderful speex codec"), |
|---|
| 526 | MS_FILTER_DECODER, |
|---|
| 527 | "speex", |
|---|
| 528 | 1, |
|---|
| 529 | 1, |
|---|
| 530 | dec_init, |
|---|
| 531 | dec_preprocess, |
|---|
| 532 | dec_process, |
|---|
| 533 | dec_postprocess, |
|---|
| 534 | dec_uninit, |
|---|
| 535 | dec_methods |
|---|
| 536 | }; |
|---|
| 537 | |
|---|
| 538 | #else |
|---|
| 539 | |
|---|
| 540 | MSFilterDesc ms_speex_dec_desc={ |
|---|
| 541 | .id=MS_SPEEX_DEC_ID, |
|---|
| 542 | .name="MSSpeexDec", |
|---|
| 543 | .text=N_("The free and wonderful speex codec"), |
|---|
| 544 | .category=MS_FILTER_DECODER, |
|---|
| 545 | .enc_fmt="speex", |
|---|
| 546 | .ninputs=1, |
|---|
| 547 | .noutputs=1, |
|---|
| 548 | .init=dec_init, |
|---|
| 549 | .preprocess=dec_preprocess, |
|---|
| 550 | .postprocess=dec_postprocess, |
|---|
| 551 | .process=dec_process, |
|---|
| 552 | .uninit=dec_uninit, |
|---|
| 553 | .methods=dec_methods |
|---|
| 554 | }; |
|---|
| 555 | |
|---|
| 556 | #endif |
|---|
| 557 | |
|---|
| 558 | MS_FILTER_DESC_EXPORT(ms_speex_dec_desc) |
|---|
| 559 | MS_FILTER_DESC_EXPORT(ms_speex_enc_desc) |
|---|