Changeset 2506 for pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
- Timestamp:
- Mar 12, 2009 6:11:37 PM (14 years ago)
- Location:
- pjproject/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk
-
Property
svn:mergeinfo
set to
False
/pjproject/branches/projects/aps-direct merged eligible
-
Property
svn:mergeinfo
set to
False
-
pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
r2394 r2506 19 19 */ 20 20 #include <pjmedia/sound_port.h> 21 #include <pjmedia/alaw_ulaw.h> 21 22 #include <pjmedia/delaybuf.h> 22 23 #include <pjmedia/echo.h> 23 24 #include <pjmedia/errno.h> 24 #include <pjmedia/plc.h>25 25 #include <pj/assert.h> 26 26 #include <pj/log.h> … … 28 28 #include <pj/string.h> /* pj_memset() */ 29 29 30 //#define SIMULATE_LOST_PCT 2031 30 #define AEC_TAIL 128 /* default AEC length in ms */ 32 31 #define AEC_SUSPEND_LIMIT 5 /* seconds of no activity */ … … 36 35 //#define TEST_OVERFLOW_UNDERFLOW 37 36 38 enum39 {40 PJMEDIA_PLC_ENABLED = 1,41 };42 43 //#define DEFAULT_OPTIONS PJMEDIA_PLC_ENABLED44 #define DEFAULT_OPTIONS 045 46 47 37 struct pjmedia_snd_port 48 38 { 49 39 int rec_id; 50 40 int play_id; 51 pjmedia_snd_stream *snd_stream; 41 pj_uint32_t aud_caps; 42 pjmedia_aud_param aud_param; 43 pjmedia_aud_stream *aud_stream; 52 44 pjmedia_dir dir; 53 45 pjmedia_port *port; 54 unsigned options;55 56 pjmedia_echo_state *ec_state;57 unsigned aec_tail_len;58 59 pj_bool_t ec_suspended;60 unsigned ec_suspend_count;61 unsigned ec_suspend_limit;62 63 pjmedia_plc *plc;64 46 65 47 unsigned clock_rate; … … 68 50 unsigned bits_per_sample; 69 51 70 #if PJMEDIA_SOUND_USE_DELAYBUF 71 pjmedia_delay_buf *delay_buf; 72 #endif 52 /* software ec */ 53 pjmedia_echo_state *ec_state; 54 unsigned ec_options; 55 unsigned ec_tail_len; 56 pj_bool_t ec_suspended; 57 unsigned ec_suspend_count; 58 unsigned ec_suspend_limit; 73 59 }; 74 60 … … 77 63 * played. 78 64 */ 79 static pj_status_t play_cb(/* in */ void *user_data, 80 /* in */ pj_uint32_t timestamp, 81 /* out */ void *output, 82 /* out */ unsigned size) 65 static pj_status_t play_cb(void *user_data, pjmedia_frame *frame) 83 66 { 84 67 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 85 68 pjmedia_port *port; 86 pjmedia_frame frame;69 unsigned required_size = frame->size; 87 70 pj_status_t status; 88 71 89 /* We're risking accessing the port without holding any mutex.90 * It's possible that port is disconnected then destroyed while91 * we're trying to access it.92 * But in the name of performance, we'll try this approach until93 * someone complains when it crashes.94 */95 72 port = snd_port->port; 96 73 if (port == NULL) 97 74 goto no_frame; 98 75 99 frame.buf = output; 100 frame.size = size; 101 frame.timestamp.u32.hi = 0; 102 frame.timestamp.u32.lo = timestamp; 103 104 #if PJMEDIA_SOUND_USE_DELAYBUF 105 if (snd_port->delay_buf) { 106 status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output); 107 if (status != PJ_SUCCESS) 108 pj_bzero(output, size); 109 110 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 111 pjmedia_port_put_frame(port, &frame); 112 113 #ifdef TEST_OVERFLOW_UNDERFLOW 114 { 115 static int count = 1; 116 if (++count % 10 == 0) { 117 status = pjmedia_delay_buf_get(snd_port->delay_buf, 118 (pj_int16_t*)output); 119 if (status != PJ_SUCCESS) 120 pj_bzero(output, size); 121 122 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 123 pjmedia_port_put_frame(port, &frame); 124 } 125 } 126 #endif 127 128 } 129 #endif 130 131 status = pjmedia_port_get_frame(port, &frame); 76 status = pjmedia_port_get_frame(port, frame); 132 77 if (status != PJ_SUCCESS) 133 78 goto no_frame; 134 79 135 if (frame .type != PJMEDIA_FRAME_TYPE_AUDIO)80 if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) 136 81 goto no_frame; 137 82 138 83 /* Must supply the required samples */ 139 pj_assert(frame.size == size); 140 141 #ifdef SIMULATE_LOST_PCT 142 /* Simulate packet lost */ 143 if (pj_rand() % 100 < SIMULATE_LOST_PCT) { 144 PJ_LOG(4,(THIS_FILE, "Frame dropped")); 145 goto no_frame; 146 } 147 #endif 148 149 if (snd_port->plc) 150 pjmedia_plc_save(snd_port->plc, (pj_int16_t*) output); 84 PJ_UNUSED_ARG(required_size); 85 pj_assert(frame->size == required_size); 151 86 152 87 if (snd_port->ec_state) { … … 157 92 } 158 93 snd_port->ec_suspend_count = 0; 159 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*) output);94 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 160 95 } 161 96 … … 173 108 if (snd_port->ec_state) { 174 109 /* To maintain correct delay in EC */ 175 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output); 176 } 177 } 178 179 /* Apply PLC */ 180 if (snd_port->plc) { 181 182 pjmedia_plc_generate(snd_port->plc, (pj_int16_t*) output); 183 #ifdef SIMULATE_LOST_PCT 184 PJ_LOG(4,(THIS_FILE, "Lost frame generated")); 185 #endif 186 } else { 187 pj_bzero(output, size); 188 } 189 110 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 111 } 112 } 190 113 191 114 return PJ_SUCCESS; … … 197 120 * frame. 198 121 */ 199 static pj_status_t rec_cb(/* in */ void *user_data, 200 /* in */ pj_uint32_t timestamp, 201 /* in */ void *input, 202 /* in*/ unsigned size) 122 static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame) 203 123 { 204 124 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 205 125 pjmedia_port *port; 206 pjmedia_frame frame; 207 208 /* We're risking accessing the port without holding any mutex. 209 * It's possible that port is disconnected then destroyed while 210 * we're trying to access it. 211 * But in the name of performance, we'll try this approach until 212 * someone complains when it crashes. 213 */ 126 214 127 port = snd_port->port; 215 128 if (port == NULL) … … 218 131 /* Cancel echo */ 219 132 if (snd_port->ec_state && !snd_port->ec_suspended) { 220 pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0); 221 } 222 223 #if PJMEDIA_SOUND_USE_DELAYBUF 224 if (snd_port->delay_buf) { 225 pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input); 226 } else { 227 frame.buf = (void*)input; 228 frame.size = size; 229 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 230 frame.timestamp.u32.lo = timestamp; 231 232 pjmedia_port_put_frame(port, &frame); 233 } 234 #else 235 frame.buf = (void*)input; 236 frame.size = size; 237 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 238 frame.timestamp.u32.lo = timestamp; 239 240 pjmedia_port_put_frame(port, &frame); 241 #endif 133 pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0); 134 } 135 136 pjmedia_port_put_frame(port, frame); 137 138 return PJ_SUCCESS; 139 } 140 141 /* 142 * The callback called by sound player when it needs more samples to be 143 * played. This version is for non-PCM data. 144 */ 145 static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 146 { 147 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 148 pjmedia_port *port = snd_port->port; 149 150 if (port == NULL) { 151 frame->type = PJMEDIA_FRAME_TYPE_NONE; 152 return PJ_SUCCESS; 153 } 154 155 pjmedia_port_get_frame(port, frame); 156 157 return PJ_SUCCESS; 158 } 159 160 161 /* 162 * The callback called by sound recorder when it has finished capturing a 163 * frame. This version is for non-PCM data. 164 */ 165 static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 166 { 167 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 168 pjmedia_port *port; 169 170 port = snd_port->port; 171 if (port == NULL) 172 return PJ_SUCCESS; 173 174 pjmedia_port_put_frame(port, frame); 242 175 243 176 return PJ_SUCCESS; … … 251 184 pjmedia_snd_port *snd_port ) 252 185 { 186 pjmedia_aud_rec_cb snd_rec_cb; 187 pjmedia_aud_play_cb snd_play_cb; 188 pjmedia_aud_param param_copy; 253 189 pj_status_t status; 254 190 255 191 /* Check if sound has been started. */ 256 if (snd_port-> snd_stream != NULL)192 if (snd_port->aud_stream != NULL) 257 193 return PJ_SUCCESS; 258 194 259 /* Open sound stream. */ 260 if (snd_port->dir == PJMEDIA_DIR_CAPTURE) { 261 status = pjmedia_snd_open_rec( snd_port->rec_id, 262 snd_port->clock_rate, 263 snd_port->channel_count, 264 snd_port->samples_per_frame, 265 snd_port->bits_per_sample, 266 &rec_cb, 195 PJ_ASSERT_RETURN(snd_port->dir == PJMEDIA_DIR_CAPTURE || 196 snd_port->dir == PJMEDIA_DIR_PLAYBACK || 197 snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK, 198 PJ_EBUG); 199 200 /* Get device caps */ 201 if (snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) { 202 pjmedia_aud_dev_info dev_info; 203 204 status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id, 205 &dev_info); 206 if (status != PJ_SUCCESS) 207 return status; 208 209 snd_port->aud_caps = dev_info.caps; 210 } else { 211 snd_port->aud_caps = 0; 212 } 213 214 /* Process EC settings */ 215 pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy)); 216 if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) { 217 /* EC is wanted */ 218 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 219 /* Device supports EC */ 220 /* Nothing to do */ 221 } else { 222 /* Device doesn't support EC, remove EC settings from 223 * device parameters 224 */ 225 param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC | 226 PJMEDIA_AUD_DEV_CAP_EC_TAIL); 227 } 228 } 229 230 /* Use different callback if format is not PCM */ 231 if (snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) { 232 snd_rec_cb = &rec_cb; 233 snd_play_cb = &play_cb; 234 } else { 235 snd_rec_cb = &rec_cb_ext; 236 snd_play_cb = &play_cb_ext; 237 } 238 239 /* Open the device */ 240 status = pjmedia_aud_stream_create(¶m_copy, 241 snd_rec_cb, 242 snd_play_cb, 267 243 snd_port, 268 &snd_port->snd_stream); 269 270 } else if (snd_port->dir == PJMEDIA_DIR_PLAYBACK) { 271 status = pjmedia_snd_open_player( snd_port->play_id, 272 snd_port->clock_rate, 273 snd_port->channel_count, 274 snd_port->samples_per_frame, 275 snd_port->bits_per_sample, 276 &play_cb, 277 snd_port, 278 &snd_port->snd_stream); 279 280 } else if (snd_port->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) { 281 status = pjmedia_snd_open( snd_port->rec_id, 282 snd_port->play_id, 283 snd_port->clock_rate, 284 snd_port->channel_count, 285 snd_port->samples_per_frame, 286 snd_port->bits_per_sample, 287 &rec_cb, 288 &play_cb, 289 snd_port, 290 &snd_port->snd_stream); 291 } else { 292 pj_assert(!"Invalid dir"); 293 status = PJ_EBUG; 294 } 244 &snd_port->aud_stream); 295 245 296 246 if (status != PJ_SUCCESS) 297 247 return status; 298 299 300 #ifdef SIMULATE_LOST_PCT301 snd_port->options |= PJMEDIA_PLC_ENABLED;302 #endif303 304 /* If we have player components, allocate buffer to save the last305 * frame played to the speaker. The last frame is used for packet306 * lost concealment (PLC) algorithm.307 */308 if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) &&309 (snd_port->options & PJMEDIA_PLC_ENABLED))310 {311 status = pjmedia_plc_create(pool, snd_port->clock_rate,312 snd_port->samples_per_frame *313 snd_port->channel_count,314 0, &snd_port->plc);315 if (status != PJ_SUCCESS) {316 PJ_LOG(4,(THIS_FILE, "Unable to create PLC"));317 snd_port->plc = NULL;318 }319 }320 248 321 249 /* Inactivity limit before EC is suspended. */ … … 324 252 snd_port->samples_per_frame); 325 253 254 /* Create software EC if parameter specifies EC but device 255 * doesn't support EC. Only do this if the format is PCM! 256 */ 257 if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) && 258 (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 && 259 param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM) 260 { 261 if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 262 snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 263 snd_port->aud_param.ec_tail_ms = AEC_TAIL; 264 PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 265 snd_port->aud_param.ec_tail_ms)); 266 } 267 268 status = pjmedia_snd_port_set_ec(snd_port, pool, 269 snd_port->aud_param.ec_tail_ms, 0); 270 if (status != PJ_SUCCESS) { 271 pjmedia_aud_stream_destroy(snd_port->aud_stream); 272 snd_port->aud_stream = NULL; 273 return status; 274 } 275 } 276 326 277 /* Start sound stream. */ 327 status = pjmedia_ snd_stream_start(snd_port->snd_stream);278 status = pjmedia_aud_stream_start(snd_port->aud_stream); 328 279 if (status != PJ_SUCCESS) { 329 pjmedia_ snd_stream_close(snd_port->snd_stream);330 snd_port-> snd_stream = NULL;280 pjmedia_aud_stream_destroy(snd_port->aud_stream); 281 snd_port->aud_stream = NULL; 331 282 return status; 332 283 } … … 343 294 { 344 295 /* Check if we have sound stream device. */ 345 if (snd_port-> snd_stream) {346 pjmedia_ snd_stream_stop(snd_port->snd_stream);347 pjmedia_ snd_stream_close(snd_port->snd_stream);348 snd_port-> snd_stream = NULL;296 if (snd_port->aud_stream) { 297 pjmedia_aud_stream_stop(snd_port->aud_stream); 298 pjmedia_aud_stream_destroy(snd_port->aud_stream); 299 snd_port->aud_stream = NULL; 349 300 } 350 301 … … 372 323 pjmedia_snd_port **p_port) 373 324 { 374 pjmedia_snd_port *snd_port; 375 376 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 377 378 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 379 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 380 381 snd_port->rec_id = rec_id; 382 snd_port->play_id = play_id; 383 snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 384 snd_port->options = options | DEFAULT_OPTIONS; 385 snd_port->clock_rate = clock_rate; 386 snd_port->channel_count = channel_count; 387 snd_port->samples_per_frame = samples_per_frame; 388 snd_port->bits_per_sample = bits_per_sample; 389 390 #if PJMEDIA_SOUND_USE_DELAYBUF 391 do { 392 pj_status_t status; 393 unsigned ptime; 394 395 ptime = samples_per_frame * 1000 / (clock_rate * channel_count); 396 397 status = pjmedia_delay_buf_create(pool, "snd_buff", 398 clock_rate, samples_per_frame, 399 channel_count, 400 PJMEDIA_SOUND_BUFFER_COUNT * ptime, 401 0, &snd_port->delay_buf); 402 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 403 } while (0); 404 #endif 405 406 *p_port = snd_port; 407 408 409 /* Start sound device immediately. 410 * If there's no port connected, the sound callback will return 411 * empty signal. 412 */ 413 return start_sound_device( pool, snd_port ); 414 325 pjmedia_aud_param param; 326 pj_status_t status; 327 328 PJ_UNUSED_ARG(options); 329 330 status = pjmedia_aud_dev_default_param(rec_id, ¶m); 331 if (status != PJ_SUCCESS) 332 return status; 333 334 param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 335 param.rec_id = rec_id; 336 param.play_id = play_id; 337 param.clock_rate = clock_rate; 338 param.channel_count = channel_count; 339 param.samples_per_frame = samples_per_frame; 340 param.bits_per_sample = bits_per_sample; 341 342 return pjmedia_snd_port_create2(pool, ¶m, p_port); 415 343 } 416 344 … … 427 355 pjmedia_snd_port **p_port) 428 356 { 429 pjmedia_snd_port *snd_port; 430 431 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 432 433 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 434 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 435 436 snd_port->rec_id = dev_id; 437 snd_port->dir = PJMEDIA_DIR_CAPTURE; 438 snd_port->options = options | DEFAULT_OPTIONS; 439 snd_port->clock_rate = clock_rate; 440 snd_port->channel_count = channel_count; 441 snd_port->samples_per_frame = samples_per_frame; 442 snd_port->bits_per_sample = bits_per_sample; 443 444 *p_port = snd_port; 445 446 /* Start sound device immediately. 447 * If there's no port connected, the sound callback will return 448 * empty signal. 449 */ 450 return start_sound_device( pool, snd_port ); 357 pjmedia_aud_param param; 358 pj_status_t status; 359 360 PJ_UNUSED_ARG(options); 361 362 status = pjmedia_aud_dev_default_param(dev_id, ¶m); 363 if (status != PJ_SUCCESS) 364 return status; 365 366 param.dir = PJMEDIA_DIR_CAPTURE; 367 param.rec_id = dev_id; 368 param.clock_rate = clock_rate; 369 param.channel_count = channel_count; 370 param.samples_per_frame = samples_per_frame; 371 param.bits_per_sample = bits_per_sample; 372 373 return pjmedia_snd_port_create2(pool, ¶m, p_port); 451 374 } 452 375 … … 464 387 pjmedia_snd_port **p_port) 465 388 { 389 pjmedia_aud_param param; 390 pj_status_t status; 391 392 PJ_UNUSED_ARG(options); 393 394 status = pjmedia_aud_dev_default_param(dev_id, ¶m); 395 if (status != PJ_SUCCESS) 396 return status; 397 398 param.dir = PJMEDIA_DIR_PLAYBACK; 399 param.play_id = dev_id; 400 param.clock_rate = clock_rate; 401 param.channel_count = channel_count; 402 param.samples_per_frame = samples_per_frame; 403 param.bits_per_sample = bits_per_sample; 404 405 return pjmedia_snd_port_create2(pool, ¶m, p_port); 406 } 407 408 409 /* 410 * Create sound port. 411 */ 412 PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool, 413 const pjmedia_aud_param *prm, 414 pjmedia_snd_port **p_port) 415 { 466 416 pjmedia_snd_port *snd_port; 467 468 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 417 pj_status_t status; 418 419 PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL); 469 420 470 421 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 471 422 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 472 423 473 snd_port-> play_id = dev_id;474 snd_port-> dir = PJMEDIA_DIR_PLAYBACK;475 snd_port-> options = options | DEFAULT_OPTIONS;476 snd_port-> clock_rate = clock_rate;477 snd_port->c hannel_count = channel_count;478 snd_port-> samples_per_frame = samples_per_frame;479 snd_port-> bits_per_sample = bits_per_sample;480 481 *p_port = snd_port;482 424 snd_port->dir = prm->dir; 425 snd_port->rec_id = prm->rec_id; 426 snd_port->play_id = prm->play_id; 427 snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 428 snd_port->clock_rate = prm->clock_rate; 429 snd_port->channel_count = prm->channel_count; 430 snd_port->samples_per_frame = prm->samples_per_frame; 431 snd_port->bits_per_sample = prm->bits_per_sample; 432 pj_memcpy(&snd_port->aud_param, prm, sizeof(*prm)); 433 483 434 /* Start sound device immediately. 484 435 * If there's no port connected, the sound callback will return 485 436 * empty signal. 486 437 */ 487 return start_sound_device( pool, snd_port ); 438 status = start_sound_device( pool, snd_port ); 439 if (status != PJ_SUCCESS) { 440 pjmedia_snd_port_destroy(snd_port); 441 return status; 442 } 443 444 *p_port = snd_port; 445 return PJ_SUCCESS; 488 446 } 489 447 … … 503 461 * Retrieve the sound stream associated by this sound device port. 504 462 */ 505 PJ_DEF(pjmedia_ snd_stream*) pjmedia_snd_port_get_snd_stream(463 PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream( 506 464 pjmedia_snd_port *snd_port) 507 465 { 508 466 PJ_ASSERT_RETURN(snd_port, NULL); 509 return snd_port-> snd_stream;510 } 511 512 513 /* 514 * Enable AEC467 return snd_port->aud_stream; 468 } 469 470 471 /* 472 * Change EC settings. 515 473 */ 516 474 PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port, … … 519 477 unsigned options) 520 478 { 521 pjmedia_ snd_stream_info si;479 pjmedia_aud_param prm; 522 480 pj_status_t status; 523 481 … … 527 485 PJ_EINVALIDOP); 528 486 529 /* Sound port must have 16bits per sample */ 530 PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16, 531 PJ_EINVALIDOP); 532 533 /* Destroy AEC */ 534 if (snd_port->ec_state) { 535 pjmedia_echo_destroy(snd_port->ec_state); 536 snd_port->ec_state = NULL; 537 } 538 539 snd_port->aec_tail_len = tail_ms; 540 541 if (tail_ms != 0) { 542 unsigned delay_ms; 543 544 status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si); 487 /* Determine whether we use device or software EC */ 488 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 489 /* We use device EC */ 490 pj_bool_t ec_enabled; 491 492 /* Query EC status */ 493 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 494 PJMEDIA_AUD_DEV_CAP_EC, 495 &ec_enabled); 545 496 if (status != PJ_SUCCESS) 546 si.rec_latency = si.play_latency = 0; 547 548 //No need to add input latency in the latency calculation, 549 //since actual input latency should be zero. 550 //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 551 // snd_port->clock_rate; 552 delay_ms = si.play_latency * 1000 / snd_port->clock_rate; 553 status = pjmedia_echo_create2(pool, snd_port->clock_rate, 554 snd_port->channel_count, 555 snd_port->samples_per_frame, 556 tail_ms, delay_ms, 557 options, &snd_port->ec_state); 497 return status; 498 499 if (tail_ms != 0) { 500 /* Change EC setting */ 501 502 if (!ec_enabled) { 503 /* Enable EC first */ 504 pj_bool_t value = PJ_TRUE; 505 status = pjmedia_aud_stream_set_cap(snd_port->aud_stream, 506 PJMEDIA_AUD_DEV_CAP_EC, 507 &value); 508 if (status != PJ_SUCCESS) 509 return status; 510 } 511 512 if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 513 /* Device does not support setting EC tail */ 514 return PJMEDIA_EAUD_INVCAP; 515 } 516 517 return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 518 PJMEDIA_AUD_DEV_CAP_EC_TAIL, 519 &tail_ms); 520 521 } else if (ec_enabled) { 522 /* Disable EC */ 523 pj_bool_t value = PJ_FALSE; 524 return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 525 PJMEDIA_AUD_DEV_CAP_EC, 526 &value); 527 } else { 528 /* Request to disable EC but EC has been disabled */ 529 /* Do nothing */ 530 return PJ_SUCCESS; 531 } 532 533 } else { 534 /* We use software EC */ 535 536 /* Check if there is change in parameters */ 537 if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) { 538 PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no " 539 "change in settings")); 540 return PJ_SUCCESS; 541 } 542 543 status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm); 558 544 if (status != PJ_SUCCESS) 545 return status; 546 547 /* Audio stream must be in PCM format */ 548 PJ_ASSERT_RETURN(prm.ext_fmt.id == PJMEDIA_FORMAT_PCM, 549 PJ_EINVALIDOP); 550 551 /* Destroy AEC */ 552 if (snd_port->ec_state) { 553 pjmedia_echo_destroy(snd_port->ec_state); 559 554 snd_port->ec_state = NULL; 560 else 561 snd_port->ec_suspended = PJ_FALSE; 562 } else { 563 PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 564 "sound port")); 565 status = PJ_SUCCESS; 555 } 556 557 if (tail_ms != 0) { 558 unsigned delay_ms; 559 560 //No need to add input latency in the latency calculation, 561 //since actual input latency should be zero. 562 //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 563 // snd_port->clock_rate; 564 delay_ms = prm.output_latency_ms; 565 status = pjmedia_echo_create2(pool, snd_port->clock_rate, 566 snd_port->channel_count, 567 snd_port->samples_per_frame, 568 tail_ms, delay_ms, 569 options, &snd_port->ec_state); 570 if (status != PJ_SUCCESS) 571 snd_port->ec_state = NULL; 572 else 573 snd_port->ec_suspended = PJ_FALSE; 574 } else { 575 PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 576 "sound port")); 577 status = PJ_SUCCESS; 578 } 579 580 snd_port->ec_options = options; 581 snd_port->ec_tail_len = tail_ms; 566 582 } 567 583 … … 575 591 { 576 592 PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL); 577 *p_length = snd_port->ec_state ? snd_port->aec_tail_len : 0; 578 return PJ_SUCCESS; 579 } 580 593 594 /* Determine whether we use device or software EC */ 595 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 596 /* We use device EC */ 597 pj_bool_t ec_enabled; 598 pj_status_t status; 599 600 /* Query EC status */ 601 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 602 PJMEDIA_AUD_DEV_CAP_EC, 603 &ec_enabled); 604 if (status != PJ_SUCCESS) 605 return status; 606 607 if (!ec_enabled) { 608 *p_length = 0; 609 } else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) { 610 /* Get device EC tail */ 611 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 612 PJMEDIA_AUD_DEV_CAP_EC_TAIL, 613 p_length); 614 if (status != PJ_SUCCESS) 615 return status; 616 } else { 617 /* Just use default */ 618 *p_length = AEC_TAIL; 619 } 620 621 } else { 622 /* We use software EC */ 623 *p_length = snd_port->ec_state ? snd_port->ec_tail_len : 0; 624 } 625 return PJ_SUCCESS; 626 } 581 627 582 628
Note: See TracChangeset
for help on using the changeset viewer.