Changeset 205 for pjproject/trunk/pjmedia/src/pjmedia/conference.c
- Timestamp:
- Feb 21, 2006 12:11:18 AM (18 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
pjproject/trunk/pjmedia/src/pjmedia/conference.c
r203 r205 17 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 18 */ 19 #include <pjmedia/ audio_conf.h>19 #include <pjmedia/conference.h> 20 20 #include <pjmedia/vad.h> 21 21 #include <pjmedia/stream.h> 22 22 #include <pjmedia/sound.h> 23 23 #include <pjmedia/errno.h> 24 #include <pjmedia/port.h> 24 25 #include <pj/assert.h> 25 26 #include <pj/log.h> … … 27 28 #include <pj/string.h> 28 29 29 30 31 #define THIS_FILE "audio_conf.c" 30 //#define CONF_DEBUG 31 #ifdef CONF_DEBUG 32 # include <stdio.h> 33 # define TRACE_(x) printf x 34 #else 35 # define TRACE_(x) 36 #endif 37 38 39 #define THIS_FILE "conference.c" 40 #define RX_BUF_COUNT 8 41 42 /* 43 * DON'T GET CONFUSED!! 44 * 45 * TX and RX directions are always viewed from the conference bridge's point 46 * of view, and NOT from the port's point of view. 47 */ 32 48 33 49 34 50 struct conf_port 35 51 { 36 pj_str_t name; 37 pjmedia_stream_port *port; 38 pj_bool_t online; 39 pj_bool_t is_member; 40 pjmedia_vad *vad; 41 pj_int32_t level; 52 pj_str_t name; /**< Port name. */ 53 pjmedia_port *port; /**< get_frame() and put_frame() */ 54 pjmedia_port_op rx_setting; /**< Can we receive from this port */ 55 pjmedia_port_op tx_setting; /**< Can we transmit to this port */ 56 pj_bool_t *listeners; /**< Array of listeners. */ 57 pjmedia_vad *vad; /**< VAD for this port. */ 58 59 /* Tx buffer contains the frame to be "transmitted" to this port 60 * (i.e. for put_frame()). 61 * We use dual buffer since the port may be accessed by two threads, 62 * and we don't want to use mutex for synchronization. 63 */ 64 pj_int16_t *cur_tx_buf; /**< Buffer for put_frame(). */ 65 pj_int16_t *tx_buf1; /**< Buffer 1. */ 66 pj_int16_t *tx_buf2; /**< Buffer 2. */ 67 68 /* Rx buffers is a special buffer for sound device port (port 0). 69 * It's not used by other ports. 70 */ 71 int rx_write, rx_read; 72 pj_int16_t *rx_buf[RX_BUF_COUNT]; /**< Buffer */ 73 74 75 /* Sum buf is a temporary buffer used to calculate the average signal 76 * received by this port from all other ports. 77 */ 78 unsigned sources; /**< Number of sources. */ 79 pj_uint32_t *sum_buf; /**< Total sum of signal. */ 42 80 }; 43 81 82 44 83 /* 45 84 * Conference bridge. … … 47 86 struct pjmedia_conf 48 87 { 49 unsigned max_ports; /**< Maximum ports. */ 50 unsigned port_cnt; /**< Current number of ports. */ 51 pj_snd_stream *snd_rec; /**< Sound recorder stream. */ 52 pj_snd_stream *snd_player; /**< Sound player stream. */ 53 struct conf_port **port; /**< Array of ports. */ 54 pj_int16_t *rec_buf; /**< Sample buffer for rec. */ 55 pj_int16_t *play_buf; /**< Sample buffer for player */ 56 unsigned samples_cnt; /**< Samples per frame. */ 57 pj_size_t buf_size; /**< Buffer size, in bytes. */ 88 unsigned max_ports; /**< Maximum ports. */ 89 unsigned port_cnt; /**< Current number of ports. */ 90 unsigned connect_cnt; /**< Total number of connections */ 91 pj_snd_stream *snd_rec; /**< Sound recorder stream. */ 92 pj_snd_stream *snd_player; /**< Sound player stream. */ 93 struct conf_port **ports; /**< Array of ports. */ 94 pj_uint16_t *uns_buf; /**< Buf for unsigned conversion */ 95 unsigned sampling_rate; /**< Sampling rate. */ 96 unsigned samples_per_frame; /**< Samples per frame. */ 97 unsigned bits_per_sample; /**< Bits per sample. */ 98 pj_snd_stream_info snd_info; 58 99 }; 59 100 … … 69 110 /* in*/ unsigned size); 70 111 112 /* 113 * Create port. 114 */ 115 static pj_status_t create_conf_port( pj_pool_t *pool, 116 pjmedia_conf *conf, 117 const pj_str_t *name, 118 struct conf_port **p_conf_port) 119 { 120 struct conf_port *conf_port; 121 pj_status_t status; 122 123 /* Create port. */ 124 conf_port = pj_pool_zalloc(pool, sizeof(struct conf_port)); 125 PJ_ASSERT_RETURN(conf_port, PJ_ENOMEM); 126 127 /* Set name */ 128 pj_strdup(pool, &conf_port->name, name); 129 130 /* Default has tx and rx enabled. */ 131 conf_port->rx_setting = PJMEDIA_PORT_ENABLE; 132 conf_port->tx_setting = PJMEDIA_PORT_ENABLE; 133 134 /* Create transmit flag array */ 135 conf_port->listeners = pj_pool_zalloc(pool, 136 conf->max_ports*sizeof(pj_bool_t)); 137 PJ_ASSERT_RETURN(conf_port->listeners, PJ_ENOMEM); 138 139 140 /* Create and init vad. */ 141 status = pjmedia_vad_create( pool, &conf_port->vad); 142 if (status != PJ_SUCCESS) 143 return status; 144 145 pjmedia_vad_set_adaptive(conf_port->vad, conf->samples_per_frame); 146 147 148 /* Create TX buffers. */ 149 conf_port->tx_buf1 = pj_pool_zalloc(pool, conf->samples_per_frame * 150 sizeof(conf_port->tx_buf1[0])); 151 PJ_ASSERT_RETURN(conf_port->tx_buf1, PJ_ENOMEM); 152 153 conf_port->tx_buf2 = pj_pool_zalloc(pool, conf->samples_per_frame * 154 sizeof(conf_port->tx_buf2[0])); 155 PJ_ASSERT_RETURN(conf_port->tx_buf2, PJ_ENOMEM); 156 157 /* Set initial TX buffer */ 158 conf_port->cur_tx_buf = conf_port->tx_buf1; 159 160 /* Create temporary buffer to calculate average signal received by 161 * this port. 162 */ 163 conf_port->sum_buf = pj_pool_zalloc(pool, conf->samples_per_frame * 164 sizeof(conf_port->sum_buf[0])); 165 166 167 168 /* Done */ 169 *p_conf_port = conf_port; 170 return PJ_SUCCESS; 171 } 172 173 /* 174 * Create port zero for the sound device. 175 */ 176 static pj_status_t create_sound_port( pj_pool_t *pool, 177 pjmedia_conf *conf ) 178 { 179 struct conf_port *conf_port; 180 pj_str_t name = { "sound-device", 12 }; 181 unsigned i; 182 pj_status_t status; 183 184 185 /* Init default sound device parameters. */ 186 pj_memset(&conf->snd_info, 0, sizeof(conf->snd_info)); 187 conf->snd_info.samples_per_sec = conf->sampling_rate; 188 conf->snd_info.bits_per_sample = conf->bits_per_sample; 189 conf->snd_info.samples_per_frame = conf->samples_per_frame; 190 conf->snd_info.bytes_per_frame = conf->samples_per_frame * 191 conf->bits_per_sample / 8; 192 conf->snd_info.frames_per_packet = 1; 193 194 195 /* Create port */ 196 status = create_conf_port(pool, conf, &name, &conf_port); 197 if (status != PJ_SUCCESS) 198 goto on_error; 199 200 /* Sound device has rx buffers. */ 201 for (i=0; i<RX_BUF_COUNT; ++i) { 202 conf_port->rx_buf[i] = pj_pool_zalloc(pool, conf->samples_per_frame * 203 sizeof(conf_port->rx_buf[0][0])); 204 if (conf_port->rx_buf[i] == NULL) { 205 status = PJ_ENOMEM; 206 goto on_error; 207 } 208 } 209 conf_port->rx_write = 0; 210 conf_port->rx_read = 0; 211 212 213 /* Set to port zero */ 214 conf->ports[0] = conf_port; 215 conf->port_cnt++; 216 217 PJ_LOG(5,(THIS_FILE, "Sound device successfully created for port 0")); 218 return PJ_SUCCESS; 219 220 on_error: 221 return status; 222 223 } 71 224 72 225 /* … … 75 228 PJ_DEF(pj_status_t) pjmedia_conf_create( pj_pool_t *pool, 76 229 unsigned max_ports, 230 unsigned sampling_rate, 231 unsigned samples_per_frame, 232 unsigned bits_per_sample, 77 233 pjmedia_conf **p_conf ) 78 234 { 79 235 pjmedia_conf *conf; 80 pj_snd_stream_info snd_info;81 236 pj_status_t status; 82 237 238 PJ_LOG(5,(THIS_FILE, "Creating conference bridge with %d ports", 239 max_ports)); 240 241 /* Create and init conf structure. */ 83 242 conf = pj_pool_zalloc(pool, sizeof(pjmedia_conf)); 243 PJ_ASSERT_RETURN(conf, PJ_ENOMEM); 244 245 conf->ports = pj_pool_zalloc(pool, max_ports*sizeof(void*)); 246 PJ_ASSERT_RETURN(conf->ports, PJ_ENOMEM); 247 84 248 conf->max_ports = max_ports; 85 conf->port = pj_pool_zalloc(pool, max_ports*sizeof(void*)); 86 87 /* Create default parameters. */ 88 pj_memset(&snd_info, 0, sizeof(snd_info)); 89 snd_info.samples_per_sec = 8000; 90 snd_info.bits_per_sample = 16; 91 snd_info.samples_per_frame = 160; 92 snd_info.bytes_per_frame = 16000; 93 snd_info.frames_per_packet = 1; 94 95 /* Create buffers. */ 96 conf->samples_cnt = snd_info.samples_per_frame; 97 conf->buf_size = snd_info.samples_per_frame * snd_info.bits_per_sample / 8; 98 conf->rec_buf = pj_pool_alloc(pool, conf->buf_size); 99 conf->play_buf = pj_pool_alloc(pool, conf->buf_size ); 100 101 249 conf->sampling_rate = sampling_rate; 250 conf->samples_per_frame = samples_per_frame; 251 conf->bits_per_sample = bits_per_sample; 252 253 254 /* Create port zero for sound device. */ 255 status = create_sound_port(pool, conf); 256 if (status != PJ_SUCCESS) 257 return status; 258 259 /* Create temporary buffer. */ 260 conf->uns_buf = pj_pool_zalloc(pool, samples_per_frame * 261 sizeof(conf->uns_buf[0])); 262 /* Done */ 263 264 *p_conf = conf; 265 266 return PJ_SUCCESS; 267 } 268 269 270 /* 271 * Create sound device 272 */ 273 static pj_status_t create_sound( pjmedia_conf *conf ) 274 { 102 275 /* Open recorder. */ 103 conf->snd_rec = pj_snd_open_recorder(-1 ,& snd_info, &rec_cb, conf);276 conf->snd_rec = pj_snd_open_recorder(-1 ,&conf->snd_info, &rec_cb, conf); 104 277 if (conf->snd_rec == NULL) { 105 status = -1; 106 goto on_error; 278 return -1; 107 279 } 108 280 109 281 /* Open player */ 110 conf->snd_player = pj_snd_open_player(-1, & snd_info, &play_cb, conf);282 conf->snd_player = pj_snd_open_player(-1, &conf->snd_info, &play_cb, conf); 111 283 if (conf->snd_player == NULL) { 112 status = -1;113 goto on_error;114 } 115 116 /* Done */117 118 *p_conf = conf; 119 120 return PJ_SUCCESS;121 122 123 on_error: 284 pj_snd_stream_close(conf->snd_rec); 285 return -1; 286 } 287 288 return PJ_SUCCESS; 289 } 290 291 /* 292 * Destroy sound device 293 */ 294 static pj_status_t destroy_sound( pjmedia_conf *conf ) 295 { 124 296 if (conf->snd_rec) { 125 pj_snd_stream_stop(conf->snd_rec);126 297 pj_snd_stream_close(conf->snd_rec); 127 298 conf->snd_rec = NULL; 128 299 } 129 300 if (conf->snd_player) { 130 pj_snd_stream_stop(conf->snd_player);131 301 pj_snd_stream_close(conf->snd_player); 132 302 conf->snd_player = NULL; 133 303 } 134 return status;304 return PJ_SUCCESS; 135 305 } 136 306 … … 138 308 * Activate sound device. 139 309 */ 140 static pj_status_t activate_conf( pjmedia_conf *conf )310 static pj_status_t resume_sound( pjmedia_conf *conf ) 141 311 { 142 312 char errmsg[PJ_ERR_MSG_SIZE]; 143 313 pj_status_t status; 144 314 315 if (conf->snd_rec == NULL) { 316 status = create_sound(conf); 317 if (status != PJ_SUCCESS) 318 return status; 319 } 320 145 321 /* Start recorder. */ 146 status = pj_snd_stream_start(conf->snd_rec); 147 if (status != PJ_SUCCESS) 148 goto on_error; 322 if (conf->snd_rec) { 323 status = pj_snd_stream_start(conf->snd_rec); 324 if (status != PJ_SUCCESS) 325 goto on_error; 326 } 149 327 150 328 /* Start player. */ 151 status = pj_snd_stream_start(conf->snd_rec); 152 if (status != PJ_SUCCESS) 153 goto on_error; 329 if (conf->snd_player) { 330 status = pj_snd_stream_start(conf->snd_player); 331 if (status != PJ_SUCCESS) 332 goto on_error; 333 } 154 334 155 335 return PJ_SUCCESS; … … 166 346 * Suspend sound device 167 347 */ 168 static void suspend_conf( pjmedia_conf *conf ) 169 { 170 pj_snd_stream_stop(conf->snd_rec); 171 pj_snd_stream_stop(conf->snd_player); 348 static void suspend_sound( pjmedia_conf *conf ) 349 { 350 if (conf->snd_rec) 351 pj_snd_stream_stop(conf->snd_rec); 352 if (conf->snd_player) 353 pj_snd_stream_stop(conf->snd_player); 354 } 355 356 357 /** 358 * Destroy conference bridge. 359 */ 360 PJ_DEF(pj_status_t) pjmedia_conf_destroy( pjmedia_conf *conf ) 361 { 362 PJ_ASSERT_RETURN(conf != NULL, PJ_EINVAL); 363 364 suspend_sound(conf); 365 366 pj_snd_stream_close(conf->snd_rec); 367 conf->snd_rec = NULL; 368 pj_snd_stream_close(conf->snd_player); 369 conf->snd_player = NULL; 370 371 return PJ_SUCCESS; 172 372 } 173 373 … … 178 378 PJ_DEF(pj_status_t) pjmedia_conf_add_port( pjmedia_conf *conf, 179 379 pj_pool_t *pool, 180 pjmedia_ stream_port *strm_port,380 pjmedia_port *strm_port, 181 381 const pj_str_t *port_name, 182 382 unsigned *p_port ) … … 194 394 } 195 395 396 /* Find empty port in the conference bridge. */ 397 for (index=0; index < conf->max_ports; ++index) { 398 if (conf->ports[index] == NULL) 399 break; 400 } 401 402 pj_assert(index != conf->max_ports); 403 196 404 /* Create port structure. */ 197 conf_port = pj_pool_zalloc(pool, sizeof(struct conf_port)); 198 pj_strdup_with_null(pool, &conf_port->name, port_name); 199 conf_port->port = strm_port; 200 conf_port->online = PJ_TRUE; 201 conf_port->level = 0; 202 203 /* Create VAD for this port. */ 204 status = pjmedia_vad_create(pool, &conf_port->vad); 405 status = create_conf_port(pool, conf, port_name, &conf_port); 205 406 if (status != PJ_SUCCESS) 206 407 return status; 207 408 208 /* Set vad settings. */ 209 pjmedia_vad_set_adaptive(conf_port->vad, conf->samples_cnt); 210 211 /* Find empty port in the conference bridge. */ 212 for (index=0; index < conf->max_ports; ++index) { 213 if (conf->port[index] == NULL) 214 break; 215 } 216 217 pj_assert(index != conf->max_ports); 409 /* Set the port */ 410 conf_port->port = strm_port; 218 411 219 412 /* Put the port. */ 220 conf->port [index] = conf_port;413 conf->ports[index] = conf_port; 221 414 conf->port_cnt++; 222 415 223 /* If this is the first port, activate sound device. */ 224 if (conf->port_cnt == 1) { 225 status = activate_conf(conf);; 226 if (status != PJ_SUCCESS) { 227 conf->port[index] = NULL; 228 --conf->port_cnt; 229 return status; 416 /* Done. */ 417 *p_port = index; 418 419 return PJ_SUCCESS; 420 } 421 422 423 /* 424 * Change TX and RX settings for the port. 425 */ 426 PJ_DECL(pj_status_t) pjmedia_conf_configure_port( pjmedia_conf *conf, 427 unsigned slot, 428 pjmedia_port_op tx, 429 pjmedia_port_op rx) 430 { 431 struct conf_port *conf_port; 432 433 /* Check arguments */ 434 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 435 436 /* Port must be valid. */ 437 PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 438 439 conf_port = conf->ports[slot]; 440 441 if (tx != PJMEDIA_PORT_NO_CHANGE) 442 conf_port->tx_setting = tx; 443 444 if (rx != PJMEDIA_PORT_NO_CHANGE) 445 conf_port->rx_setting = rx; 446 447 return PJ_SUCCESS; 448 } 449 450 451 /* 452 * Connect port. 453 */ 454 PJ_DEF(pj_status_t) pjmedia_conf_connect_port( pjmedia_conf *conf, 455 unsigned src_slot, 456 unsigned sink_slot ) 457 { 458 struct conf_port *src_port, *dst_port; 459 460 /* Check arguments */ 461 PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports && 462 sink_slot<conf->max_ports, PJ_EINVAL); 463 464 /* Ports must be valid. */ 465 PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL); 466 PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL); 467 468 src_port = conf->ports[src_slot]; 469 dst_port = conf->ports[sink_slot]; 470 471 if (src_port->listeners[sink_slot] == 0) { 472 src_port->listeners[sink_slot] = 1; 473 ++conf->connect_cnt; 474 475 if (conf->connect_cnt == 1) 476 resume_sound(conf); 477 478 PJ_LOG(5,(THIS_FILE,"Port %.*s transmitting to port %.*s", 479 (int)src_port->name.slen, 480 src_port->name.ptr, 481 (int)dst_port->name.slen, 482 dst_port->name.ptr)); 483 } 484 485 return PJ_SUCCESS; 486 } 487 488 489 /* 490 * Disconnect port 491 */ 492 PJ_DEF(pj_status_t) pjmedia_conf_disconnect_port( pjmedia_conf *conf, 493 unsigned src_slot, 494 unsigned sink_slot ) 495 { 496 struct conf_port *src_port, *dst_port; 497 498 /* Check arguments */ 499 PJ_ASSERT_RETURN(conf && src_slot<conf->max_ports && 500 sink_slot<conf->max_ports, PJ_EINVAL); 501 502 /* Ports must be valid. */ 503 PJ_ASSERT_RETURN(conf->ports[src_slot] != NULL, PJ_EINVAL); 504 PJ_ASSERT_RETURN(conf->ports[sink_slot] != NULL, PJ_EINVAL); 505 506 src_port = conf->ports[src_slot]; 507 dst_port = conf->ports[sink_slot]; 508 509 if (src_port->listeners[sink_slot] != 0) { 510 src_port->listeners[sink_slot] = 0; 511 --conf->connect_cnt; 512 513 PJ_LOG(5,(THIS_FILE,"Port %.*s stop transmitting to port %.*s", 514 (int)src_port->name.slen, 515 src_port->name.ptr, 516 (int)dst_port->name.slen, 517 dst_port->name.ptr)); 518 519 if (conf->connect_cnt == 0) { 520 suspend_sound(conf); 521 destroy_sound(conf); 230 522 } 231 523 } 232 524 233 /* Done. */ 234 return PJ_SUCCESS; 235 } 236 237 238 /* 239 * Mute or unmute port. 240 */ 241 PJ_DEF(pj_status_t) pjmedia_conf_set_mute( pjmedia_conf *conf, 242 unsigned port, 243 pj_bool_t mute ) 244 { 525 return PJ_SUCCESS; 526 } 527 528 529 /* 530 * Remove the specified port. 531 */ 532 PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf, 533 unsigned port ) 534 { 535 struct conf_port *conf_port; 536 unsigned i; 537 245 538 /* Check arguments */ 246 539 PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 247 540 248 541 /* Port must be valid. */ 249 PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 250 251 conf->port[port]->online = !mute; 252 253 return PJ_SUCCESS; 254 } 255 256 257 /* 258 * Set the specified port to be member of conference bridge. 259 */ 260 PJ_DEF(pj_status_t) pjmedia_conf_set_membership( pjmedia_conf *conf, 261 unsigned port, 262 pj_bool_t enabled ) 263 { 264 /* Check arguments */ 265 PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 266 267 /* Port must be valid. */ 268 PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 269 270 conf->port[port]->is_member = enabled; 271 272 return PJ_SUCCESS; 273 } 274 275 276 /* 277 * Remove the specified port. 278 */ 279 PJ_DEF(pj_status_t) pjmedia_conf_remove_port( pjmedia_conf *conf, 280 unsigned port ) 281 { 282 /* Check arguments */ 283 PJ_ASSERT_RETURN(conf && port < conf->max_ports, PJ_EINVAL); 284 285 /* Port must be valid. */ 286 PJ_ASSERT_RETURN(conf->port[port] != NULL, PJ_EINVAL); 542 PJ_ASSERT_RETURN(conf->ports[port] != NULL, PJ_EINVAL); 287 543 288 544 /* Suspend the sound devices. 289 545 * Don't want to remove port while port is being accessed by sound 290 * device's threads .546 * device's threads! 291 547 */ 292 suspend_conf(conf); 548 //suspend_sound(conf); 549 550 conf_port = conf->ports[port]; 551 conf_port->tx_setting = PJMEDIA_PORT_DISABLE; 552 conf_port->rx_setting = PJMEDIA_PORT_DISABLE; 553 554 /* Remove this port from transmit array of other ports. */ 555 for (i=0; i<conf->max_ports; ++i) { 556 conf_port = conf->ports[i]; 557 558 if (!conf_port) 559 continue; 560 561 if (conf_port->listeners[port] != 0) { 562 --conf->connect_cnt; 563 conf_port->listeners[port] = 0; 564 } 565 } 566 567 /* Remove all ports listening from this port. */ 568 conf_port = conf->ports[port]; 569 for (i=0; i<conf->max_ports; ++i) { 570 if (conf_port->listeners[i]) 571 --conf->connect_cnt; 572 } 293 573 294 574 /* Remove the port. */ 295 conf->port [port] = NULL;575 conf->ports[port] = NULL; 296 576 --conf->port_cnt; 297 577 298 /* Reactivate sound device if ports are not zero */ 299 if (conf->port_cnt != 0) 300 activate_conf(conf); 301 302 return PJ_SUCCESS; 303 } 304 578 /* Reactivate sound device if there are connections */ 579 if (conf->connect_cnt != 0) { 580 //resume_sound(conf); 581 } else { 582 destroy_sound(conf); 583 } 584 585 pj_thread_sleep(60); 586 return PJ_SUCCESS; 587 } 588 589 /* 590 * Get port info 591 */ 592 PJ_DEF(pj_status_t) pjmedia_conf_get_port_info( pjmedia_conf *conf, 593 unsigned slot, 594 pjmedia_conf_port_info *info) 595 { 596 struct conf_port *conf_port; 597 598 /* Check arguments */ 599 PJ_ASSERT_RETURN(conf && slot<conf->max_ports, PJ_EINVAL); 600 601 /* Port must be valid. */ 602 PJ_ASSERT_RETURN(conf->ports[slot] != NULL, PJ_EINVAL); 603 604 conf_port = conf->ports[slot]; 605 606 info->name = conf_port->name; 607 info->tx_setting = conf_port->tx_setting; 608 info->rx_setting = conf_port->rx_setting; 609 info->listener = conf_port->listeners; 610 611 return PJ_SUCCESS; 612 } 613 614 615 /* Convert signed 16bit pcm sample to unsigned 16bit sample */ 616 static pj_uint16_t pcm2unsigned(pj_int32_t pcm) 617 { 618 return (pj_uint16_t)(pcm + 32767); 619 } 620 621 /* Convert unsigned 16bit sample to signed 16bit pcm sample */ 622 static pj_int16_t unsigned2pcm(pj_uint32_t uns) 623 { 624 return (pj_int16_t)(uns - 32767); 625 } 305 626 306 627 /* … … 314 635 pjmedia_conf *conf = user_data; 315 636 pj_int16_t *output_buf = output; 316 pj_int32_t highest_level = 0;317 int highest_index = -1;318 unsigned sources = 0;319 637 unsigned i, j; 320 638 321 639 PJ_UNUSED_ARG(timestamp); 322 323 /* Clear temporary buffer. */ 324 pj_memset(output_buf, 0, size);325 326 /* Get frames from ports. */640 PJ_UNUSED_ARG(size); 641 642 TRACE_(("p")); 643 644 /* Clear all port's tmp buffers. */ 327 645 for (i=0; i<conf->max_ports; ++i) { 328 struct conf_port *conf_port = conf->port[i]; 646 struct conf_port *conf_port = conf->ports[i]; 647 pj_uint32_t *sum_buf; 648 649 if (!conf_port) 650 continue; 651 652 conf_port->sources = 0; 653 sum_buf = conf_port->sum_buf; 654 655 for (j=0; j<conf->samples_per_frame; ++j) 656 sum_buf[j] = 0; 657 } 658 659 /* Get frames from all ports, and "add" the signal 660 * to sum_buf of all listeners of the port. 661 */ 662 for (i=0; i<conf->max_ports; ++i) { 663 struct conf_port *conf_port = conf->ports[i]; 329 664 pj_int32_t level; 330 665 pj_bool_t silence; 331 666 667 /* Skip empty port. */ 332 668 if (!conf_port) 333 669 continue; 334 670 335 conf_port->port->get_frame(conf->play_buf, conf->samples_cnt); 671 /* Skip if we're not allowed to receive from this port. */ 672 if (conf_port->rx_setting == PJMEDIA_PORT_DISABLE) { 673 TRACE_(("rxdis:%d ", i)); 674 continue; 675 } 676 677 /* Get frame from this port. 678 * If port has rx_buffer, then get the frame from the rx_buffer 679 * instead. 680 */ 681 if (i==0/*conf_port->cur_rx_buf*/) { 682 pj_int16_t *rx_buf; 683 684 if (conf_port->rx_read == conf_port->rx_write) 685 conf_port->rx_read = (conf_port->rx_write+RX_BUF_COUNT-RX_BUF_COUNT/2) % RX_BUF_COUNT; 686 687 rx_buf = conf_port->rx_buf[conf_port->rx_read]; 688 for (j=0; j<conf->samples_per_frame; ++j) { 689 ((pj_int16_t*)output)[j] = rx_buf[j]; 690 } 691 conf_port->rx_read = (conf_port->rx_read+1) % RX_BUF_COUNT; 692 } else { 693 pjmedia_frame frame; 694 695 pj_memset(&frame, 0, sizeof(frame)); 696 frame.buf = output; 697 frame.size = size; 698 pjmedia_port_get_frame(conf_port->port, &frame); 699 } 700 701 /* Skip (after receiving the frame) if this port is muted. */ 702 if (conf_port->rx_setting == PJMEDIA_PORT_MUTE) 703 continue; 704 705 /* Do we have signal? */ 336 706 silence = pjmedia_vad_detect_silence(conf_port->vad, 337 conf->play_buf,338 conf->samples_ cnt,707 output, 708 conf->samples_per_frame, 339 709 &level); 340 if (!silence) { 341 if (level > highest_level) { 342 highest_index = i; 343 highest_level = level; 344 } 345 346 ++sources; 347 348 for (j=0; j<conf->samples_cnt; ++j) { 349 output_buf[j] = (pj_int16_t)(output_buf[j] + conf->play_buf[j]); 710 711 /* Skip if we don't have signal. */ 712 if (silence) { 713 TRACE_(("sil:%d ", i)); 714 continue; 715 } 716 717 /* Convert the buffer to unsigned value */ 718 for (j=0; j<conf->samples_per_frame; ++j) 719 conf->uns_buf[j] = pcm2unsigned(((pj_int16_t*)output)[j]); 720 721 /* Add the signal to all listeners. */ 722 for (j=0; j<conf->max_ports; ++j) { 723 struct conf_port *listener = conf->ports[j]; 724 pj_uint32_t *sum_buf; 725 unsigned k; 726 727 if (conf_port->listeners[j] == 0) 728 continue; 729 730 /* Skip if this listener doesn't want to receive audio */ 731 if (listener->tx_setting != PJMEDIA_PORT_ENABLE) 732 continue; 733 734 //TRACE_(("mix:%d->%d ", i, j)); 735 736 sum_buf = listener->sum_buf; 737 for (k=0; k<conf->samples_per_frame; ++k) 738 sum_buf[k] += conf->uns_buf[k]; 739 740 listener->sources++; 741 } 742 } 743 744 /* For all ports, calculate avg signal. */ 745 for (i=0; i<conf->max_ports; ++i) { 746 struct conf_port *conf_port = conf->ports[i]; 747 pjmedia_frame frame; 748 pj_int16_t *target_buf; 749 750 if (!conf_port) 751 continue; 752 753 754 target_buf = (conf_port->cur_tx_buf==conf_port->tx_buf1? 755 conf_port->tx_buf2 : conf_port->tx_buf1); 756 757 if (!conf_port->sources) { 758 for (j=0; j<conf->samples_per_frame; ++j) 759 target_buf[j] = 0; 760 } else { 761 for (j=0; j<conf->samples_per_frame; ++j) { 762 target_buf[j] = unsigned2pcm(conf_port->sum_buf[j] / conf_port->sources); 350 763 } 351 764 } 352 } 353 354 /* Calculate average signal. */ 355 if (sources) { 356 for (j=0; j<conf->samples_cnt; ++j) { 357 output_buf[j] = (pj_int16_t)(output_buf[j] / sources); 358 } 359 } 360 361 /* Broadcast to conference member. */ 362 for (i=0; i<conf->max_ports; ++i) { 363 struct conf_port *conf_port = conf->port[i]; 364 365 if (!conf_port) 765 766 /* Switch buffer. */ 767 conf_port->cur_tx_buf = target_buf; 768 769 if (conf_port->tx_setting != PJMEDIA_PORT_ENABLE) 366 770 continue; 367 771 368 if (!conf_port->is_member) 369 continue; 370 371 conf_port->port->put_frame(output_buf, conf->samples_cnt); 372 } 373 374 return PJ_SUCCESS; 375 } 772 pj_memset(&frame, 0, sizeof(frame)); 773 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 774 frame.buf = conf_port->cur_tx_buf; 775 frame.size = conf->samples_per_frame * conf->bits_per_sample / 8; 776 frame.timestamp.u64 = timestamp; 777 778 if (conf_port->port) 779 pjmedia_port_put_frame(conf_port->port, &frame); 780 781 } 782 783 /* Return sound playback frame. */ 784 for (j=0; j<conf->samples_per_frame; ++j) 785 output_buf[j] = conf->ports[0]->cur_tx_buf[j]; 786 787 return PJ_SUCCESS; 788 } 789 376 790 377 791 /* … … 381 795 /* in */ pj_uint32_t timestamp, 382 796 /* in */ const void *input, 383 /* in */unsigned size)797 /* in */ unsigned size) 384 798 { 385 799 pjmedia_conf *conf = user_data; 800 struct conf_port *snd_port = conf->ports[0]; 801 pj_int16_t *target_rx_buf; 386 802 unsigned i; 387 803 388 804 PJ_UNUSED_ARG(timestamp); 389 PJ_UNUSED_ARG(size); 390 391 for (i=0; i<conf->max_ports; ++i) { 392 struct conf_port *conf_port = conf->port[i]; 805 806 TRACE_(("r")); 807 808 if (size != conf->samples_per_frame*2) { 809 TRACE_(("rxerr ")); 810 } 811 812 813 /* Determine which rx_buffer to fill in */ 814 target_rx_buf = snd_port->rx_buf[snd_port->rx_write]; 815 816 /* Copy samples from audio device to target rx_buffer */ 817 for (i=0; i<conf->samples_per_frame; ++i) { 818 target_rx_buf[i] = ((pj_int16_t*)input)[i]; 819 } 820 821 /* Switch buffer */ 822 snd_port->rx_write = (snd_port->rx_write+1)%RX_BUF_COUNT; 823 824 825 /* Time for all ports (except sound port) to transmit frames */ 826 /* 827 for (i=1; i<conf->max_ports; ++i) { 828 struct conf_port *conf_port = conf->ports[i]; 829 pjmedia_frame frame; 393 830 394 831 if (!conf_port) 395 832 continue; 396 833 397 if (!conf_port->online) 398 continue; 399 400 conf_port->port->put_frame(input, conf->samples_cnt); 401 } 834 } 835 */ 402 836 403 837 return PJ_SUCCESS;
Note: See TracChangeset
for help on using the changeset viewer.