- Timestamp:
- Feb 21, 2009 2:21:59 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia/sound_port.c
r2460 r2468 23 23 #include <pjmedia/echo.h> 24 24 #include <pjmedia/errno.h> 25 #include <pjmedia/plc.h>26 25 #include <pj/assert.h> 27 26 #include <pj/log.h> … … 29 28 #include <pj/string.h> /* pj_memset() */ 30 29 31 //#define SIMULATE_LOST_PCT 2032 30 #define AEC_TAIL 128 /* default AEC length in ms */ 33 31 #define AEC_SUSPEND_LIMIT 5 /* seconds of no activity */ … … 41 39 int rec_id; 42 40 int play_id; 43 pjmedia_snd_stream *snd_stream; 41 pj_uint32_t aud_caps; 42 pjmedia_aud_param aud_param; 43 pjmedia_aud_stream *aud_stream; 44 44 pjmedia_dir dir; 45 45 pjmedia_port *port; 46 47 pjmedia_echo_state *ec_state;48 unsigned aec_tail_len;49 50 pj_bool_t ec_suspended;51 unsigned ec_suspend_count;52 unsigned ec_suspend_limit;53 54 pjmedia_plc *plc;55 46 56 47 unsigned clock_rate; … … 58 49 unsigned samples_per_frame; 59 50 unsigned bits_per_sample; 60 pjmedia_snd_setting setting; 61 62 #if PJMEDIA_SOUND_USE_DELAYBUF 63 pjmedia_delay_buf *delay_buf; 64 #endif 65 66 /* Encoded sound emulation */ 67 #if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || !PJMEDIA_SND_SUPPORT_OPEN2 68 unsigned frm_buf_size; 69 pj_uint8_t *put_frm_buf; 70 pj_uint8_t *get_frm_buf; 71 #endif 51 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; 72 59 }; 73 60 … … 76 63 * played. 77 64 */ 78 static pj_status_t play_cb(/* in */ void *user_data, 79 /* in */ pj_uint32_t timestamp, 80 /* out */ void *output, 81 /* out */ unsigned size) 65 static pj_status_t play_cb(void *user_data, pjmedia_frame *frame) 82 66 { 83 67 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 84 68 pjmedia_port *port; 85 pjmedia_frame frame;69 unsigned required_size = frame->size; 86 70 pj_status_t status; 87 71 … … 90 74 goto no_frame; 91 75 92 frame.buf = output; 93 frame.size = size; 94 frame.timestamp.u32.hi = 0; 95 frame.timestamp.u32.lo = timestamp; 96 97 #if PJMEDIA_SOUND_USE_DELAYBUF 98 if (snd_port->delay_buf) { 99 status = pjmedia_delay_buf_get(snd_port->delay_buf, (pj_int16_t*)output); 100 if (status != PJ_SUCCESS) 101 pj_bzero(output, size); 102 103 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 104 pjmedia_port_put_frame(port, &frame); 105 106 #ifdef TEST_OVERFLOW_UNDERFLOW 107 { 108 static int count = 1; 109 if (++count % 10 == 0) { 110 status = pjmedia_delay_buf_get(snd_port->delay_buf, 111 (pj_int16_t*)output); 112 if (status != PJ_SUCCESS) 113 pj_bzero(output, size); 114 115 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 116 pjmedia_port_put_frame(port, &frame); 117 } 118 } 119 #endif 120 121 } 122 #endif 123 124 status = pjmedia_port_get_frame(port, &frame); 76 status = pjmedia_port_get_frame(port, frame); 125 77 if (status != PJ_SUCCESS) 126 78 goto no_frame; 127 79 128 if (frame .type != PJMEDIA_FRAME_TYPE_AUDIO)80 if (frame->type != PJMEDIA_FRAME_TYPE_AUDIO) 129 81 goto no_frame; 130 82 131 83 /* Must supply the required samples */ 132 pj_assert(frame.size == size); 133 134 #ifdef SIMULATE_LOST_PCT 135 /* Simulate packet lost */ 136 if (pj_rand() % 100 < SIMULATE_LOST_PCT) { 137 PJ_LOG(4,(THIS_FILE, "Frame dropped")); 138 goto no_frame; 139 } 140 #endif 141 142 if (snd_port->plc) 143 pjmedia_plc_save(snd_port->plc, (pj_int16_t*) output); 84 PJ_UNUSED_ARG(required_size); 85 pj_assert(frame->size == required_size); 144 86 145 87 if (snd_port->ec_state) { … … 150 92 } 151 93 snd_port->ec_suspend_count = 0; 152 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*) output);94 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 153 95 } 154 96 … … 166 108 if (snd_port->ec_state) { 167 109 /* To maintain correct delay in EC */ 168 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)output); 169 } 170 } 171 172 /* Apply PLC */ 173 if (snd_port->plc) { 174 175 pjmedia_plc_generate(snd_port->plc, (pj_int16_t*) output); 176 #ifdef SIMULATE_LOST_PCT 177 PJ_LOG(4,(THIS_FILE, "Lost frame generated")); 178 #endif 179 } else { 180 pj_bzero(output, size); 181 } 182 110 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf); 111 } 112 } 183 113 184 114 return PJ_SUCCESS; … … 190 120 * frame. 191 121 */ 192 static pj_status_t rec_cb(/* in */ void *user_data, 193 /* in */ pj_uint32_t timestamp, 194 /* in */ void *input, 195 /* in*/ unsigned size) 122 static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame) 196 123 { 197 124 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 198 125 pjmedia_port *port; 199 pjmedia_frame frame;200 126 201 127 port = snd_port->port; … … 205 131 /* Cancel echo */ 206 132 if (snd_port->ec_state && !snd_port->ec_suspended) { 207 pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) input, 0); 208 } 209 210 #if PJMEDIA_SOUND_USE_DELAYBUF 211 if (snd_port->delay_buf) { 212 pjmedia_delay_buf_put(snd_port->delay_buf, (pj_int16_t*)input); 213 } else { 214 frame.buf = (void*)input; 215 frame.size = size; 216 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 217 frame.timestamp.u32.lo = timestamp; 218 219 pjmedia_port_put_frame(port, &frame); 220 } 221 #else 222 frame.buf = (void*)input; 223 frame.size = size; 224 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 225 frame.timestamp.u32.lo = timestamp; 226 227 pjmedia_port_put_frame(port, &frame); 228 #endif 133 pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0); 134 } 135 136 pjmedia_port_put_frame(port, frame); 229 137 230 138 return PJ_SUCCESS; … … 235 143 * played. This version is for non-PCM data. 236 144 */ 237 static pj_status_t play_cb_ext(/* in */ void *user_data, 238 /* in */ pj_uint32_t timestamp, 239 /* out */ void *output, 240 /* out */ unsigned size) 241 { 242 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 243 /* This is the version to use when the sound device supports 244 * open2(). 245 */ 145 static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 146 { 246 147 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 247 pjmedia_port *port; 248 pjmedia_frame *frame = (pjmedia_frame*) output; 249 pj_status_t status; 250 251 PJ_UNUSED_ARG(size); 252 PJ_UNUSED_ARG(timestamp); 253 254 port = snd_port->port; 148 pjmedia_port *port = snd_port->port; 149 255 150 if (port == NULL) { 256 151 frame->type = PJMEDIA_FRAME_TYPE_NONE; … … 258 153 } 259 154 260 status = pjmedia_port_get_frame(port, frame); 261 262 return status; 263 #else 264 /* This is the emulation version */ 265 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 266 pjmedia_port *port = snd_port->port; 267 pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->get_frm_buf; 268 pj_status_t status; 269 270 if (port==NULL) { 271 goto no_frame; 272 } 273 274 pj_bzero(fx, sizeof(*fx)); 275 fx->base.type = PJMEDIA_FRAME_TYPE_NONE; 276 fx->base.buf = ((pj_uint8_t*)fx) + sizeof(*fx); 277 fx->base.size = snd_port->frm_buf_size - sizeof(*fx); 278 fx->base.timestamp.u32.hi = 0; 279 fx->base.timestamp.u32.lo = timestamp; 280 281 status = pjmedia_port_get_frame(port, &fx->base); 282 if (status != PJ_SUCCESS) 283 goto no_frame; 284 285 if (fx->base.type == PJMEDIA_FRAME_TYPE_AUDIO) { 286 pj_assert(fx->base.size == size); 287 pj_memcpy(output, fx->base.buf, size); 288 } else if (fx->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) { 289 void (*decoder)(pj_int16_t*, const pj_uint8_t*, pj_size_t) = NULL; 290 unsigned i, size_decoded; 291 292 switch (snd_port->setting.format.id) { 293 case PJMEDIA_FORMAT_PCMA: 294 decoder = &pjmedia_alaw_decode; 295 break; 296 case PJMEDIA_FORMAT_PCMU: 297 decoder = &pjmedia_ulaw_decode; 298 break; 299 default: 300 PJ_LOG(1,(THIS_FILE, "Unsupported format %d", 301 snd_port->setting.format.id)); 302 goto no_frame; 303 } 304 305 if (fx->samples_cnt > size>>1) { 306 PJ_LOG(4,(THIS_FILE, "Frame too large by %d samples", 307 fx->samples_cnt - (size>>1))); 308 } else if (fx->samples_cnt < size>>1) { 309 PJ_LOG(4,(THIS_FILE, "Not enough frame by %d samples", 310 (size>>1) - fx->samples_cnt)); 311 } 312 313 for (i=0, size_decoded=0; 314 i<fx->subframe_cnt && size_decoded<size; 315 ++i) 316 { 317 pjmedia_frame_ext_subframe *subfrm; 318 319 subfrm = pjmedia_frame_ext_get_subframe(fx, i); 320 321 if (!subfrm || subfrm->bitlen==0) 322 continue; 323 324 if ((subfrm->bitlen>>3) > (int)(size-size_decoded)) { 325 subfrm->bitlen = (pj_uint16_t)((size-size_decoded) << 3); 326 } 327 328 (*decoder)((short*)((pj_uint8_t*)output + size_decoded), 329 subfrm->data, subfrm->bitlen>>3); 330 331 size_decoded += (subfrm->bitlen>>3) << 1; 332 } 333 334 if (size_decoded < size) { 335 pj_bzero((pj_uint8_t*)output + size_decoded, size-size_decoded); 336 } 337 338 } else { 339 goto no_frame; 340 } 341 342 return PJ_SUCCESS; 343 344 no_frame: 345 pj_bzero(output, size); 346 return PJ_SUCCESS; 347 348 #endif /* PJMEDIA_SND_SUPPORT_OPEN2 */ 155 pjmedia_port_get_frame(port, frame); 156 157 return PJ_SUCCESS; 349 158 } 350 159 … … 354 163 * frame. This version is for non-PCM data. 355 164 */ 356 static pj_status_t rec_cb_ext(/* in */ void *user_data, 357 /* in */ pj_uint32_t timestamp, 358 /* in */ void *input, 359 /* in*/ unsigned size) 360 { 361 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 362 /* This is the version to use when the sound device supports 363 * open2(). 364 */ 165 static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 166 { 365 167 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 366 168 pjmedia_port *port; 367 pjmedia_frame *frame = (pjmedia_frame*)input;368 369 PJ_UNUSED_ARG(size);370 PJ_UNUSED_ARG(timestamp);371 169 372 170 port = snd_port->port; … … 377 175 378 176 return PJ_SUCCESS; 379 #else380 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;381 pjmedia_port *port = snd_port->port;382 pjmedia_frame_ext *fx = (pjmedia_frame_ext*) snd_port->put_frm_buf;383 void (*encoder)(pj_uint8_t*, const pj_int16_t*, pj_size_t) = NULL;384 385 if (port==NULL)386 return PJ_SUCCESS;387 388 pj_bzero(fx, sizeof(*fx));389 fx->base.buf = NULL;390 fx->base.size = snd_port->frm_buf_size - sizeof(*fx);391 fx->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;392 fx->base.timestamp.u32.lo = timestamp;393 394 switch (snd_port->setting.format.id) {395 case PJMEDIA_FORMAT_PCMA:396 encoder = &pjmedia_alaw_encode;397 break;398 case PJMEDIA_FORMAT_PCMU:399 encoder = &pjmedia_ulaw_encode;400 break;401 default:402 PJ_LOG(1,(THIS_FILE, "Unsupported format %d",403 snd_port->setting.format.id));404 return PJ_SUCCESS;405 }406 407 (*encoder)((pj_uint8_t*)input, (pj_int16_t*)input, size >> 1);408 409 pjmedia_frame_ext_append_subframe(fx, input, (size >> 1) << 3,410 size >> 1);411 pjmedia_port_put_frame(port, &fx->base);412 413 return PJ_SUCCESS;414 #endif415 177 } 416 178 … … 422 184 pjmedia_snd_port *snd_port ) 423 185 { 424 pjmedia_snd_rec_cb snd_rec_cb; 425 pjmedia_snd_play_cb snd_play_cb; 186 pjmedia_aud_rec_cb snd_rec_cb; 187 pjmedia_aud_play_cb snd_play_cb; 188 pjmedia_aud_param param_copy; 426 189 pj_status_t status; 427 190 428 191 /* Check if sound has been started. */ 429 if (snd_port-> snd_stream != NULL)192 if (snd_port->aud_stream != NULL) 430 193 return PJ_SUCCESS; 431 194 … … 435 198 PJ_EBUG); 436 199 437 if (snd_port->setting.format.id == PJMEDIA_FORMAT_L16) { 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) { 438 232 snd_rec_cb = &rec_cb; 439 233 snd_play_cb = &play_cb; … … 443 237 } 444 238 445 #if defined(PJMEDIA_SND_SUPPORT_OPEN2) && PJMEDIA_SND_SUPPORT_OPEN2!=0 446 status = pjmedia_snd_open2( snd_port->dir, 447 snd_port->rec_id, 448 snd_port->play_id, 449 snd_port->clock_rate, 450 snd_port->channel_count, 451 snd_port->samples_per_frame, 452 snd_port->bits_per_sample, 453 snd_rec_cb, 454 snd_play_cb, 455 snd_port, 456 &snd_port->setting, 457 &snd_port->snd_stream); 458 #else 459 status = pjmedia_snd_open( snd_port->rec_id, 460 snd_port->play_id, 461 snd_port->clock_rate, 462 snd_port->channel_count, 463 snd_port->samples_per_frame, 464 snd_port->bits_per_sample, 465 snd_rec_cb, 466 snd_play_cb, 467 snd_port, 468 &snd_port->snd_stream); 469 #endif 239 /* Open the device */ 240 status = pjmedia_aud_stream_create(¶m_copy, 241 snd_rec_cb, 242 snd_play_cb, 243 snd_port, 244 &snd_port->aud_stream); 470 245 471 246 if (status != PJ_SUCCESS) 472 247 return status; 473 474 475 #ifdef SIMULATE_LOST_PCT476 snd_port->setting.plc = PJ_TRUE;477 #endif478 479 /* If we have player components, allocate buffer to save the last480 * frame played to the speaker. The last frame is used for packet481 * lost concealment (PLC) algorithm.482 */483 if ((snd_port->dir & PJMEDIA_DIR_PLAYBACK) &&484 (snd_port->setting.plc))485 {486 status = pjmedia_plc_create(pool, snd_port->clock_rate,487 snd_port->samples_per_frame *488 snd_port->channel_count,489 0, &snd_port->plc);490 if (status != PJ_SUCCESS) {491 PJ_LOG(4,(THIS_FILE, "Unable to create PLC"));492 snd_port->plc = NULL;493 }494 }495 248 496 249 /* Inactivity limit before EC is suspended. */ … … 499 252 snd_port->samples_per_frame); 500 253 254 /* Create software EC if parameter specifies EC but device 255 * doesn't support EC 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 { 260 if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 261 snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 262 snd_port->aud_param.ec_tail_ms = AEC_TAIL; 263 PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 264 snd_port->aud_param.ec_tail_ms)); 265 } 266 267 status = pjmedia_snd_port_set_ec(snd_port, pool, 268 snd_port->aud_param.ec_tail_ms, 0); 269 if (status != PJ_SUCCESS) { 270 pjmedia_aud_stream_destroy(snd_port->aud_stream); 271 snd_port->aud_stream = NULL; 272 return status; 273 } 274 } 275 501 276 /* Start sound stream. */ 502 status = pjmedia_ snd_stream_start(snd_port->snd_stream);277 status = pjmedia_aud_stream_start(snd_port->aud_stream); 503 278 if (status != PJ_SUCCESS) { 504 pjmedia_ snd_stream_close(snd_port->snd_stream);505 snd_port-> snd_stream = NULL;279 pjmedia_aud_stream_destroy(snd_port->aud_stream); 280 snd_port->aud_stream = NULL; 506 281 return status; 507 282 } … … 518 293 { 519 294 /* Check if we have sound stream device. */ 520 if (snd_port-> snd_stream) {521 pjmedia_ snd_stream_stop(snd_port->snd_stream);522 pjmedia_ snd_stream_close(snd_port->snd_stream);523 snd_port-> snd_stream = NULL;295 if (snd_port->aud_stream) { 296 pjmedia_aud_stream_stop(snd_port->aud_stream); 297 pjmedia_aud_stream_destroy(snd_port->aud_stream); 298 snd_port->aud_stream = NULL; 524 299 } 525 300 … … 547 322 pjmedia_snd_port **p_port) 548 323 { 549 pjmedia_snd_port *snd_port; 324 pjmedia_aud_param param; 325 pj_status_t status; 550 326 551 327 PJ_UNUSED_ARG(options); 552 328 553 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 554 555 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 556 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 557 558 snd_port->rec_id = rec_id; 559 snd_port->play_id = play_id; 560 snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 561 snd_port->clock_rate = clock_rate; 562 snd_port->channel_count = channel_count; 563 snd_port->samples_per_frame = samples_per_frame; 564 snd_port->bits_per_sample = bits_per_sample; 565 566 #if PJMEDIA_SOUND_USE_DELAYBUF 567 do { 568 pj_status_t status; 569 unsigned ptime; 570 571 ptime = samples_per_frame * 1000 / (clock_rate * channel_count); 572 573 status = pjmedia_delay_buf_create(pool, "snd_buff", 574 clock_rate, samples_per_frame, 575 channel_count, 576 PJMEDIA_SOUND_BUFFER_COUNT * ptime, 577 0, &snd_port->delay_buf); 578 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 579 } while (0); 580 #endif 581 582 *p_port = snd_port; 583 584 585 /* Start sound device immediately. 586 * If there's no port connected, the sound callback will return 587 * empty signal. 588 */ 589 return start_sound_device( pool, snd_port ); 590 329 status = pjmedia_aud_dev_default_param(rec_id, ¶m); 330 if (status != PJ_SUCCESS) 331 return status; 332 333 param.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 334 param.rec_id = rec_id; 335 param.play_id = play_id; 336 param.clock_rate = clock_rate; 337 param.channel_count = channel_count; 338 param.samples_per_frame = samples_per_frame; 339 param.bits_per_sample = bits_per_sample; 340 341 return pjmedia_snd_port_create2(pool, ¶m, p_port); 591 342 } 592 343 … … 603 354 pjmedia_snd_port **p_port) 604 355 { 605 pjmedia_snd_port *snd_port; 356 pjmedia_aud_param param; 357 pj_status_t status; 606 358 607 359 PJ_UNUSED_ARG(options); 608 360 609 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 610 611 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 612 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 613 614 snd_port->rec_id = dev_id; 615 snd_port->dir = PJMEDIA_DIR_CAPTURE; 616 snd_port->clock_rate = clock_rate; 617 snd_port->channel_count = channel_count; 618 snd_port->samples_per_frame = samples_per_frame; 619 snd_port->bits_per_sample = bits_per_sample; 620 621 *p_port = snd_port; 622 623 /* Start sound device immediately. 624 * If there's no port connected, the sound callback will return 625 * empty signal. 626 */ 627 return start_sound_device( pool, snd_port ); 361 status = pjmedia_aud_dev_default_param(dev_id, ¶m); 362 if (status != PJ_SUCCESS) 363 return status; 364 365 param.dir = PJMEDIA_DIR_CAPTURE; 366 param.rec_id = dev_id; 367 param.clock_rate = clock_rate; 368 param.channel_count = channel_count; 369 param.samples_per_frame = samples_per_frame; 370 param.bits_per_sample = bits_per_sample; 371 372 return pjmedia_snd_port_create2(pool, ¶m, p_port); 628 373 } 629 374 … … 641 386 pjmedia_snd_port **p_port) 642 387 { 388 pjmedia_aud_param param; 389 pj_status_t status; 390 391 PJ_UNUSED_ARG(options); 392 393 status = pjmedia_aud_dev_default_param(dev_id, ¶m); 394 if (status != PJ_SUCCESS) 395 return status; 396 397 param.dir = PJMEDIA_DIR_PLAYBACK; 398 param.play_id = dev_id; 399 param.clock_rate = clock_rate; 400 param.channel_count = channel_count; 401 param.samples_per_frame = samples_per_frame; 402 param.bits_per_sample = bits_per_sample; 403 404 return pjmedia_snd_port_create2(pool, ¶m, p_port); 405 } 406 407 408 /* 409 * Create sound port. 410 */ 411 PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool, 412 const pjmedia_aud_param *prm, 413 pjmedia_snd_port **p_port) 414 { 643 415 pjmedia_snd_port *snd_port; 644 416 645 PJ_UNUSED_ARG(options); 646 647 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL); 417 PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL); 648 418 649 419 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 650 420 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 651 421 652 snd_port->play_id = dev_id; 653 snd_port->dir = PJMEDIA_DIR_PLAYBACK; 654 snd_port->clock_rate = clock_rate; 655 snd_port->channel_count = channel_count; 656 snd_port->samples_per_frame = samples_per_frame; 657 snd_port->bits_per_sample = bits_per_sample; 658 422 snd_port->dir = prm->dir; 423 snd_port->rec_id = prm->rec_id; 424 snd_port->play_id = prm->play_id; 425 snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; 426 snd_port->clock_rate = prm->clock_rate; 427 snd_port->channel_count = prm->channel_count; 428 snd_port->samples_per_frame = prm->samples_per_frame; 429 snd_port->bits_per_sample = prm->bits_per_sample; 430 pj_memcpy(&snd_port->aud_param, prm, sizeof(*prm)); 431 659 432 *p_port = snd_port; 433 660 434 661 435 /* Start sound device immediately. … … 664 438 */ 665 439 return start_sound_device( pool, snd_port ); 666 }667 668 669 /*670 * Create bidirectional port.671 */672 PJ_DEF(pj_status_t) pjmedia_snd_port_create2(pj_pool_t *pool,673 pjmedia_dir dir,674 int rec_id,675 int play_id,676 unsigned clock_rate,677 unsigned channel_count,678 unsigned samples_per_frame,679 unsigned bits_per_sample,680 const pjmedia_snd_setting *setting,681 pjmedia_snd_port **p_port)682 {683 pjmedia_snd_port *snd_port;684 685 PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);686 687 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port);688 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM);689 690 snd_port->dir = dir;691 snd_port->rec_id = rec_id;692 snd_port->play_id = play_id;693 snd_port->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;694 snd_port->clock_rate = clock_rate;695 snd_port->channel_count = channel_count;696 snd_port->samples_per_frame = samples_per_frame;697 snd_port->bits_per_sample = bits_per_sample;698 pj_memcpy(&snd_port->setting, setting, sizeof(*setting));699 700 #if PJMEDIA_SOUND_USE_DELAYBUF701 if (snd_port->setting.format.u32 == PJMEDIA_FORMAT_L16) {702 pj_status_t status;703 unsigned ptime;704 705 ptime = samples_per_frame * 1000 / (clock_rate * channel_count);706 707 status = pjmedia_delay_buf_create(pool, "snd_buff",708 clock_rate, samples_per_frame,709 channel_count,710 PJMEDIA_SOUND_BUFFER_COUNT * ptime,711 0, &snd_port->delay_buf);712 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);713 }714 #endif715 716 #if !defined(PJMEDIA_SND_SUPPORT_OPEN2) || PJMEDIA_SND_SUPPORT_OPEN2==0717 /* For devices that doesn't support open2(), enable simulation */718 if (snd_port->setting.format.id != PJMEDIA_FORMAT_L16) {719 snd_port->frm_buf_size = sizeof(pjmedia_frame_ext) +720 (samples_per_frame << 1) +721 16 * sizeof(pjmedia_frame_ext_subframe);722 snd_port->put_frm_buf = (pj_uint8_t*)723 pj_pool_alloc(pool, snd_port->frm_buf_size);724 snd_port->get_frm_buf = (pj_uint8_t*)725 pj_pool_alloc(pool, snd_port->frm_buf_size);726 }727 #endif728 729 *p_port = snd_port;730 731 732 /* Start sound device immediately.733 * If there's no port connected, the sound callback will return734 * empty signal.735 */736 return start_sound_device( pool, snd_port );737 440 738 441 } … … 753 456 * Retrieve the sound stream associated by this sound device port. 754 457 */ 755 PJ_DEF(pjmedia_ snd_stream*) pjmedia_snd_port_get_snd_stream(458 PJ_DEF(pjmedia_aud_stream*) pjmedia_snd_port_get_snd_stream( 756 459 pjmedia_snd_port *snd_port) 757 460 { 758 461 PJ_ASSERT_RETURN(snd_port, NULL); 759 return snd_port-> snd_stream;760 } 761 762 763 /* 764 * Enable AEC462 return snd_port->aud_stream; 463 } 464 465 466 /* 467 * Change EC settings. 765 468 */ 766 469 PJ_DEF(pj_status_t) pjmedia_snd_port_set_ec( pjmedia_snd_port *snd_port, … … 769 472 unsigned options) 770 473 { 771 pjmedia_ snd_stream_info si;474 pjmedia_aud_param prm; 772 475 pj_status_t status; 773 476 … … 777 480 PJ_EINVALIDOP); 778 481 779 /* Sound port must have 16bits per sample */ 780 PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16, 781 PJ_EINVALIDOP); 782 783 /* Destroy AEC */ 784 if (snd_port->ec_state) { 785 pjmedia_echo_destroy(snd_port->ec_state); 786 snd_port->ec_state = NULL; 787 } 788 789 snd_port->aec_tail_len = tail_ms; 790 791 if (tail_ms != 0) { 792 unsigned delay_ms; 793 794 status = pjmedia_snd_stream_get_info(snd_port->snd_stream, &si); 482 /* Determine whether we use device or software EC */ 483 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 484 /* We use device EC */ 485 pj_bool_t ec_enabled; 486 487 /* Query EC status */ 488 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 489 PJMEDIA_AUD_DEV_CAP_EC, 490 &ec_enabled); 795 491 if (status != PJ_SUCCESS) 796 si.rec_latency = si.play_latency = 0; 797 798 //No need to add input latency in the latency calculation, 799 //since actual input latency should be zero. 800 //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 801 // snd_port->clock_rate; 802 delay_ms = si.play_latency * 1000 / snd_port->clock_rate; 803 status = pjmedia_echo_create2(pool, snd_port->clock_rate, 804 snd_port->channel_count, 805 snd_port->samples_per_frame, 806 tail_ms, delay_ms, 807 options, &snd_port->ec_state); 808 if (status != PJ_SUCCESS) 492 return status; 493 494 if (tail_ms != 0) { 495 /* Change EC setting */ 496 497 if (!ec_enabled) { 498 /* Enable EC first */ 499 pj_bool_t value = PJ_TRUE; 500 status = pjmedia_aud_stream_set_cap(snd_port->aud_stream, 501 PJMEDIA_AUD_DEV_CAP_EC, 502 &value); 503 if (status != PJ_SUCCESS) 504 return status; 505 } 506 507 if ((snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 508 /* Device does not support setting EC tail */ 509 return PJMEDIA_EAUD_INVCAP; 510 } 511 512 return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 513 PJMEDIA_AUD_DEV_CAP_EC_TAIL, 514 &tail_ms); 515 516 } else if (ec_enabled) { 517 /* Disable EC */ 518 pj_bool_t value = PJ_FALSE; 519 return pjmedia_aud_stream_set_cap(snd_port->aud_stream, 520 PJMEDIA_AUD_DEV_CAP_EC, 521 &value); 522 } else { 523 /* Request to disable EC but EC has been disabled */ 524 /* Do nothing */ 525 return PJ_SUCCESS; 526 } 527 528 } else { 529 /* We use software EC */ 530 /* Sound port must have 16bits per sample */ 531 PJ_ASSERT_RETURN(snd_port->bits_per_sample == 16, 532 PJ_EINVALIDOP); 533 534 /* Check if there is change in parameters */ 535 if (tail_ms==snd_port->ec_tail_len && options==snd_port->ec_options) { 536 PJ_LOG(5,(THIS_FILE, "pjmedia_snd_port_set_ec() ignored, no " 537 "change in settings")); 538 return PJ_SUCCESS; 539 } 540 541 /* Destroy AEC */ 542 if (snd_port->ec_state) { 543 pjmedia_echo_destroy(snd_port->ec_state); 809 544 snd_port->ec_state = NULL; 810 else 811 snd_port->ec_suspended = PJ_FALSE; 812 } else { 813 PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 814 "sound port")); 815 status = PJ_SUCCESS; 545 } 546 547 snd_port->ec_options = options; 548 snd_port->ec_tail_len = tail_ms; 549 550 if (tail_ms != 0) { 551 unsigned delay_ms; 552 553 status = pjmedia_aud_stream_get_param(snd_port->aud_stream, &prm); 554 if (status != PJ_SUCCESS) 555 prm.input_latency_ms = prm.output_latency_ms = 0; 556 557 //No need to add input latency in the latency calculation, 558 //since actual input latency should be zero. 559 //delay_ms = (si.rec_latency + si.play_latency) * 1000 / 560 // snd_port->clock_rate; 561 delay_ms = prm.output_latency_ms; 562 status = pjmedia_echo_create2(pool, snd_port->clock_rate, 563 snd_port->channel_count, 564 snd_port->samples_per_frame, 565 tail_ms, delay_ms, 566 options, &snd_port->ec_state); 567 if (status != PJ_SUCCESS) 568 snd_port->ec_state = NULL; 569 else 570 snd_port->ec_suspended = PJ_FALSE; 571 } else { 572 PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " 573 "sound port")); 574 status = PJ_SUCCESS; 575 } 816 576 } 817 577 … … 825 585 { 826 586 PJ_ASSERT_RETURN(snd_port && p_length, PJ_EINVAL); 827 *p_length = snd_port->ec_state ? snd_port->aec_tail_len : 0; 828 return PJ_SUCCESS; 829 } 830 587 588 /* Determine whether we use device or software EC */ 589 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) { 590 /* We use device EC */ 591 pj_bool_t ec_enabled; 592 pj_status_t status; 593 594 /* Query EC status */ 595 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 596 PJMEDIA_AUD_DEV_CAP_EC, 597 &ec_enabled); 598 if (status != PJ_SUCCESS) 599 return status; 600 601 if (!ec_enabled) { 602 *p_length = 0; 603 } else if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC_TAIL) { 604 /* Get device EC tail */ 605 status = pjmedia_aud_stream_get_cap(snd_port->aud_stream, 606 PJMEDIA_AUD_DEV_CAP_EC_TAIL, 607 p_length); 608 if (status != PJ_SUCCESS) 609 return status; 610 } else { 611 /* Just use default */ 612 *p_length = AEC_TAIL; 613 } 614 615 } else { 616 /* We use software EC */ 617 *p_length = snd_port->ec_state ? snd_port->ec_tail_len : 0; 618 } 619 return PJ_SUCCESS; 620 } 831 621 832 622
Note: See TracChangeset
for help on using the changeset viewer.