Changeset 2747 for pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
- Timestamp:
- Jun 4, 2009 6:48:49 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/sound_port.c
r2685 r2747 20 20 #include <pjmedia/sound_port.h> 21 21 #include <pjmedia/alaw_ulaw.h> 22 #include <pjmedia/delaybuf.h> 23 #include <pjmedia/echo.h> 22 #include <pjmedia/echo_port.h> 24 23 #include <pjmedia/errno.h> 24 #include <pjmedia/sync_port.h> 25 25 #include <pj/assert.h> 26 26 #include <pj/log.h> … … 29 29 30 30 #define AEC_TAIL 128 /* default AEC length in ms */ 31 #define AEC_SUSPEND_LIMIT 5 /* seconds of no activity */32 31 33 32 #define THIS_FILE "sound_port.c" 34 33 35 //#define TEST_OVERFLOW_UNDERFLOW36 37 34 struct pjmedia_snd_port 38 35 { 36 pj_pool_t *pool; 39 37 int rec_id; 40 38 int play_id; … … 44 42 pjmedia_dir dir; 45 43 pjmedia_port *port; 44 pjmedia_port *dn_port; 45 pjmedia_port *sync_port; 46 46 47 47 unsigned clock_rate; … … 51 51 52 52 /* software ec */ 53 pjmedia_ echo_state *ec_state;53 pjmedia_port *echo_port; 54 54 unsigned ec_options; 55 55 unsigned ec_tail_len; 56 pj_bool_t ec_suspended;57 unsigned ec_suspend_count;58 unsigned ec_suspend_limit;59 56 }; 60 57 … … 70 67 pj_status_t status; 71 68 72 port = snd_port-> port;69 port = snd_port->dn_port; 73 70 if (port == NULL) 74 71 goto no_frame; … … 83 80 /* Must supply the required samples */ 84 81 pj_assert(frame->size == required_size); 85 86 if (snd_port->ec_state) {87 if (snd_port->ec_suspended) {88 snd_port->ec_suspended = PJ_FALSE;89 //pjmedia_echo_state_reset(snd_port->ec_state);90 PJ_LOG(4,(THIS_FILE, "EC activated"));91 }92 snd_port->ec_suspend_count = 0;93 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);94 }95 82 96 83 … … 102 89 pj_bzero(frame->buf, frame->size); 103 90 104 if (snd_port->ec_state && !snd_port->ec_suspended) {105 ++snd_port->ec_suspend_count;106 if (snd_port->ec_suspend_count > snd_port->ec_suspend_limit) {107 snd_port->ec_suspended = PJ_TRUE;108 PJ_LOG(4,(THIS_FILE, "EC suspended because of inactivity"));109 }110 if (snd_port->ec_state) {111 /* To maintain correct delay in EC */112 pjmedia_echo_playback(snd_port->ec_state, (pj_int16_t*)frame->buf);113 }114 }115 116 91 return PJ_SUCCESS; 117 92 } … … 123 98 */ 124 99 static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame) 100 { 101 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 102 pjmedia_port *port; 103 104 port = snd_port->dn_port; 105 if (port == NULL) 106 return PJ_SUCCESS; 107 108 pjmedia_port_put_frame(port, frame); 109 110 return PJ_SUCCESS; 111 } 112 113 /* 114 * The callback called by sound player when it needs more samples to be 115 * played. This version is for non-PCM data. 116 */ 117 static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame) 118 { 119 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; 120 pjmedia_port *port = snd_port->port; 121 122 if (port == NULL) { 123 frame->type = PJMEDIA_FRAME_TYPE_NONE; 124 return PJ_SUCCESS; 125 } 126 127 pjmedia_port_get_frame(port, frame); 128 129 return PJ_SUCCESS; 130 } 131 132 133 /* 134 * The callback called by sound recorder when it has finished capturing a 135 * frame. This version is for non-PCM data. 136 */ 137 static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame) 125 138 { 126 139 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data; … … 131 144 return PJ_SUCCESS; 132 145 133 /* Cancel echo */134 if (snd_port->ec_state && !snd_port->ec_suspended) {135 pjmedia_echo_capture(snd_port->ec_state, (pj_int16_t*) frame->buf, 0);136 }137 138 pjmedia_port_put_frame(port, frame);139 140 return PJ_SUCCESS;141 }142 143 /*144 * The callback called by sound player when it needs more samples to be145 * played. This version is for non-PCM data.146 */147 static pj_status_t play_cb_ext(void *user_data, pjmedia_frame *frame)148 {149 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;150 pjmedia_port *port = snd_port->port;151 152 if (port == NULL) {153 frame->type = PJMEDIA_FRAME_TYPE_NONE;154 return PJ_SUCCESS;155 }156 157 pjmedia_port_get_frame(port, frame);158 159 return PJ_SUCCESS;160 }161 162 163 /*164 * The callback called by sound recorder when it has finished capturing a165 * frame. This version is for non-PCM data.166 */167 static pj_status_t rec_cb_ext(void *user_data, pjmedia_frame *frame)168 {169 pjmedia_snd_port *snd_port = (pjmedia_snd_port*) user_data;170 pjmedia_port *port;171 172 port = snd_port->port;173 if (port == NULL)174 return PJ_SUCCESS;175 176 146 pjmedia_port_put_frame(port, frame); 177 147 … … 183 153 * This may be called even when the sound stream has already been started. 184 154 */ 185 static pj_status_t start_sound_device( pj_pool_t *pool, 186 pjmedia_snd_port *snd_port ) 155 static pj_status_t start_sound_device( pjmedia_snd_port *snd_port ) 187 156 { 188 157 pjmedia_aud_rec_cb snd_rec_cb; 189 158 pjmedia_aud_play_cb snd_play_cb; 190 pjmedia_aud_param param_copy;159 pjmedia_aud_param *param; 191 160 pj_status_t status; 192 161 … … 200 169 PJ_EBUG); 201 170 171 param = &snd_port->aud_param; 172 202 173 /* Get device caps */ 203 if ( snd_port->aud_param.dir & PJMEDIA_DIR_CAPTURE) {174 if (param->dir & PJMEDIA_DIR_CAPTURE) { 204 175 pjmedia_aud_dev_info dev_info; 205 176 206 status = pjmedia_aud_dev_get_info(snd_port->aud_param.rec_id, 207 &dev_info); 177 status = pjmedia_aud_dev_get_info(param->rec_id, &dev_info); 208 178 if (status != PJ_SUCCESS) 209 179 return status; … … 214 184 } 215 185 216 /* Process EC settings */217 pj_memcpy(¶m_copy, &snd_port->aud_param, sizeof(param_copy));218 if (param_copy.flags & PJMEDIA_AUD_DEV_CAP_EC) {219 /* EC is wanted */220 if (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC) {221 /* Device supports EC */222 /* Nothing to do */223 } else {224 /* Device doesn't support EC, remove EC settings from225 * device parameters226 */227 param_copy.flags &= ~(PJMEDIA_AUD_DEV_CAP_EC |228 PJMEDIA_AUD_DEV_CAP_EC_TAIL);229 }230 }231 232 186 /* Use different callback if format is not PCM */ 233 if ( snd_port->aud_param.ext_fmt.id == PJMEDIA_FORMAT_L16) {187 if (param->ext_fmt.id == PJMEDIA_FORMAT_L16) { 234 188 snd_rec_cb = &rec_cb; 235 189 snd_play_cb = &play_cb; … … 240 194 241 195 /* Open the device */ 242 status = pjmedia_aud_stream_create( ¶m_copy,196 status = pjmedia_aud_stream_create(param, 243 197 snd_rec_cb, 244 198 snd_play_cb, … … 248 202 if (status != PJ_SUCCESS) 249 203 return status; 250 251 /* Inactivity limit before EC is suspended. */252 snd_port->ec_suspend_limit = AEC_SUSPEND_LIMIT *253 (snd_port->clock_rate /254 snd_port->samples_per_frame);255 256 /* Create software EC if parameter specifies EC but device257 * doesn't support EC. Only do this if the format is PCM!258 */259 if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC) &&260 (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 &&261 param_copy.ext_fmt.id == PJMEDIA_FORMAT_PCM)262 {263 if ((snd_port->aud_param.flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) {264 snd_port->aud_param.flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL;265 snd_port->aud_param.ec_tail_ms = AEC_TAIL;266 PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms",267 snd_port->aud_param.ec_tail_ms));268 }269 270 status = pjmedia_snd_port_set_ec(snd_port, pool,271 snd_port->aud_param.ec_tail_ms, 0);272 if (status != PJ_SUCCESS) {273 pjmedia_aud_stream_destroy(snd_port->aud_stream);274 snd_port->aud_stream = NULL;275 return status;276 }277 }278 204 279 205 /* Start sound stream. */ … … 300 226 pjmedia_aud_stream_destroy(snd_port->aud_stream); 301 227 snd_port->aud_stream = NULL; 302 }303 304 /* Destroy AEC */305 if (snd_port->ec_state) {306 pjmedia_echo_destroy(snd_port->ec_state);307 snd_port->ec_state = NULL;308 228 } 309 229 … … 421 341 PJ_ASSERT_RETURN(pool && prm && p_port, PJ_EINVAL); 422 342 343 pool = pj_pool_create(pool->factory, pool->obj_name, 256, 256, NULL); 423 344 snd_port = PJ_POOL_ZALLOC_T(pool, pjmedia_snd_port); 424 345 PJ_ASSERT_RETURN(snd_port, PJ_ENOMEM); 425 346 347 snd_port->pool = pool; 426 348 snd_port->dir = prm->dir; 427 349 snd_port->rec_id = prm->rec_id; … … 438 360 * empty signal. 439 361 */ 440 status = start_sound_device( pool,snd_port );362 status = start_sound_device( snd_port ); 441 363 if (status != PJ_SUCCESS) { 442 364 pjmedia_snd_port_destroy(snd_port); … … 454 376 PJ_DEF(pj_status_t) pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port) 455 377 { 378 pj_status_t status; 379 456 380 PJ_ASSERT_RETURN(snd_port, PJ_EINVAL); 457 381 458 return stop_sound_device(snd_port); 382 /* Stop sound port */ 383 status = stop_sound_device(snd_port); 384 385 /* Disconnect sound port */ 386 pjmedia_snd_port_disconnect(snd_port); 387 388 pj_pool_release(snd_port->pool); 389 390 return status; 459 391 } 460 392 … … 552 484 553 485 /* Destroy AEC */ 554 if (snd_port->ec _state) {555 pjmedia_ echo_destroy(snd_port->ec_state);556 snd_port->ec _state= NULL;486 if (snd_port->echo_port) { 487 pjmedia_port_destroy(snd_port->echo_port); 488 snd_port->echo_port = NULL; 557 489 } 558 490 … … 565 497 // snd_port->clock_rate; 566 498 delay_ms = prm.output_latency_ms; 567 status = pjmedia_echo_create2(pool, snd_port->clock_rate, 568 snd_port->channel_count, 569 snd_port->samples_per_frame, 570 tail_ms, delay_ms, 571 options, &snd_port->ec_state); 499 status = pjmedia_echo_port_create(pool, snd_port->port, 500 tail_ms, delay_ms, 501 options, &snd_port->echo_port); 572 502 if (status != PJ_SUCCESS) 573 snd_port->ec_state = NULL; 574 else 575 snd_port->ec_suspended = PJ_FALSE; 503 snd_port->echo_port = NULL; 576 504 } else { 577 505 PJ_LOG(4,(THIS_FILE, "Echo canceller is now disabled in the " … … 623 551 } else { 624 552 /* We use software EC */ 625 *p_length = snd_port->ec _state? snd_port->ec_tail_len : 0;553 *p_length = snd_port->echo_port ? snd_port->ec_tail_len : 0; 626 554 } 627 555 return PJ_SUCCESS; … … 636 564 { 637 565 pjmedia_port_info *pinfo; 566 pjmedia_aud_param *param; 567 pjmedia_sync_param sync_param; 568 pj_status_t status; 638 569 639 570 PJ_ASSERT_RETURN(snd_port && port, PJ_EINVAL); … … 657 588 /* Port is okay. */ 658 589 snd_port->port = port; 590 591 /* Create software EC if parameter specifies EC but device 592 * doesn't support EC. Only do this if the format is PCM! 593 */ 594 param = &snd_port->aud_param; 595 if ((param->flags & PJMEDIA_AUD_DEV_CAP_EC) && 596 (snd_port->aud_caps & PJMEDIA_AUD_DEV_CAP_EC)==0 && 597 param->ext_fmt.id == PJMEDIA_FORMAT_PCM) 598 { 599 if ((param->flags & PJMEDIA_AUD_DEV_CAP_EC_TAIL)==0) { 600 param->flags |= PJMEDIA_AUD_DEV_CAP_EC_TAIL; 601 param->ec_tail_ms = AEC_TAIL; 602 PJ_LOG(4,(THIS_FILE, "AEC tail is set to default %u ms", 603 param->ec_tail_ms)); 604 } 605 606 status = pjmedia_snd_port_set_ec(snd_port, snd_port->pool, 607 param->ec_tail_ms, 0); 608 if (status != PJ_SUCCESS) 609 return status; 610 } 611 612 /* Create sync port */ 613 pj_bzero(&sync_param, sizeof(sync_param)); 614 sync_param.options = PJMEDIA_SYNC_DONT_DESTROY_DN; 615 status = pjmedia_sync_port_create(snd_port->pool, 616 (snd_port->echo_port? 617 snd_port->echo_port:snd_port->port), 618 &sync_param, &snd_port->sync_port); 619 if (status != PJ_SUCCESS) 620 return status; 621 622 /* Update down port of sound port */ 623 snd_port->dn_port = snd_port->sync_port; 624 659 625 return PJ_SUCCESS; 660 626 } … … 679 645 680 646 snd_port->port = NULL; 681 682 return PJ_SUCCESS; 683 } 684 685 647 snd_port->dn_port = NULL; 648 649 /* Destroy sync port */ 650 if (snd_port->sync_port) { 651 pjmedia_port_destroy(snd_port->sync_port); 652 snd_port->sync_port = NULL; 653 } 654 655 /* Destroy EC port */ 656 if (snd_port->echo_port) { 657 pjmedia_port_destroy(snd_port->echo_port); 658 snd_port->echo_port = NULL; 659 snd_port->ec_tail_len = 0; 660 snd_port->ec_options = 0; 661 } 662 663 return PJ_SUCCESS; 664 } 665 666
Note: See TracChangeset
for help on using the changeset viewer.