Parent Directory
|
Revision Log
Pass/store rtp information in RtpIpInfo objects. These include the media direction in addition to the ip address and port number.
1 /* 2 * This file is part of Project DiaStar Server. 3 * 4 * More information about this project can be found at: 5 * http://www.projectdiastar.org. 6 * 7 * Copyright (C) 2009,2010 Dialogic Corp. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 2 12 * of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 * 02110-1301, USA. 23 * Alternatively see <http://www.gnu.org/licenses/>. 24 * Or see the LICENSE file included within the source tree. 25 * 26 */ 27 28 /*! 29 * \file ipmdevice.cxx 30 * \brief Controller for a Dialogic IPM device. 31 * \author Antony Martin <antony.martin@dialogic.com> 32 * \author John Tarlton <john.tarlton@dialogic.com> 33 * \version 2-APR-2009 34 */ 35 36 /*------------------------------ Dependencies --------------------------------*/ 37 38 #include <climits> 39 40 #include "logger.h" 41 #include "string-util.h" 42 43 #include "overlay.h" 44 #include "dialogicchannelmanager.h" 45 #include "mmdevice.h" 46 #include "gciptdevice.h" 47 #include "ipmdevice.h" 48 49 /*----------------------------------------------------------------------------*/ 50 51 52 /* 53 * ctor 54 */ 55 IpmDevice::IpmDevice( const std::string& name, 56 DialogicChannelManager& channelMgr ) 57 : DialogicDevice(name, channelMgr) 58 { 59 ipt_ = 0; /* Standalone mode. */ 60 61 busy_ = false; 62 63 overlay_ = 0; 64 overlayActive_ = false; 65 66 /* Use configured client audio coder as the default. 67 */ 68 const Coders::audio_coders_t& audioCoders = channelMgr_.getAudioCoders(); 69 Coders::audio_coders_t::const_iterator i = audioCoders.begin(); 70 for ( ; i != audioCoders.end(); ++i ) 71 { 72 if ( channelMgr_.getClientAudioFormat() == (*i).encoding ) 73 { 74 localMedia_.audioCoder = *i; 75 break; 76 } 77 } 78 if ( i == audioCoders.end() ) 79 { 80 /* Hard default: PCMU */ 81 82 LOGWARN("IpmDevice::IpmDevice() No coder found for: " << 83 channelMgr_.getClientAudioFormat() << 84 ", falling back to hard default PCMU"); 85 86 localMedia_.audioCoder.coderType = CODER_TYPE_G711ULAW64K; 87 localMedia_.audioCoder.coderPayloadType = 0; 88 localMedia_.audioCoder.coderFramesize = CODER_FRAMESIZE_20; 89 localMedia_.audioCoder.framesPerPkt = 1; 90 localMedia_.audioCoder.vadEnable = CODER_VAD_ENABLE; 91 localMedia_.audioCoder.redPayloadType = 0; 92 } 93 94 /* Use configured client video coder as the default. 95 */ 96 const Coders::video_coders_t& videoCoders = channelMgr_.getVideoCoders(); 97 Coders::video_coders_t::const_iterator j = videoCoders.begin(); 98 for ( ; j != videoCoders.end(); ++j ) 99 { 100 if ( channelMgr_.getClientVideoFormat() == (*j).encoding ) 101 { 102 localMedia_.videoCoder = *j; 103 break; 104 } 105 } 106 if ( j == videoCoders.end() ) 107 { 108 /* Hard default: H.263 QCIF=2 */ 109 110 LOGWARN("IpmDevice::IpmDevice() No coder found for: " << 111 channelMgr_.getClientVideoFormat() << 112 ", falling back to hard default H.263"); 113 114 localMedia_.videoCoder.coderType = CODER_TYPE_H263; 115 localMedia_.videoCoder.coderPayloadType = 34; 116 localMedia_.videoCoder.samplingRate = VIDEO_SAMPLING_RATE_DEFAULT; 117 118 localMedia_.videoCoder.active_fmt.imageWidth = VIDEO_IMAGE_WIDTH_176; 119 localMedia_.videoCoder.active_fmt.imageHeight = VIDEO_IMAGE_HEIGHT_144; 120 localMedia_.videoCoder.active_fmt.framesPerSec = VIDEO_FRAMESPERSEC_15; 121 localMedia_.videoCoder.active_fmt.bitRate = 384000; 122 localMedia_.videoCoder.active_fmt.profile = VIDEO_PROFILE_0_H263; 123 localMedia_.videoCoder.active_fmt.level = VIDEO_LEVEL_30_H263; 124 localMedia_.videoCoder.available_fmts.push_back(localMedia_.videoCoder.active_fmt); 125 } 126 127 remoteMedia_.audioCoder = localMedia_.audioCoder; 128 remoteMedia_.videoCoder = localMedia_.videoCoder; 129 130 dtmfMode_ = DTMF_RFC2833; 131 rfc2833PayloadType_ = DEFAULT_RFC2833_PAYLOAD_TYPE; /* may be changed by sdp processing */ 132 133 /* Number of steps in the initialisation sequence, decremented by event 134 * handlers. When zero, state is changed to IDLE. 135 * 136 * IPMEV_OPEN, 137 * DMEV_GET_RX_PORT_INFO, 138 * DMEV_GET_TX_PORT_INFO 139 */ 140 initStepsRemaining_ = 3; 141 } 142 143 144 /* 145 * dtor 146 */ 147 IpmDevice::~IpmDevice() 148 { 149 delete overlay_; 150 } 151 152 153 /* 154 * Use current timestamp as session id and initial version. 155 */ 156 void IpmDevice::initSdpSession() 157 { 158 time_t t; 159 time(&t); 160 std::stringstream session_id_and_version; 161 session_id_and_version << t; 162 localMedia_.origin.sess_id = session_id_and_version.str(); 163 localMedia_.origin.sess_version = session_id_and_version.str(); 164 } 165 166 167 /* 168 * Process a command that was queueued because an async operation was in progress 169 * when it was initially requested. 170 */ 171 void IpmDevice::processPendingCommand() 172 { 173 while ( !busy_ && !pending_.empty() ) 174 { 175 switch ( pending_.front().cmd ) 176 { 177 case IpmCommand::START: 178 startMedia(); 179 break; 180 181 case IpmCommand::STOP: 182 stopMedia(pending_.front().operation); 183 break; 184 185 case IpmCommand::LISTEN: 186 listen(pending_.front().other.audio); 187 break; 188 189 case IpmCommand::UNLISTEN: 190 unListen(); 191 break; 192 193 case IpmCommand::CONNECT: 194 connect(pending_.front().other.audio, 195 pending_.front().other.video, 196 pending_.front().other.transcode_audio, 197 pending_.front().other.transcode_video); 198 break; 199 200 case IpmCommand::DISCONNECT: 201 disconnect(); 202 break; 203 204 case IpmCommand::ADD_OVERLAY: 205 addOverlay(pending_.front().overlay_info); 206 break; 207 208 case IpmCommand::REMOVE_OVERLAY: 209 removeOverlay(); 210 break; 211 212 case IpmCommand::GENERATE_IFRAME: 213 generateIFrame(pending_.front().force_iframe); 214 break; 215 216 default: 217 break; 218 } 219 pending_.pop(); 220 } 221 } 222 223 224 /* 225 * Open the device. 226 */ 227 bool IpmDevice::open() 228 { 229 LOGDEBUG("IpmDevice::open() device: " << getDeviceName()); 230 231 devHandle_ = ipm_Open(getDeviceName().c_str(), NULL, EV_ASYNC); 232 if ( devHandle_ < 0 ) 233 { 234 LOGERROR("ipm_Open() failed"); 235 return false; 236 } 237 state_ = IPM_OPENING; 238 return true; 239 } 240 241 242 /* 243 * Close the device 244 */ 245 bool IpmDevice::close() 246 { 247 LOGDEBUG("IpmDevice::close() device: " << getDeviceName()); 248 249 if ( state_ == IPM_STREAMING ) 250 { 251 ipm_Stop(devHandle_, STOP_ALL, EV_SYNC); 252 } 253 254 if ( devHandle_ > 0 ) 255 { 256 if ( ipm_Close(devHandle_, NULL) < 0 ) 257 { 258 LOGERROR("ipm_Close() failed"); 259 return false; 260 } 261 devHandle_ = 0; 262 } 263 return true; 264 } 265 266 267 /* 268 * Connect media. 269 */ 270 bool IpmDevice::listen( DialogicDevice* other ) 271 { 272 if ( busy_ ) 273 { 274 pending_.push(IpmCommand(IpmCommand::LISTEN, other)); 275 return true; 276 } 277 278 if ( other_audio_ != other ) 279 { 280 LOGDEBUG("IpmDevice::listen() device: " << getDeviceName() << 281 " other: " << other->getDeviceName()); 282 283 SC_TSINFO tsinfo; 284 tsinfo.sc_numts = 1; 285 tsinfo.sc_tsarrayp = other->getXmitTimeslotPtr(); 286 287 if ( ipm_Listen(devHandle_, &tsinfo, EV_ASYNC) == -1 ) 288 { 289 LOGERROR("ipm_Listen() failed on device: " << getDeviceName() << 290 " " << ATDV_ERRMSGP(devHandle_)); 291 return false; 292 } 293 other_audio_ = other; 294 busy_ = true; 295 } 296 return true; 297 } 298 299 300 /* 301 * Disconnect media. 302 */ 303 bool IpmDevice::unListen() 304 { 305 if ( busy_ ) 306 { 307 pending_.push(IpmCommand(IpmCommand::UNLISTEN)); 308 return true; 309 } 310 311 if ( other_audio_ ) 312 { 313 LOGDEBUG("IpmDevice::unListen() device: " << getDeviceName()); 314 315 if ( ipm_UnListen(devHandle_, EV_ASYNC) == -1) 316 { 317 LOGERROR("ipm_UnListen() failed on device: " << getDeviceName() << 318 " " << ATDV_ERRMSGP(devHandle_)); 319 return false; 320 } 321 other_audio_ = 0; 322 busy_ = true; 323 } 324 return true; 325 } 326 327 328 /* 329 * Connect media. 330 */ 331 bool IpmDevice::connect( DialogicDevice* other_audio, 332 DialogicDevice* other_video, 333 bool transcode_audio, 334 bool transcode_video ) 335 { 336 if ( busy_ ) 337 { 338 pending_.push(IpmCommand(IpmCommand::CONNECT, 339 other_audio, 340 other_video, 341 transcode_audio, 342 transcode_video)); 343 return true; 344 } 345 346 if ( !other_audio_ && !other_video_ ) 347 { 348 LOGDEBUG("IpmDevice::connect() device: " << getDeviceName() << 349 " other_audio: " << (other_audio ? other_audio->getDeviceName() : "n/a") << 350 " other_video: " << (other_video ? other_video->getDeviceName() : "n/a") << 351 " transcode_audio: " << (transcode_audio ? "Y" : "N") << 352 " transcode_video: " << (transcode_video ? "Y" : "N")); 353 354 DM_PORT_CONNECT_INFO_LIST portConnectInfoList; 355 memset(&portConnectInfoList, 0, sizeof(portConnectInfoList)); 356 INIT_DM_PORT_CONNECT_INFO_LIST(&portConnectInfoList); 357 int count = 0; 358 359 if ( other_audio ) 360 { 361 INIT_DM_PORT_CONNECT_INFO(&portConnectInfoList.port_connect_info[count]); 362 audioConnectFlags_ = transcode_audio ? DMFL_TRANSCODE_ON : DMFL_TRANSCODE_NATIVE; 363 portConnectInfoList.port_connect_info[count].unFlags = audioConnectFlags_; 364 portConnectInfoList.port_connect_info[count].port_info_tx = getAudioTxPortInfo(); 365 portConnectInfoList.port_connect_info[count].port_info_rx = other_audio->getAudioRxPortInfo(); 366 count++; 367 } 368 if ( other_video ) 369 { 370 INIT_DM_PORT_CONNECT_INFO(&portConnectInfoList.port_connect_info[count]); 371 videoConnectFlags_ = transcode_video ? DMFL_TRANSCODE_ON : DMFL_TRANSCODE_NATIVE; 372 portConnectInfoList.port_connect_info[count].unFlags = videoConnectFlags_; 373 portConnectInfoList.port_connect_info[count].port_info_tx = getVideoTxPortInfo(); 374 portConnectInfoList.port_connect_info[count].port_info_rx = other_video->getVideoRxPortInfo(); 375 count++; 376 } 377 portConnectInfoList.unCount = count; 378 if ( dev_PortConnect(devHandle_, &portConnectInfoList, NULL) != DEV_SUCCESS ) 379 { 380 LOGERROR("IpmDevice::connect() dev_PortConnect() failed on device: " << getDeviceName() << 381 " " << ATDV_ERRMSGP(devHandle_)); 382 return false; 383 } 384 385 other_audio_ = other_audio; 386 other_video_ = other_video; 387 busy_ = true; 388 } 389 else 390 { 391 LOGERROR("IpmDevice::connect() device: " << getDeviceName() << " already connected" 392 ", other_audio: " << (other_audio_ ? other_audio_->getDeviceName() : "n/a") << 393 ", other_video: " << (other_video_ ? other_video_->getDeviceName() : "n/a")); 394 return false; 395 } 396 return true; 397 } 398 399 400 /* 401 * Disconnect media. 402 */ 403 bool IpmDevice::disconnect() 404 { 405 if ( busy_ ) 406 { 407 pending_.push(IpmCommand(IpmCommand::DISCONNECT)); 408 return true; 409 } 410 411 if ( other_audio_ || other_video_ ) 412 { 413 LOGDEBUG("IpmDevice::disconnect() device: " << getDeviceName() << 414 " other_audio: " << (other_audio_ ? other_audio_->getDeviceName() : "n/a") << 415 " other_video: " << (other_video_ ? other_video_->getDeviceName() : "n/a")); 416 417 DM_PORT_CONNECT_INFO_LIST portConnectInfoList; 418 memset(&portConnectInfoList, 0, sizeof(portConnectInfoList)); 419 INIT_DM_PORT_CONNECT_INFO_LIST(&portConnectInfoList); 420 int count = 0; 421 422 if ( other_audio_ ) 423 { 424 INIT_DM_PORT_CONNECT_INFO(&portConnectInfoList.port_connect_info[count]); 425 portConnectInfoList.port_connect_info[count].unFlags = audioConnectFlags_; 426 portConnectInfoList.port_connect_info[count].port_info_tx = getAudioTxPortInfo(); 427 portConnectInfoList.port_connect_info[count].port_info_rx = other_audio_->getAudioRxPortInfo(); 428 count++; 429 } 430 if ( other_video_ ) 431 { 432 INIT_DM_PORT_CONNECT_INFO(&portConnectInfoList.port_connect_info[count]); 433 portConnectInfoList.port_connect_info[count].unFlags = videoConnectFlags_; 434 portConnectInfoList.port_connect_info[count].port_info_tx = getVideoTxPortInfo(); 435 portConnectInfoList.port_connect_info[count].port_info_rx = other_video_->getVideoRxPortInfo(); 436 count++; 437 } 438 439 portConnectInfoList.unCount = count; 440 if ( dev_PortDisconnect(devHandle_, &portConnectInfoList, NULL) != DEV_SUCCESS ) 441 { 442 LOGERROR("IpmDevice::disconnect() dev_PortDisconnect() failed on device: " << getDeviceName() << 443 " " << ATDV_ERRMSGP(devHandle_)); 444 return false; 445 } 446 other_audio_ = 0; 447 other_video_ = 0; 448 busy_ = true; 449 } 450 else /* not connected, fake completion. */ 451 { 452 if ( channel_ ) 453 { 454 channel_->onDisconnectCompleted(this); 455 } 456 } 457 return true; 458 } 459 460 461 /* 462 * Get local RTP info. 463 */ 464 bool IpmDevice::getLocalMediaInfo( eIPM_MEDIA_TYPE type, 465 RtpIpInfo& rtp_media ) const 466 { 467 switch ( type ) 468 { 469 case MEDIATYPE_AUDIO_LOCAL_RTP_INFO: 470 rtp_media = localMedia_.audioRtp; 471 break; 472 473 case MEDIATYPE_AUDIO_LOCAL_RTCP_INFO: 474 rtp_media = localMedia_.audioRtcp; 475 break; 476 477 case MEDIATYPE_VIDEO_LOCAL_RTP_INFO: 478 rtp_media = localMedia_.videoRtp; 479 break; 480 481 case MEDIATYPE_VIDEO_LOCAL_RTCP_INFO: 482 rtp_media = localMedia_.videoRtcp; 483 break; 484 485 default: 486 return false; 487 } 488 return true; 489 } 490 491 492 /* 493 * Save the remote params, the RTCP port is assumed to be media + 1. 494 */ 495 void IpmDevice::setRemoteMediaInfo( eIPM_MEDIA_TYPE type, 496 const RtpIpInfo& rtp_info ) 497 { 498 if ( type == MEDIATYPE_AUDIO_REMOTE_RTP_INFO ) 499 { 500 remoteMedia_.audioRtp = rtp_info; 501 remoteMedia_.audioRtcp = rtp_info; 502 remoteMedia_.audioRtcp.setPort(remoteMedia_.audioRtp.getPort() + 1); 503 504 LOGDEBUG("IpmDevice::setRemoteMediaInfo() device: " << getDeviceName() << 505 " a=" << remoteMedia_.audioRtp); 506 } 507 if ( type == MEDIATYPE_VIDEO_REMOTE_RTP_INFO ) 508 { 509 remoteMedia_.videoRtp = rtp_info; 510 remoteMedia_.videoRtcp = rtp_info; 511 remoteMedia_.videoRtcp.setPort(remoteMedia_.videoRtp.getPort() + 1); 512 513 LOGDEBUG("IpmDevice::setRemoteMediaInfo() device: " << getDeviceName() << 514 " v=" << remoteMedia_.videoRtp); 515 } 516 } 517 518 519 /* 520 * Get remote Rtp info. 521 */ 522 bool IpmDevice::getRemoteMediaInfo( eIPM_MEDIA_TYPE type, 523 RtpIpInfo& rtp_media ) const 524 { 525 switch ( type ) 526 { 527 case MEDIATYPE_AUDIO_REMOTE_RTP_INFO: 528 rtp_media = remoteMedia_.audioRtp; 529 break; 530 531 case MEDIATYPE_AUDIO_REMOTE_RTCP_INFO: 532 rtp_media = remoteMedia_.audioRtcp; 533 break; 534 535 case MEDIATYPE_VIDEO_REMOTE_RTP_INFO: 536 rtp_media = remoteMedia_.videoRtp; 537 break; 538 539 case MEDIATYPE_VIDEO_REMOTE_RTCP_INFO: 540 rtp_media = remoteMedia_.videoRtcp; 541 break; 542 543 default: 544 return false; 545 } 546 return true; 547 } 548 549 550 /* 551 * Stop the IPM streaming. 552 */ 553 bool IpmDevice::stopMedia( eIPM_STOP_OPERATION operation /* = STOP_ALL */ ) 554 { 555 if ( busy_ ) 556 { 557 pending_.push(IpmCommand(IpmCommand::STOP, operation)); 558 return true; 559 } 560 561 if ( state_ == IPM_IDLE ) 562 { 563 return true; /* Already stopped. */ 564 } 565 566 #if 0 567 IPM_SESSION_INFO session_info; 568 if ( ipm_GetSessionInfo(devHandle_, &session_info, EV_SYNC) == 0 ) 569 { 570 LOGINFO("IPM_SESSION_INFO: " << std::endl << session_info); 571 } 572 #endif 573 574 if ( ipm_Stop(devHandle_, operation, EV_ASYNC) == -1 ) 575 { 576 LOGERROR("ipm_Stop() on device: " << getDeviceName() << " failed: " << 577 ATDV_LASTERR(devHandle_)); 578 return false; 579 } 580 581 LOGDEBUG("IpmDevice::stopMedia() stopping RTP streaming on device: " << 582 getDeviceName()); 583 584 state_ = IPM_STOPPING; 585 busy_ = true; 586 587 return true; 588 } 589 590 591 /* 592 * Start RTP streaming to peer using the current settings. 593 */ 594 bool IpmDevice::startMedia() 595 { 596 return startMedia(remoteMedia_.audioRtp, 597 remoteMedia_.audioRtcp, 598 remoteMedia_.videoRtp, 599 remoteMedia_.videoRtcp); 600 } 601 602 603 /* 604 * Start RTP streaming: audio and video. 605 */ 606 bool IpmDevice::startMedia( const RtpIpInfo& remote_audio_rtp, 607 const RtpIpInfo& remote_audio_rtcp, 608 const RtpIpInfo& remote_video_rtp, 609 const RtpIpInfo& remote_video_rtcp ) 610 { 611 if ( busy_ ) 612 { 613 pending_.push(IpmCommand(IpmCommand::START)); 614 return true; 615 } 616 617 if ( (state_ == IPM_STARTING) || (state_ == IPM_STREAMING) ) 618 { 619 /* Already started, ignore. */ 620 LOGDEBUG("IpmDevice::startMedia() already streaming on device: " << 621 getDeviceName()); 622 return true; 623 } 624 625 if ( ipt_ ) 626 { 627 setDtmfMode(dtmfMode_); 628 } 629 630 IPM_MEDIA_INFO mediaInfo; 631 memset(&mediaInfo, 0, sizeof(IPM_MEDIA_INFO)); 632 633 int mediaCnt = 0; /* Limit is MAX_MEDIA_INFO */ 634 635 /* Local audio. 636 */ 637 if ( !localMedia_.audioCoder.encoding.empty() ) 638 { 639 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_LOCAL_CODER_INFO; 640 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eCoderType = localMedia_.audioCoder.coderType; 641 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eFrameSize = localMedia_.audioCoder.coderFramesize; 642 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unFramesPerPkt = localMedia_.audioCoder.framesPerPkt; 643 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eVadEnable = localMedia_.audioCoder.vadEnable; 644 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unCoderPayloadType = localMedia_.audioCoder.coderPayloadType; 645 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unRedPayloadType = localMedia_.audioCoder.redPayloadType; 646 mediaCnt++; 647 648 if ( localMedia_.audioCoder.coderType == CODER_TYPE_AMRNB_12_2k ) 649 { 650 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_LOCAL_CODER_OPTIONS_INFO; 651 mediaInfo.MediaData[mediaCnt].mediaInfo.AudioCoderOptionsInfo.unVersion = IPM_AUDIO_CODER_OPTIONS_INFO_VERSION; 652 mediaInfo.MediaData[mediaCnt].mediaInfo.AudioCoderOptionsInfo.unCoderOptions = CODER_OPT_AMR_CMR_TRACK | CODER_OPT_AMR_OCTET; 653 mediaCnt++; 654 } 655 } 656 657 /* Remote audio. 658 */ 659 if ( !remoteMedia_.audioCoder.encoding.empty() ) 660 { 661 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_CODER_INFO; 662 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eCoderType = remoteMedia_.audioCoder.coderType; 663 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eFrameSize = remoteMedia_.audioCoder.coderFramesize; 664 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unFramesPerPkt = remoteMedia_.audioCoder.framesPerPkt; 665 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eVadEnable = remoteMedia_.audioCoder.vadEnable; 666 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unCoderPayloadType = remoteMedia_.audioCoder.coderPayloadType; 667 mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unRedPayloadType = remoteMedia_.audioCoder.redPayloadType; 668 mediaCnt++; 669 670 if ( remoteMedia_.audioCoder.coderType == CODER_TYPE_AMRNB_12_2k ) 671 { 672 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_CODER_OPTIONS_INFO; 673 mediaInfo.MediaData[mediaCnt].mediaInfo.AudioCoderOptionsInfo.unVersion = IPM_AUDIO_CODER_OPTIONS_INFO_VERSION; 674 mediaInfo.MediaData[mediaCnt].mediaInfo.AudioCoderOptionsInfo.unCoderOptions = CODER_OPT_AMR_CMR_TRACK | CODER_OPT_AMR_OCTET; 675 mediaCnt++; 676 } 677 678 /* Remote audio ports and IP addresses. 679 */ 680 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_RTP_INFO; 681 copy_string_to_c_array(remote_audio_rtp.getAddress(), 682 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, 683 IP_ADDR_SIZE); 684 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_audio_rtp.getPort(); 685 mediaCnt++; 686 687 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_RTCP_INFO; 688 copy_string_to_c_array(remote_audio_rtcp.getAddress(), 689 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, 690 IP_ADDR_SIZE); 691 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_audio_rtcp.getPort(); 692 mediaCnt++; 693 } 694 695 /* Local video. 696 */ 697 IPM_VIDEO_CODER_INFO_EX localVideoCoderInfoEx; 698 INIT_IPM_VIDEO_CODER_INFO_EX(&localVideoCoderInfoEx); 699 700 std::vector<unsigned char> localVisualConfig; /* Copy for passing to api.*/ 701 702 if ( !localMedia_.videoCoder.encoding.empty() ) 703 { 704 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_VIDEO_LOCAL_CODER_INFO; 705 INIT_IPM_VIDEO_CODER_INFO(&mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo); 706 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.eCoderType = localMedia_.videoCoder.coderType; 707 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.unCoderPayloadType = localMedia_.videoCoder.coderPayloadType; 708 709 localVideoCoderInfoEx.eProfile = localMedia_.videoCoder.active_fmt.profile; 710 localVideoCoderInfoEx.eLevel = localMedia_.videoCoder.active_fmt.level; 711 localVideoCoderInfoEx.eImageWidth = localMedia_.videoCoder.active_fmt.imageWidth; 712 localVideoCoderInfoEx.eImageHeight = localMedia_.videoCoder.active_fmt.imageHeight; 713 localVideoCoderInfoEx.eFramesPerSec = localMedia_.videoCoder.active_fmt.framesPerSec; 714 localVideoCoderInfoEx.unBitRate = localMedia_.videoCoder.active_fmt.bitRate; 715 localVideoCoderInfoEx.eSamplingRate = localMedia_.videoCoder.samplingRate; 716 if ( !localMedia_.videoCoder.active_fmt.visualConfiguration.empty() ) 717 { 718 localVisualConfig.assign(localMedia_.videoCoder.active_fmt.visualConfiguration.begin(), 719 localMedia_.videoCoder.active_fmt.visualConfiguration.end()); 720 localVideoCoderInfoEx.unVisualConfigSize = localVisualConfig.size(); 721 localVideoCoderInfoEx.szVisualConfiguration = &localVisualConfig[0]; 722 } 723 else 724 { 725 localVideoCoderInfoEx.unVisualConfigSize = 0; 726 localVideoCoderInfoEx.szVisualConfiguration = NULL; 727 } 728 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.pExtraCoderInfo = &localVideoCoderInfoEx; 729 #if 1 730 LOGDEBUG("IpmDevice::startMedia() Local VideoCoderInfo: " << std::endl << 731 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo); 732 #endif 733 mediaCnt++; 734 } 735 736 /* Remote video. 737 */ 738 IPM_VIDEO_CODER_INFO_EX remoteVideoCoderInfoEx; 739 INIT_IPM_VIDEO_CODER_INFO_EX(&remoteVideoCoderInfoEx); 740 741 std::vector<unsigned char> remoteVisualConfig; /* Copy for passing to api.*/ 742 743 if ( !remoteMedia_.videoCoder.encoding.empty() ) 744 { 745 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_VIDEO_REMOTE_CODER_INFO; 746 INIT_IPM_VIDEO_CODER_INFO(&mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo); 747 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.eCoderType = remoteMedia_.videoCoder.coderType; 748 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.unCoderPayloadType = remoteMedia_.videoCoder.coderPayloadType; 749 750 remoteVideoCoderInfoEx.eProfile = remoteMedia_.videoCoder.active_fmt.profile; 751 remoteVideoCoderInfoEx.eLevel = remoteMedia_.videoCoder.active_fmt.level; 752 remoteVideoCoderInfoEx.eImageWidth = remoteMedia_.videoCoder.active_fmt.imageWidth; 753 remoteVideoCoderInfoEx.eImageHeight = remoteMedia_.videoCoder.active_fmt.imageHeight; 754 remoteVideoCoderInfoEx.eFramesPerSec = remoteMedia_.videoCoder.active_fmt.framesPerSec; 755 remoteVideoCoderInfoEx.unBitRate = remoteMedia_.videoCoder.active_fmt.bitRate; 756 remoteVideoCoderInfoEx.eSamplingRate = remoteMedia_.videoCoder.samplingRate; 757 if ( !remoteMedia_.videoCoder.active_fmt.visualConfiguration.empty() ) 758 { 759 remoteVisualConfig.assign(remoteMedia_.videoCoder.active_fmt.visualConfiguration.begin(), 760 remoteMedia_.videoCoder.active_fmt.visualConfiguration.end()); 761 remoteVideoCoderInfoEx.unVisualConfigSize = remoteVisualConfig.size(); 762 remoteVideoCoderInfoEx.szVisualConfiguration = &remoteVisualConfig[0]; 763 } 764 else 765 { 766 remoteVideoCoderInfoEx.unVisualConfigSize = 0; 767 remoteVideoCoderInfoEx.szVisualConfiguration = NULL; 768 } 769 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo.pExtraCoderInfo = &remoteVideoCoderInfoEx; 770 #if 1 771 LOGDEBUG("IpmDevice::startMedia() Remote VideoCoderInfo: " << std::endl << 772 mediaInfo.MediaData[mediaCnt].mediaInfo.VideoCoderInfo); 773 #endif 774 775 mediaCnt++; 776 777 /* Remote video ports and IP addresses. 778 */ 779 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_VIDEO_REMOTE_RTP_INFO; 780 copy_string_to_c_array(remote_video_rtp.getAddress(), 781 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, 782 IP_ADDR_SIZE); 783 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_video_rtp.getPort(); 784 mediaCnt++; 785 786 mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_VIDEO_REMOTE_RTCP_INFO; 787 copy_string_to_c_array(remote_video_rtcp.getAddress(), 788 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, 789 IP_ADDR_SIZE); 790 mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_video_rtcp.getPort(); 791 mediaCnt++; 792 } 793 794 if ( mediaCnt == 0 ) 795 { 796 LOGERROR("IpmDevice::startMedia() no media for device: " << getDeviceName()); 797 return false; 798 } 799 mediaInfo.unCount = mediaCnt; 800 801 /* Use the remote rtp's direction to control whether or not media 802 * should be transmitted. 803 */ 804 eIPM_DATA_DIRECTION audio_direction; 805 eIPM_DATA_DIRECTION video_direction; 806 807 if ( remote_audio_rtp.getDirection() == RtpIpInfo::INACTIVE ) 808 { 809 audio_direction = DATA_IP_INACTIVE; 810 } 811 else if ( remote_audio_rtp.getDirection() == RtpIpInfo::SENDONLY ) 812 { 813 audio_direction = DATA_IP_RECEIVEONLY; 814 } 815 else if ( remote_audio_rtp.getDirection() == RtpIpInfo::RECVONLY ) 816 { 817 audio_direction = DATA_IP_SENDONLY; 818 } 819 else /* RtpIpInfo::SENDRECV */ 820 { 821 audio_direction = DATA_IP_TDM_BIDIRECTIONAL; 822 } 823 824 if ( remote_video_rtp.getDirection() == RtpIpInfo::INACTIVE ) 825 { 826 video_direction = DATA_IP_INACTIVE; 827 } 828 else if ( remote_video_rtp.getDirection() == RtpIpInfo::SENDONLY ) 829 { 830 video_direction = DATA_IP_RECEIVEONLY; 831 } 832 else if ( remote_video_rtp.getDirection() == RtpIpInfo::RECVONLY ) 833 { 834 video_direction = DATA_IP_SENDONLY; 835 } 836 else /* RtpIpInfo::SENDRECV */ 837 { 838 video_direction = DATA_IP_TDM_BIDIRECTIONAL; 839 } 840 841 eIPM_DATA_DIRECTION direction = DATA_IP_TDM_BIDIRECTIONAL; 842 if ( (audio_direction == DATA_IP_INACTIVE) && (video_direction == DATA_IP_INACTIVE) ) 843 { 844 LOGDEBUG("IpmDevice::startMedia() DATA_IP_INACTIVE for device: " << 845 getDeviceName()); 846 direction = DATA_IP_INACTIVE; 847 } 848 else if ( (audio_direction == DATA_IP_RECEIVEONLY) && (video_direction == DATA_IP_RECEIVEONLY) ) 849 { 850 LOGDEBUG("IpmDevice::startMedia() DATA_IP_RECEIVEONLY for device: " << 851 getDeviceName()); 852 direction = DATA_IP_RECEIVEONLY; 853 } 854 else 855 { 856 LOGDEBUG("IpmDevice::startMedia() DATA_IP_TDM_BIDIRECTIONAL for device: " << 857 getDeviceName()); 858 } 859 860 /* Start streaming... 861 */ 862 if ( remote_audio_rtp.isValid() ) 863 { 864 LOGDEBUG("IpmDevice::startMedia() starting audio on device: " << 865 getDeviceName() << 866 " remote_rtp: " << remote_audio_rtp << 867 " remote_rtcp: " << remote_audio_rtcp); 868 } 869 if ( remote_video_rtp.isValid() ) 870 { 871 LOGDEBUG("IpmDevice::startMedia() starting video on device: " << 872 getDeviceName() << 873 " remote_rtp: " << remote_video_rtp << 874 " remote_rtcp: " << remote_video_rtcp); 875 } 876 877 if ( ipm_StartMedia(devHandle_, &mediaInfo, direction, EV_ASYNC) == -1 ) 878 { 879 LOGERROR("ipm_StartMedia failed for device: " << getDeviceName() << 880 " with error: " << ATDV_ERRMSGP(devHandle_)); 881 return false; 882 } 883 884 state_ = IPM_STARTING; 885 busy_ = true; 886 887 return true; 888 } 889 890 891 /* 892 * Set the dtmf signalling mode. 893 */ 894 void IpmDevice::setDtmfMode( DtmfMode dtmf_mode ) 895 { 896 IPM_PARM_INFO parmInfo; 897 898 switch ( dtmf_mode ) 899 { 900 case DTMF_RFC2833: 901 { 902 eIPM_DTMFXFERMODE value = DTMFXFERMODE_RFC2833; 903 parmInfo.eParm = PARMCH_DTMFXFERMODE; 904 parmInfo.pvParmValue = &value; 905 LOGDEBUG("IpmDevice::setDtmfMode() using RFC2833"); 906 if ( ipm_SetParm(devHandle_, &parmInfo, EV_SYNC) < 0 ) 907 { 908 LOGERROR("ipm_SetParm() DTMFXFERMODE_RFC2833"); 909 } 910 911 parmInfo.eParm = PARMCH_RFC2833EVT_TX_PLT; 912 parmInfo.pvParmValue = &rfc2833PayloadType_; 913 if ( ipm_SetParm(devHandle_, &parmInfo, EV_SYNC) < 0 ) 914 { 915 LOGERROR("ipm_SetParm() PARMCH_RFC2833EVT_TX_PLT " << rfc2833PayloadType_); 916 } 917 918 parmInfo.eParm = PARMCH_RFC2833EVT_RX_PLT; 919 parmInfo.pvParmValue = &rfc2833PayloadType_; 920 if ( ipm_SetParm(devHandle_, &parmInfo, EV_SYNC) < 0 ) 921 { 922 LOGERROR("ipm_SetParm() PARMCH_RFC2833EVT_RX_PLT " << rfc2833PayloadType_); 923 } 924 } 925 break; 926 927 case DTMF_SIPINFO: 928 LOGDEBUG("IpmDevice::setDtmfMode() using SIPINFO"); 929 break; 930 931 case DTMF_INBAND: 932 { 933 eIPM_DTMFXFERMODE value = DTMFXFERMODE_INBAND; 934 parmInfo.eParm = PARMCH_DTMFXFERMODE; 935 parmInfo.pvParmValue = &value; 936 937 LOGDEBUG("IpmDevice::setDtmfMode() using inband audio"); 938 if ( ipm_SetParm(devHandle_, &parmInfo, EV_SYNC) < 0 ) 939 { 940 LOGERROR("ipm_SetParm() DTMFXFERMODE_INBAND"); 941 } 942 } 943 break; 944 } 945 } 946 947 948 /* 949 * Add the overlay to media stream. 950 */ 951 bool IpmDevice::addOverlay( OverlayInfo* overlayInfo ) 952 { 953 if ( other_video_ && (videoConnectFlags_ != DMFL_TRANSCODE_ON) ) 954 { 955 LOGWARN("IpmDevice::addOverlay() can not add overlay as transcoding is not active for device: " << getDeviceName()); 956 return false; 957 } 958 959 removeOverlay(); 960 961 if ( busy_ ) 962 { 963 pending_.push(IpmCommand(IpmCommand::ADD_OVERLAY, overlayInfo)); 964 return true; 965 } 966 967 if ( !overlay_ ) 968 { 969 overlay_ = new Overlay; /* Will exist until this object is deleted. */ 970 } 971 972 LOGDEBUG("IpmDevice::addOverlay() for device: " << getDeviceName()); 973 974 eSM_OVERLAY_DIRECTION direction = overlayInfo->direction; 975 overlay_->createOverlay(*overlayInfo); 976 delete overlayInfo; 977 978 if ( !overlay_->addOverlay(getDeviceHandle(), direction) ) 979 { 980 LOGERROR("IpmDevice::addOverlay() failed for device: " << getDeviceName()); 981 return false; 982 } 983 overlayActive_ = true; 984 busy_ = true; 985 986 return true; 987 } 988 989 990 /* 991 * Add the overlay to media stream. 992 */ 993 bool IpmDevice::removeOverlay() 994 { 995 if ( busy_ ) 996 { 997 pending_.push(IpmCommand(IpmCommand::REMOVE_OVERLAY)); 998 return true; 999 } 1000 1001 if ( !overlay_ || !overlayActive_ ) 1002 { 1003 return false; 1004 } 1005 1006 LOGDEBUG("IpmDevice::removeOverlay() for device: " << getDeviceName()); 1007 1008 if ( !overlay_->removeOverlay(getDeviceHandle()) ) 1009 { 1010 LOGERROR("IpmDevice::removeOverlay() failed for device: " << getDeviceName()); 1011 return false; 1012 } 1013 busy_ = true; 1014 return true; 1015 } 1016 1017 1018 /* 1019 * Generate an I-frame. Transcoding must be active. 1020 */ 1021 bool IpmDevice::generateIFrame( bool force ) 1022 { 1023 if ( busy_ ) 1024 { 1025 pending_.push(IpmCommand(IpmCommand::GENERATE_IFRAME, force)); 1026 return true; 1027 } 1028 1029 if ( force || (other_video_ && (videoConnectFlags_ == DMFL_TRANSCODE_ON)) ) 1030 { 1031 IFRAME_INFO iframeInfo; 1032 INIT_IFRAME_INFO(&iframeInfo); 1033 1034 if ( ipm_GenerateIFrame(devHandle_, &iframeInfo, EV_ASYNC) == -1 ) 1035 { 1036 LOGERROR("IpmDevice::generateIFrame() ipm_GenerateIFrame failed for device: " << getDeviceName() << 1037 " with error: " << ATDV_ERRMSGP(devHandle_)); 1038 return false; 1039 } 1040 busy_ = true; 1041 LOGDEBUG("IpmDevice::generateIFrame() for device: " << getDeviceName()); 1042 } 1043 return true; 1044 } 1045 1046 1047 /* 1048 * Convert a minimum-picture-interval to frames-per-second. 1049 * RFC4629: fps = 30 / (1.001 * the specified value). 1050 */ 1051 eVIDEO_FRAMESPERSEC IpmDevice::mpi2fps( int mpi ) 1052 { 1053 eVIDEO_FRAMESPERSEC fps; 1054 switch ( mpi ) 1055 { 1056 case 1: 1057 fps = VIDEO_FRAMESPERSEC_2997; 1058 break; 1059 1060 case 2: 1061 fps = VIDEO_FRAMESPERSEC_15; 1062 break; 1063 1064 case 3: 1065 fps = VIDEO_FRAMESPERSEC_10; 1066 break; 1067 1068 case 5: 1069 fps = VIDEO_FRAMESPERSEC_6; 1070 break; 1071 1072 default: 1073 fps = VIDEO_FRAMESPERSEC_DEFAULT; 1074 break; 1075 } 1076 return fps; 1077 } 1078 1079 1080 /* 1081 * Convert frames-per-second to a minimum-picture-interval. 1082 * RFC4629: fps = 30 / (1.001 * the specified value). 1083 */ 1084 int IpmDevice::fps2mpi( eVIDEO_FRAMESPERSEC fps ) 1085 { 1086 int mpi; 1087 switch ( fps ) 1088 { 1089 case VIDEO_FRAMESPERSEC_6: 1090 mpi = 5; 1091 break; 1092 1093 case VIDEO_FRAMESPERSEC_10: 1094 mpi = 3; 1095 break; 1096 1097 case VIDEO_FRAMESPERSEC_2997: 1098 case VIDEO_FRAMESPERSEC_30: 1099 mpi = 1; 1100 break; 1101 1102 default: /* 15 fps */ 1103 mpi = 2; 1104 break; 1105 } 1106 return mpi; 1107 } 1108 1109 1110 /* 1111 * Offer sdpS contain all available codecs. 1112 */ 1113 void IpmDevice::buildOfferSdp( SdpSessionDescription& sdp_desc ) 1114 { 1115 const Coders::audio_coders_t& local_audio_coders = ipt_->getAudioCoders(); 1116 const Coders::video_coders_t& local_video_coders = ipt_->getVideoCoders(); 1117 1118 RtpIpInfo local_rtp_audio; 1119 getLocalMediaInfo(MEDIATYPE_AUDIO_LOCAL_RTP_INFO, local_rtp_audio); 1120 1121 RtpIpInfo local_rtp_video; 1122 getLocalMediaInfo(MEDIATYPE_VIDEO_LOCAL_RTP_INFO, local_rtp_video); 1123 1124 /* v= */ 1125 sdp_desc.version()->setVersion("0"); 1126 1127 /* o= */ 1128 sdp_desc.origin()->setUserName("DiaStarServer"); 1129 sdp_desc.origin()->setSessionId(localMedia_.origin.sess_id.c_str()); 1130 1131 std::stringstream ss; 1132 ss << (atoi(localMedia_.origin.sess_version.c_str()) + 1); 1133 localMedia_.origin.sess_version = ss.str(); 1134 sdp_desc.origin()->setVersion(localMedia_.origin.sess_version.c_str()); 1135 1136 sdp_desc.origin()->setNetworkType("IN"); 1137 sdp_desc.origin()->setAddressType("IP4"); 1138 if ( sdp_address_.empty() ) 1139 { 1140 sdp_desc.origin()->setAddress(local_rtp_audio.getAddress().c_str()); 1141 } 1142 else 1143 { 1144 sdp_desc.origin()->setAddress(sdp_address_.c_str()); 1145 } 1146 1147 /* c= Common for all media. */ 1148 sdp_desc.connection()->setNetworkType("IN"); 1149 sdp_desc.connection()->setAddressType("IP4"); 1150 if ( sdp_address_.empty() ) 1151 { 1152 sdp_desc.connection()->setAddress(local_rtp_audio.getAddress().c_str()); 1153 } 1154 else 1155 { 1156 sdp_desc.connection()->setAddress(sdp_address_.c_str()); 1157 } 1158 1159 /* s= */ 1160 sdp_desc.sessionName()->setName("diastar"); 1161 1162 /* t= */ 1163 SdpTimeDescription* time_description = sdp_desc.timeDescriptionList()->addItem(); 1164 time_description->time()->setStart(0); 1165 time_description->time()->setStop(0); 1166 1167 /* media 1168 */ 1169 SdpMediaDescriptionList* media_desc_list = sdp_desc.mediaDescriptionList(); 1170 media_desc_list->clear(); 1171 1172 /* m=audio 1173 */ 1174 if ( local_audio_coders.size() > 0 ) 1175 { 1176 SdpMediaDescription* sdp_media_desc = media_desc_list->addItem(); 1177 SdpMedia* sdp_media = sdp_media_desc->media(); 1178 sdp_media->setMedia("audio"); 1179 sdp_media->setPort(local_rtp_audio.getPort()); 1180 sdp_media->setTransport("RTP/AVP"); 1181 sdp_media->setNumPorts(1); 1182 1183 SdpAttributeList* audio_attr_list = sdp_media_desc->attributeList(); 1184 1185 Coders::audio_coders_t::const_iterator i; 1186 for ( i = local_audio_coders.begin(); i != local_audio_coders.end(); ++i ) 1187 { 1188 const AudioCoderInfo& audio_coder_info = *i; 1189 1190 std::stringstream payload; 1191 payload << audio_coder_info.coderPayloadType;; 1192 sdp_media->addFormat(payload.str().c_str()); 1193 1194 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1195 audio_attribute->setProperty("rtpmap"); 1196 std::stringstream rtpmap; 1197 rtpmap << audio_coder_info.coderPayloadType << " "; 1198 rtpmap << audio_coder_info.encoding << '/' << audio_coder_info.clockRate; 1199 audio_attribute->setPropertyValue(rtpmap.str().c_str()); 1200 1201 if ( audio_coder_info.coderType == CODER_TYPE_G729ANNEXA ) 1202 { 1203 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1204 audio_attribute->setProperty("fmtp"); 1205 std::string fmtp = payload.str() + " annexb=no"; 1206 audio_attribute->setPropertyValue(fmtp.c_str()); 1207 } 1208 else if ( (audio_coder_info.coderType == CODER_TYPE_AMRNB_12_2k) || 1209 (audio_coder_info.coderType == CODER_TYPE_AMRWB_6_6K) ) 1210 { 1211 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1212 audio_attribute->setProperty("fmtp"); 1213 std::string fmtp = payload.str() + " octet-align="; 1214 if ( audio_coder_info.coderOptions & CODER_OPT_AMR_OCTET ) 1215 { 1216 fmtp += "1"; 1217 } 1218 else 1219 { 1220 fmtp += "0"; 1221 } 1222 audio_attribute->setPropertyValue(fmtp.c_str()); 1223 } 1224 } 1225 1226 if ( dtmfMode_ == DTMF_RFC2833 ) 1227 { 1228 rfc2833PayloadType_ = DEFAULT_RFC2833_PAYLOAD_TYPE; 1229 1230 std::stringstream payload; 1231 payload << rfc2833PayloadType_; 1232 sdp_media->addFormat(payload.str().c_str()); 1233 1234 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1235 audio_attribute->setProperty("rtpmap"); 1236 std::string rtpmap = payload.str() + " telephone-event/8000"; 1237 audio_attribute->setPropertyValue(rtpmap.c_str()); 1238 1239 /* 0-15 => 0123456789*#ABCD. 1240 * See also: IpmDevice::onTelephonyEvent(). 1241 */ 1242 audio_attribute = audio_attr_list->addItem(); 1243 audio_attribute->setProperty("fmtp"); 1244 std::string fmtp = payload.str() + " 0-15"; 1245 audio_attribute->setPropertyValue(fmtp.c_str()); 1246 } 1247 1248 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1249 audio_attribute->setProperty("sendrecv"); 1250 audio_attribute->setPropertyValue(""); 1251 } 1252 1253 /* m=video 1254 */ 1255 if ( local_video_coders.size() > 0 ) 1256 { 1257 unsigned int max_bit_rate = 0; 1258 1259 if ( local_rtp_video.isValid() ) 1260 { 1261 SdpMediaDescription* sdp_media_desc = media_desc_list->addItem(); 1262 SdpMedia* sdp_media = sdp_media_desc->media(); 1263 sdp_media->setMedia("video"); 1264 sdp_media->setPort(local_rtp_video.getPort()); 1265 sdp_media->setTransport("RTP/AVP"); 1266 sdp_media->setNumPorts(1); 1267 1268 SdpAttributeList* video_attr_list = sdp_media_desc->attributeList(); 1269 1270 Coders::video_coders_t::const_iterator i; 1271 for ( i = local_video_coders.begin(); i != local_video_coders.end(); ++i ) 1272 { 1273 const VideoCoderInfo& video_coder_info = *i; 1274 1275 std::stringstream payload; 1276 payload << video_coder_info.coderPayloadType; 1277 sdp_media->addFormat(payload.str().c_str()); 1278 1279 SdpAttribute* video_attribute = video_attr_list->addItem(); 1280 video_attribute->setProperty("rtpmap"); 1281 std::stringstream rtpmap; 1282 rtpmap << video_coder_info.coderPayloadType << " "; 1283 rtpmap << video_coder_info.encoding << '/' << 90000; 1284 video_attribute->setPropertyValue(rtpmap.str().c_str()); 1285 1286 if ( (video_coder_info.coderType == CODER_TYPE_H263) || 1287 (video_coder_info.coderType == CODER_TYPE_H263_1998) ) 1288 { 1289 SdpAttribute* video_attribute = video_attr_list->addItem(); 1290 video_attribute->setProperty("fmtp"); 1291 std::stringstream fmtp; 1292 fmtp << video_coder_info.coderPayloadType << " "; 1293 std::vector<VideoCoderInfo::Fmt>::const_iterator j = video_coder_info.available_fmts.begin(); 1294 while ( j != video_coder_info.available_fmts.end() ) 1295 { 1296 if ( ((*j).imageWidth == VIDEO_IMAGE_WIDTH_352) && 1297 ((*j).imageHeight == VIDEO_IMAGE_HEIGHT_288) ) 1298 { 1299 fmtp << "CIF="; 1300 } 1301 else if ( ((*j).imageWidth == VIDEO_IMAGE_WIDTH_176) && 1302 ((*j).imageHeight == VIDEO_IMAGE_HEIGHT_144) ) 1303 { 1304 fmtp << "QCIF="; 1305 } 1306 else 1307 { 1308 ; 1309 } 1310 fmtp << fps2mpi((*j).framesPerSec); 1311 if ( ++j != video_coder_info.available_fmts.end() ) 1312 { 1313 fmtp << "; "; 1314 } 1315 } 1316 video_attribute->setPropertyValue(fmtp.str().c_str()); 1317 } 1318 else if ( video_coder_info.coderType == CODER_TYPE_MP4V_ES ) 1319 { 1320 SdpAttribute* video_attribute = video_attr_list->addItem(); 1321 video_attribute->setProperty("fmtp"); 1322 std::stringstream fmtp; 1323 fmtp << video_coder_info.coderPayloadType << " profile-level-id="; 1324 if ( video_coder_info.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP0_MPEG4 ) 1325 { 1326 fmtp << "0"; 1327 } 1328 else if ( video_coder_info.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP1_MPEG4 ) 1329 { 1330 fmtp << "1"; 1331 } 1332 else if ( video_coder_info.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP2_MPEG4 ) 1333 { 1334 fmtp << "2"; 1335 } 1336 else if ( video_coder_info.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP3_MPEG4 ) 1337 { 1338 fmtp << "3"; 1339 } 1340 fmtp << " MaxBR=" << video_coder_info.active_fmt.bitRate / 100; 1341 video_attribute->setPropertyValue(fmtp.str().c_str()); 1342 } 1343 else if ( video_coder_info.coderType == CODER_TYPE_H264 ) 1344 { 1345 SdpAttribute* video_attribute = video_attr_list->addItem(); 1346 video_attribute->setProperty("fmtp"); 1347 std::stringstream fmtp; 1348 fmtp << video_coder_info.coderPayloadType; 1349 fmtp << " profile-level-id="; 1350 if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_1_H264 ) 1351 { 1352 fmtp << "42000A"; 1353 } 1354 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_1_B_H264 ) 1355 { 1356 fmtp << "42100B"; 1357 } 1358 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_1_1_H264 ) 1359 { 1360 fmtp << "42000B"; 1361 } 1362 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_1_2_H264 ) 1363 { 1364 fmtp << "42000C"; 1365 } 1366 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_1_3_H264 ) 1367 { 1368 fmtp << "42000D"; 1369 } 1370 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_2_0_H264 ) 1371 { 1372 fmtp << "420014"; 1373 } 1374 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_2_1_H264 ) 1375 { 1376 fmtp << "420015"; 1377 } 1378 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_2_2_H264 ) 1379 { 1380 fmtp << "420016"; 1381 } 1382 else if ( video_coder_info.active_fmt.level == VIDEO_LEVEL_3_0_H264 ) 1383 { 1384 fmtp << "42001E"; 1385 } 1386 else /* VIDEO_LEVEL_3_1_H264 */ 1387 { 1388 fmtp << "42001F"; 1389 } 1390 fmtp << "; packetization-mode=" << video_coder_info.packetizationMode; 1391 fmtp << "; max-br=" << video_coder_info.active_fmt.bitRate / 1000; 1392 video_attribute->setPropertyValue(fmtp.str().c_str()); 1393 } 1394 1395 if ( max_bit_rate < video_coder_info.active_fmt.bitRate ) 1396 { 1397 max_bit_rate = video_coder_info.active_fmt.bitRate; 1398 } 1399 } 1400 1401 SdpAttribute* video_attribute = video_attr_list->addItem(); 1402 video_attribute->setProperty("sendrecv"); 1403 video_attribute->setPropertyValue(""); 1404 1405 std::stringstream bandwidth; 1406 bandwidth << max_bit_rate / 1000; 1407 sdp_media_desc->bandwidth()->setModifier("AS"); 1408 sdp_media_desc->bandwidth()->setBandwidthValue(bandwidth.str().c_str()); 1409 } 1410 } 1411 } 1412 1413 1414 /* 1415 * RFC 3264 section 6: 1416 * For each "m=" line in the offer, there MUST be a corresponding "m=" 1417 * line in the answer. The answer MUST contain exactly the same number 1418 * of "m=" lines as the offer. 1419 * 1420 * "m=" lines with no supported formats have their port set to 0. 1421 */ 1422 void IpmDevice::buildAnswerSdp( SdpSessionDescription& sdp_desc ) 1423 { 1424 const Coders::audio_coders_t& local_audio_coders = ipt_->getAudioCoders(); 1425 const Coders::video_coders_t& local_video_coders = ipt_->getVideoCoders(); 1426 1427 RtpIpInfo local_rtp_audio; 1428 getLocalMediaInfo(MEDIATYPE_AUDIO_LOCAL_RTP_INFO, local_rtp_audio); 1429 1430 RtpIpInfo local_rtp_video; 1431 getLocalMediaInfo(MEDIATYPE_VIDEO_LOCAL_RTP_INFO, local_rtp_video); 1432 1433 /* v= */ 1434 sdp_desc.version()->setVersion("0"); 1435 1436 /* o= */ 1437 sdp_desc.origin()->setUserName("DiaStarServer"); 1438 sdp_desc.origin()->setSessionId(localMedia_.origin.sess_id.c_str()); 1439 1440 std::stringstream ss; 1441 ss << (atoi(localMedia_.origin.sess_version.c_str()) + 1); 1442 localMedia_.origin.sess_version = ss.str(); 1443 sdp_desc.origin()->setVersion(localMedia_.origin.sess_version.c_str()); 1444 1445 sdp_desc.origin()->setNetworkType("IN"); 1446 sdp_desc.origin()->setAddressType("IP4"); 1447 if ( sdp_address_.empty() ) 1448 { 1449 sdp_desc.origin()->setAddress(local_rtp_audio.getAddress().c_str()); 1450 } 1451 else 1452 { 1453 sdp_desc.origin()->setAddress(sdp_address_.c_str()); 1454 } 1455 1456 /* c= Common for all media. */ 1457 sdp_desc.connection()->setNetworkType("IN"); 1458 sdp_desc.connection()->setAddressType("IP4"); 1459 if ( sdp_address_.empty() ) 1460 { 1461 sdp_desc.connection()->setAddress(local_rtp_audio.getAddress().c_str()); 1462 } 1463 else 1464 { 1465 sdp_desc.connection()->setAddress(sdp_address_.c_str()); 1466 } 1467 1468 /* s= */ 1469 sdp_desc.sessionName()->setName("diastar"); 1470 1471 /* t= */ 1472 SdpTimeDescription* time_description = sdp_desc.timeDescriptionList()->addItem(); 1473 time_description->time()->setStart(0); 1474 time_description->time()->setStop(0); 1475 1476 /* 1477 * Media lines. 1478 */ 1479 SdpMediaDescriptionList* media_desc_list = sdp_desc.mediaDescriptionList(); 1480 media_desc_list->clear(); 1481 1482 SdpMediaDescription* sdp_media_desc = 0; 1483 SdpMedia* sdp_media = 0; 1484 int mline = -1; 1485 Offer::media_t::const_iterator i; 1486 for ( i = offer_.media.begin(); i != offer_.media.end(); ++i ) 1487 { 1488 if ( mline != (*i).mline ) 1489 { 1490 mline = (*i).mline; 1491 1492 sdp_media_desc = media_desc_list->addItem(); 1493 sdp_media = sdp_media_desc->media(); 1494 sdp_media->setMedia((*i).type.c_str()); 1495 sdp_media->setTransport((*i).transport.c_str()); 1496 sdp_media->setNumPorts(1); 1497 } 1498 if ( (*i).type == "audio" ) 1499 { 1500 if ( (mline != offer_.chosen_audio_mline) && !((*i).rfc2833) ) 1501 { 1502 sdp_media->setPort(0); 1503 std::stringstream payload; 1504 payload << (*i).audioCoder.coderPayloadType; 1505 sdp_media->addFormat(payload.str().c_str()); 1506 } 1507 else /* Chosen codec or telephone-event. */ 1508 { 1509 sdp_media->setPort(local_rtp_audio.getPort()); 1510 1511 if ( (*i).audioCoder == remoteMedia_.audioCoder ) 1512 { 1513 SdpAttributeList* audio_attr_list = sdp_media_desc->attributeList(); 1514 1515 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1516 audio_attribute->setProperty("rtpmap"); 1517 1518 std::stringstream payload; 1519 payload << remoteMedia_.audioCoder.coderPayloadType;; 1520 sdp_media->addFormat(payload.str().c_str()); 1521 1522 std::stringstream rtpmap; 1523 rtpmap << remoteMedia_.audioCoder.coderPayloadType << " "; 1524 rtpmap << remoteMedia_.audioCoder.encoding << '/' << remoteMedia_.audioCoder.clockRate; 1525 audio_attribute->setPropertyValue(rtpmap.str().c_str()); 1526 1527 if ( remoteMedia_.audioCoder.coderType == CODER_TYPE_G729ANNEXA ) 1528 { 1529 audio_attribute = audio_attr_list->addItem(); 1530 audio_attribute->setProperty("fmtp"); 1531 std::string fmtp = payload.str() + " annexb=no"; 1532 audio_attribute->setPropertyValue(fmtp.c_str()); 1533 } 1534 else if ( remoteMedia_.audioCoder.coderType == CODER_TYPE_G729ANNEXAWANNEXB ) 1535 { 1536 audio_attribute = audio_attr_list->addItem(); 1537 audio_attribute->setProperty("fmtp"); 1538 std::string fmtp = payload.str() + " annexb=yes"; 1539 audio_attribute->setPropertyValue(fmtp.c_str()); 1540 } 1541 else if ( (remoteMedia_.audioCoder.coderType == CODER_TYPE_AMRNB_12_2k) || 1542 (remoteMedia_.audioCoder.coderType == CODER_TYPE_AMRWB_6_6K) ) 1543 { 1544 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1545 audio_attribute->setProperty("fmtp"); 1546 std::string fmtp = payload.str() + " octet-align="; 1547 if ( remoteMedia_.audioCoder.coderOptions & CODER_OPT_AMR_OCTET ) 1548 { 1549 fmtp += "1"; 1550 } 1551 else 1552 { 1553 fmtp += "0"; 1554 } 1555 audio_attribute->setPropertyValue(fmtp.c_str()); 1556 } 1557 audio_attribute = audio_attr_list->addItem(); 1558 audio_attribute->setProperty(localMedia_.audioRtp.getDirectionText().c_str()); 1559 audio_attribute->setPropertyValue(""); 1560 } 1561 if ( (*i).rfc2833 ) 1562 { 1563 if ( dtmfMode_ == DTMF_RFC2833 ) 1564 { 1565 /* Save the offered payload type as it may differ from 1566 * the local default. 1567 */ 1568 rfc2833PayloadType_ = (*i).audioCoder.coderPayloadType; 1569 1570 std::stringstream payload; 1571 payload << (*i).audioCoder.coderPayloadType; 1572 sdp_media->addFormat(payload.str().c_str()); 1573 1574 SdpAttributeList* audio_attr_list = sdp_media_desc->attributeList(); 1575 1576 SdpAttribute* audio_attribute = audio_attr_list->addItem(); 1577 audio_attribute->setProperty("rtpmap"); 1578 std::string rtpmap = payload.str() + " telephone-event/8000"; 1579 audio_attribute->setPropertyValue(rtpmap.c_str()); 1580 1581 /* 0-15 => 0123456789*#ABCD. 1582 * See also: IpmDevice::onTelephonyEvent(). 1583 */ 1584 audio_attribute = audio_attr_list->addItem(); 1585 audio_attribute->setProperty("fmtp"); 1586 std::string fmtp = payload.str() + " 0-15"; 1587 audio_attribute->setPropertyValue(fmtp.c_str()); 1588 } 1589 else /* rfc2833 denied. */ 1590 { 1591 if ( mline != offer_.chosen_audio_mline ) 1592 { 1593 sdp_media->setPort(0); 1594 std::stringstream payload; 1595 payload << remoteMedia_.audioCoder.coderPayloadType; 1596 sdp_media->addFormat(payload.str().c_str()); 1597 } 1598 } 1599 } 1600 } 1601 } 1602 else if ( (*i).type == "video" ) 1603 { 1604 if ( mline != offer_.chosen_video_mline ) 1605 { 1606 sdp_media->setPort(0); 1607 std::stringstream payload; 1608 payload << (*i).videoCoder.coderPayloadType; 1609 sdp_media->addFormat(payload.str().c_str()); 1610 } 1611 else /* Chosen codec. */ 1612 { 1613 sdp_media->setPort(local_rtp_video.getPort()); 1614 1615 if ( (*i).videoCoder.coderPayloadType == remoteMedia_.videoCoder.coderPayloadType ) 1616 { 1617 unsigned int max_bit_rate; 1618 if ( remoteMedia_.videoCoder.maxBitRate < remoteMedia_.videoCoder.active_fmt.bitRate ) 1619 { 1620 max_bit_rate = remoteMedia_.videoCoder.maxBitRate; 1621 } 1622 else 1623 { 1624 max_bit_rate = remoteMedia_.videoCoder.active_fmt.bitRate; 1625 } 1626 std::stringstream bandwidth; 1627 bandwidth << max_bit_rate / 1000; 1628 sdp_media_desc->bandwidth()->setModifier("AS"); 1629 sdp_media_desc->bandwidth()->setBandwidthValue(bandwidth.str().c_str()); 1630 1631 SdpAttributeList* video_attr_list = sdp_media_desc->attributeList(); 1632 1633 std::stringstream payload; 1634 payload << remoteMedia_.videoCoder.coderPayloadType; 1635 sdp_media->addFormat(payload.str().c_str()); 1636 1637 SdpAttribute* video_attribute = video_attr_list->addItem(); 1638 video_attribute->setProperty("rtpmap"); 1639 std::stringstream rtpmap; 1640 rtpmap << remoteMedia_.videoCoder.coderPayloadType << " "; 1641 rtpmap << remoteMedia_.videoCoder.encoding << '/' << 90000; 1642 video_attribute->setPropertyValue(rtpmap.str().c_str()); 1643 1644 if ( (remoteMedia_.videoCoder.coderType == CODER_TYPE_H263) || 1645 (remoteMedia_.videoCoder.coderType == CODER_TYPE_H263_1998) ) 1646 { 1647 SdpAttribute* video_attribute = video_attr_list->addItem(); 1648 video_attribute->setProperty("fmtp"); 1649 std::stringstream fmtp; 1650 fmtp << remoteMedia_.videoCoder.coderPayloadType; 1651 1652 if ( (remoteMedia_.videoCoder.active_fmt.imageWidth == VIDEO_IMAGE_WIDTH_352) && 1653 (remoteMedia_.videoCoder.active_fmt.imageHeight == VIDEO_IMAGE_HEIGHT_288) ) 1654 { 1655 fmtp << " CIF="; 1656 } 1657 else if ( (remoteMedia_.videoCoder.active_fmt.imageWidth == VIDEO_IMAGE_WIDTH_176) && 1658 (remoteMedia_.videoCoder.active_fmt.imageHeight == VIDEO_IMAGE_HEIGHT_144) ) 1659 { 1660 fmtp << " QCIF="; 1661 } 1662 else 1663 { 1664 ; 1665 } 1666 fmtp << fps2mpi(remoteMedia_.videoCoder.active_fmt.framesPerSec); 1667 video_attribute->setPropertyValue(fmtp.str().c_str()); 1668 } 1669 else if ( remoteMedia_.videoCoder.coderType == CODER_TYPE_MP4V_ES ) 1670 { 1671 SdpAttribute* video_attribute = video_attr_list->addItem(); 1672 video_attribute->setProperty("fmtp"); 1673 std::stringstream fmtp; 1674 fmtp << remoteMedia_.videoCoder.coderPayloadType; 1675 1676 fmtp << " profile-level-id="; 1677 if ( remoteMedia_.videoCoder.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP0_MPEG4 ) 1678 { 1679 fmtp << "0"; 1680 } 1681 else if ( remoteMedia_.videoCoder.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP1_MPEG4 ) 1682 { 1683 fmtp << "1"; 1684 } 1685 else if ( remoteMedia_.videoCoder.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP2_MPEG4 ) 1686 { 1687 fmtp << "2"; 1688 } 1689 else if ( remoteMedia_.videoCoder.active_fmt.profile == VIDEO_PROFILE_LEVEL_SP3_MPEG4 ) 1690 { 1691 fmtp << "3"; 1692 } 1693 fmtp << " MaxBR=" << max_bit_rate / 100; 1694 video_attribute->setPropertyValue(fmtp.str().c_str()); 1695 } 1696 else if ( remoteMedia_.videoCoder.coderType == CODER_TYPE_H264 ) 1697 { 1698 SdpAttribute* video_attribute = video_attr_list->addItem(); 1699 video_attribute->setProperty("fmtp"); 1700 std::stringstream fmtp; 1701 fmtp << remoteMedia_.videoCoder.coderPayloadType; 1702 1703 fmtp << " profile-level-id="; 1704 if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_1_H264 ) 1705 { 1706 fmtp << "42000A"; 1707 } 1708 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_1_B_H264 ) 1709 { 1710 fmtp << "42100B"; 1711 } 1712 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_1_1_H264 ) 1713 { 1714 fmtp << "42000B"; 1715 } 1716 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_1_2_H264 ) 1717 { 1718 fmtp << "42000C"; 1719 } 1720 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_1_3_H264 ) 1721 { 1722 fmtp << "42000D"; 1723 } 1724 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_2_0_H264 ) 1725 { 1726 fmtp << "420014"; 1727 } 1728 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_2_1_H264 ) 1729 { 1730 fmtp << "420015"; 1731 } 1732 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_2_2_H264 ) 1733 { 1734 fmtp << "420016"; 1735 } 1736 else if ( remoteMedia_.videoCoder.active_fmt.level == VIDEO_LEVEL_3_0_H264 ) 1737 { 1738 fmtp << "42001E"; 1739 } 1740 else /* VIDEO_LEVEL_3_1_H264 */ 1741 { 1742 fmtp << "42001F"; 1743 } 1744 fmtp << "; packetization-mode=" << remoteMedia_.videoCoder.packetizationMode; 1745 fmtp << "; max-br=" << max_bit_rate / 1000; 1746 video_attribute->setPropertyValue(fmtp.str().c_str()); 1747 } 1748 else 1749 { 1750 /* more coders */ 1751 } 1752 1753 video_attribute = video_attr_list->addItem(); 1754 video_attribute->setProperty(localMedia_.videoRtp.getDirectionText().c_str()); 1755 video_attribute->setPropertyValue(""); 1756 } 1757 } 1758 } 1759 else /* Usupported media type. */ 1760 { 1761 sdp_media->setPort(0); 1762 std::stringstream payload; 1763 payload << (*i).audioCoder.coderPayloadType; 1764 sdp_media->addFormat(payload.str().c_str()); 1765 } 1766 } 1767 } 1768 1769 1770 /* 1771 * Extract the media details from the sdp and choose a coder from those offered. 1772 */ 1773 void IpmDevice::processSdp( SdpSessionDescription& sdp ) 1774 { 1775 parseSdp(sdp); /* Read into offer_ */ 1776 1777 /* Nothing to do if the version is unchanged. 1778 */ 1779 if ( remoteMedia_.origin.sess_version == offer_.session.origin.sess_version ) 1780 { 1781 return; 1782 } 1783 1784 remoteMedia_.origin = offer_.session.origin; 1785 1786 /* Choose the audio codec. 1787 */ 1788 localMedia_.audioCoder.encoding.clear(); 1789 remoteMedia_.audioCoder.encoding.clear(); 1790 setRemoteMediaInfo(MEDIATYPE_AUDIO_REMOTE_RTP_INFO, RtpIpInfo()); /* clear */ 1791 offer_.chosen_audio_mline = -1; 1792 1793 const Coders::audio_coders_t& audio_coders = ipt_->getAudioCoders(); 1794 1795 Offer::media_t::const_iterator j; 1796 for ( j = offer_.media.begin(); j != offer_.media.end(); ++j ) 1797 { 1798 if ( (*j).type == "audio" ) 1799 { 1800 Coders::audio_coders_t::const_iterator i; 1801 for ( i = audio_coders.begin(); i != audio_coders.end(); ++i ) 1802 { 1803 if ( *i == (*j).audioCoder ) 1804 { 1805 remoteMedia_.audioCoder = (*j).audioCoder; 1806 setRemoteMediaInfo(MEDIATYPE_AUDIO_REMOTE_RTP_INFO, (*j).rtp); 1807 1808 LOGDEBUG("IpmDevice::processSdp() chose: \"" << remoteMedia_.audioCoder.encoding << "\" for audio"); 1809 1810 /* The remoteMedia_.audioCoder preserves the encoding name from 1811 * the remote party, which may differ from the name defined in the 1812 * master coder set. The localMedia_.audioCoder uses the internal 1813 * encoding name to allow it to be safely compared. 1814 */ 1815 localMedia_.audioCoder = remoteMedia_.audioCoder; 1816 localMedia_.audioCoder.encoding = (*i).encoding; 1817 1818 if ( remoteMedia_.audioRtp.getDirection() == RtpIpInfo::INACTIVE ) 1819 { 1820 localMedia_.audioRtp.setDirection(RtpIpInfo::INACTIVE); 1821 } 1822 else if ( remoteMedia_.audioRtp.getDirection() == RtpIpInfo::SENDONLY ) 1823 { 1824 localMedia_.audioRtp.setDirection(RtpIpInfo::RECVONLY); 1825 } 1826 else if ( remoteMedia_.audioRtp.getDirection() == RtpIpInfo::RECVONLY ) 1827 { 1828 localMedia_.audioRtp.setDirection(RtpIpInfo::SENDONLY); 1829 } 1830 else /* "sendrecv" */ 1831 { 1832 localMedia_.audioRtp.setDirection(RtpIpInfo::SENDRECV); 1833 } 1834 1835 offer_.chosen_audio_mline = (*j).mline; 1836 break; 1837 } 1838 } 1839 if ( i != audio_coders.end() ) 1840 { 1841 break; /* Found a match. */ 1842 } 1843 } 1844 } 1845 1846 /* Choose the video codec. 1847 */ 1848 localMedia_.videoCoder.encoding.clear(); 1849 remoteMedia_.videoCoder.encoding.clear(); 1850 setRemoteMediaInfo(MEDIATYPE_VIDEO_REMOTE_RTP_INFO, RtpIpInfo()); /* clear */ 1851 offer_.chosen_video_mline = -1; 1852 1853 const Coders::video_coders_t& video_coders = ipt_->getVideoCoders(); 1854 1855 Offer::media_t::const_iterator l; 1856 for ( l = offer_.media.begin(); l != offer_.media.end(); ++l ) 1857 { 1858 if ( (*l).type == "video" ) 1859 { 1860 Coders::video_coders_t::const_iterator k; 1861 for ( k = video_coders.begin(); k != video_coders.end(); ++k ) 1862 { 1863 if ( *k == (*l).videoCoder ) 1864 { 1865 remoteMedia_.videoCoder = (*l).videoCoder; 1866 /* Use the first fmt offered, there is always at least one. */ 1867 remoteMedia_.videoCoder.active_fmt = (*l).videoCoder.available_fmts[0]; 1868 LOGDEBUG("IpmDevice::processSdp() chose: \"" << remoteMedia_.videoCoder.encoding << "\" for video"); 1869 1870 setRemoteMediaInfo(MEDIATYPE_VIDEO_REMOTE_RTP_INFO, (*l).rtp); 1871 1872 /* The remoteMedia_.videoCoder preserves the encoding name from 1873 * the remote party, which may differ from the name defined in the 1874 * master coder set. The localMedia_.videoCoder uses the internal 1875 * encoding name to allow it to be safely compared. 1876 */ 1877 localMedia_.videoCoder = remoteMedia_.videoCoder; 1878 localMedia_.videoCoder.encoding = (*k).encoding; 1879 1880 if ( remoteMedia_.videoRtp.getDirection() == RtpIpInfo::INACTIVE ) 1881 { 1882 localMedia_.videoRtp.setDirection(RtpIpInfo::INACTIVE); 1883 } 1884 else if ( remoteMedia_.videoRtp.getDirection() == RtpIpInfo::SENDONLY ) 1885 { 1886 localMedia_.videoRtp.setDirection(RtpIpInfo::RECVONLY); 1887 } 1888 else if ( remoteMedia_.videoRtp.getDirection() == RtpIpInfo::RECVONLY ) 1889 { 1890 localMedia_.videoRtp.setDirection(RtpIpInfo::SENDONLY); 1891 } 1892 else /* "sendrecv" */ 1893 { 1894 localMedia_.videoRtp.setDirection(RtpIpInfo::SENDRECV); 1895 } 1896 1897 offer_.chosen_video_mline = (*l).mline; 1898 break; 1899 } 1900 } 1901 if ( k != video_coders.end() ) 1902 { 1903 break; /* Found a match. */ 1904 } 1905 } 1906 } 1907 } 1908 1909 1910 /* 1911 * Lookup the sdp media direction attribute. If multiple, use the final definition. 1912 */ 1913 void IpmDevice::getSdpDirection( SdpAttributeList* attribute_list, std::string& direction ) 1914 { 1915 const int num_attribute = attribute_list->numItem(); 1916 for ( int n = 0; n < num_attribute; n++ ) 1917 { 1918 SdpAttribute* attribute = attribute_list->getItem(n); 1919 1920 if ( strcmp(attribute->getProperty(), "sendonly") == 0 ) 1921 { 1922 direction = "sendonly"; 1923 } 1924 if ( strcmp(attribute->getProperty(), "recvonly") == 0 ) 1925 { 1926 direction = "recvonly"; 1927 } 1928 if ( strcmp(attribute->getProperty(), "sendrecv") == 0 ) 1929 { 1930 direction = "sendrecv"; 1931 } 1932 if ( strcmp(attribute->getProperty(), "inactive") == 0 ) 1933 { 1934 direction = "inactive"; 1935 } 1936 } 1937 } 1938 1939 1940 /* 1941 * Extract media details from an sdp. 1942 */ 1943 void IpmDevice::parseSdp( SdpSessionDescription& sdp_desc ) 1944 { 1945 const Coders::audio_coders_t& audioCoders = ipt_->getAudioCoders(); 1946 const Coders::video_coders_t& videoCoders = ipt_->getVideoCoders(); 1947 1948 /* c= */ 1949 offer_.session.conn_address = sdp_desc.connection()->getAddress(); 1950 1951 /* b= */ 1952 offer_.session.bandwidth = 384000; 1953 std::string modifier = sdp_desc.bandwidth()->getModifier(); 1954 if ( modifier == "AS" ) 1955 { 1956 offer_.session.bandwidth = atoi(sdp_desc.bandwidth()->getBandwidthValue()) * 1000; 1957 } 1958 1959 /* o= */ 1960 offer_.session.origin.username = sdp_desc.origin()->getUserName(); 1961 offer_.session.origin.sess_id = sdp_desc.origin()->getSessionId(); 1962 offer_.session.origin.sess_version = sdp_desc.origin()->getVersion(); 1963 offer_.session.origin.net_type = sdp_desc.origin()->getNetworkType(); 1964 offer_.session.origin.addr_type = sdp_desc.origin()->getAddressType(); 1965 offer_.session.origin.address = sdp_desc.origin()->getAddress(); 1966 1967 /* a= */ 1968 offer_.session.direction = "sendrecv"; /* Default, RFC 3264 */ 1969 1970 SdpAttributeList* attribute_list = sdp_desc.attributeList(); 1971 getSdpDirection(attribute_list, offer_.session.direction); 1972 1973 /* If the connection address is "0.0.0.0" neither RTP nor RTCP can be sent 1974 * to the remote party. It _could_ indicate hold (RFC 2543), and the remote 1975 * party may still send(only) media. 1976 */ 1977 if ( offer_.session.conn_address == "0.0.0.0" ) 1978 { 1979 if ( offer_.session.direction != "sendonly" ) 1980 { 1981 offer_.session.direction = "inactive"; 1982 } 1983 } 1984 1985 offer_.media.clear(); 1986 1987 const int num_media = sdp_desc.mediaDescriptionList()->numItem(); 1988 for ( int m = 0; m < num_media; m++ ) 1989 { 1990 SdpMediaDescription* md = sdp_desc.mediaDescriptionList()->getItem(m); 1991 1992 std::string media_addr(md->connection()->getAddress()); 1993 if ( media_addr.empty() ) 1994 { 1995 media_addr = offer_.session.conn_address; 1996 } 1997 1998 SdpMedia* sdp_media = md->media(); 1999 if ( (strcmp(sdp_media->getMedia(), "audio") == 0) && 2000 (strcmp(sdp_media->getTransport(), "RTP/AVP") == 0) && 2001 (sdp_media->getPort() != 0) ) 2002 { 2003 std::string media_direction = offer_.session.direction; 2004 getSdpDirection(md->attributeList(), media_direction); 2005 if ( offer_.session.conn_address == "0.0.0.0" ) 2006 { 2007 if ( media_direction != "sendonly" ) 2008 { 2009 media_direction = "inactive"; 2010 } 2011 } 2012 RtpIpInfo rtp(media_addr, sdp_media->getPort(), RtpIpInfo::INACTIVE); 2013 rtp.setDirection(media_direction); 2014 2015 const int num_format = sdp_media->getNumFormat(); 2016 for ( int f = 0; f < num_format; f++ ) 2017 { 2018 Offer::Media remote_media; 2019 remote_media.type = sdp_media->getMedia(); 2020 remote_media.transport = sdp_media->getTransport(); 2021 remote_media.mline = m; 2022 remote_media.rtp = rtp; 2023 remote_media.rfc2833 = false; 2024 remote_media.audioCoder.coderPayloadType = atoi(sdp_media->getFormat(f)); 2025 remote_media.audioCoder.coderType = CODER_TYPE_NONSTANDARD; 2026 2027 /* Initialise any static coders as the rtpmap is optional. 2028 */ 2029 Coders::audio_coders_t::const_iterator i = audioCoders.begin(); 2030 for ( ; i != audioCoders.end(); ++i ) 2031 { 2032 if ( ((*i).coderPayloadType == remote_media.audioCoder.coderPayloadType) && 2033 ((*i).coderPayloadType < 96) ) 2034 { 2035 remote_media.audioCoder = (*i); 2036 break; 2037 } 2038 } 2039 offer_.media.push_back(remote_media); 2040 } 2041 2042 SdpAttributeList* attribute_list = md->attributeList(); 2043 const int num_attribute = attribute_list->numItem(); 2044 2045 /* First pass, read in rtpmap attributes. */ 2046 for ( int a = 0; a < num_attribute; a++ ) 2047 { 2048 SdpAttribute* attribute = attribute_list->getItem(a); 2049 2050 if ( strcmp(attribute->getProperty(), "rtpmap") == 0 ) 2051 { 2052 StringTokeniser rtpmap(attribute->getPropertyValue()); 2053 2054 int payload = atoi(rtpmap.token(' ').c_str()); 2055 std::string encoding = rtpmap.token('/'); 2056 unsigned int clockrate = atoi(rtpmap.token().c_str()); 2057 if ( (clockrate != 8000) && (clockrate != 16000) ) 2058 { 2059 LOGDEBUG("IpmDevice::parseSdp() payload: " << payload << 2060 " has an unsupported clockrate: " << clockrate); 2061 } 2062 2063 Offer::media_t::iterator i; 2064 for ( i = offer_.media.begin(); i != offer_.media.end(); ++i ) 2065 { 2066 if ( ((*i).type == "audio") && ((*i).audioCoder.coderPayloadType == payload) ) 2067 { 2068 const AudioCoderInfo* audio_coder = 0; 2069 2070 Coders::audio_coders_t::const_iterator j = audioCoders.begin(); 2071 for ( ; j != audioCoders.end(); ++j ) 2072 { 2073 if ( strcasecmp(encoding.c_str(), (*j).encoding.c_str()) == 0 ) 2074 { 2075 audio_coder = &(*j); 2076 break; 2077 } 2078 } 2079 2080 if ( audio_coder ) 2081 { 2082 (*i).audioCoder = *audio_coder; 2083 (*i).audioCoder.coderPayloadType = payload; 2084 } 2085 else /* CODER_TYPE_NONSTANDARD */ 2086 { 2087 if ( (strcasecmp(encoding.c_str(), "telephone-event") == 0 ) && 2088 (clockrate == 8000) ) 2089 { 2090 (*i).rfc2833 = true; 2091 } 2092 (*i).audioCoder.clockRate = clockrate; 2093 } 2094 (*i).audioCoder.encoding = encoding; 2095 break; 2096 } 2097 } 2098 } 2099 } 2100 /* Second pass, read non rtpmap attributes. */ 2101 for ( int a = 0; a < num_attribute; a++ ) 2102 { 2103 SdpAttribute* attribute = attribute_list->getItem(a); 2104 if ( strcmp(attribute->getProperty(), "fmtp") == 0 ) 2105 { 2106 StringTokeniser fmtp(attribute->getPropertyValue()); 2107 2108 int payload = atoi(fmtp.token(' ').c_str()); 2109 2110 Offer::media_t::iterator i; 2111 for ( i = offer_.media.begin(); i != offer_.media.end(); ++i ) 2112 { 2113 if ( ((*i).type == "audio") && ((*i).audioCoder.coderPayloadType == payload) ) 2114 { 2115 bool done = false; 2116 while ( !done ) 2117 { 2118 std::string name = fmtp.token('='); 2119 trim(name); 2120 if ( name.empty() ) 2121 { 2122 break; 2123 } 2124 std::string value = fmtp.token("; "); 2125 trim(value); 2126 if ( value.empty() ) 2127 { 2128 value = fmtp.token(); 2129 done = true; 2130 } 2131 2132 if ( (*i).audioCoder.coderType == CODER_TYPE_G729ANNEXA ) 2133 { 2134 std::string g729Annex = fmtp.token(' '); 2135 if ( g729Annex == "annexb=yes" ) 2136 { 2137 (*i).audioCoder.coderType = CODER_TYPE_G729ANNEXAWANNEXB; 2138 (*i).audioCoder.vadEnable = CODER_VAD_ENABLE; 2139 } 2140 } 2141 else if ( ((*i).audioCoder.coderType == CODER_TYPE_AMRNB_12_2k) || 2142 ((*i).audioCoder.coderType == CODER_TYPE_AMRWB_6_6K) ) 2143 { 2144 if ( name == "octet-align" ) 2145 { 2146 (*i).audioCoder.coderOptions &= ~(CODER_OPT_AMR_OCTET | CODER_OPT_AMR_EFFICIENT); 2147 if ( value == "1" ) 2148 { 2149 (*i).audioCoder.coderOptions |= CODER_OPT_AMR_OCTET; 2150 } 2151 else 2152 { 2153 (*i).audioCoder.coderOptions |= CODER_OPT_AMR_EFFICIENT; 2154 } 2155 } 2156 } 2157 else if ( ((*i).audioCoder.coderType == CODER_TYPE_NONSTANDARD) && ((*i).rfc2833) ) 2158 { 2159 ;/* TODO check 0-15 */ 2160 } 2161 else 2162 { 2163 ; 2164 } 2165 } 2166 } 2167 } 2168 } 2169 else /* Add other attributes here */ 2170 { 2171 ; 2172 } 2173 } 2174 } 2175 else if ( (strcmp(sdp_media->getMedia(), "video") == 0) && 2176 (strcmp(sdp_media->getTransport(), "RTP/AVP") == 0) && 2177 (sdp_media->getPort() != 0) ) 2178 { 2179 std::string media_direction = offer_.session.direction; 2180 getSdpDirection(md->attributeList(), media_direction); 2181 if ( offer_.session.conn_address == "0.0.0.0" ) 2182 { 2183 if ( media_direction != "sendonly" ) 2184 { 2185 media_direction = "inactive"; 2186 } 2187 } 2188 RtpIpInfo rtp(media_addr, sdp_media->getPort(), RtpIpInfo::INACTIVE); 2189 rtp.setDirection(media_direction); 2190 2191 unsigned int bandwidth = offer_.session.bandwidth; 2192 std::string modifier = md->bandwidth()->getModifier(); 2193 if ( modifier == "AS" ) 2194 { 2195 bandwidth = atoi(md->bandwidth()->getBandwidthValue()) * 1000; 2196 } 2197 2198 const int num_format = sdp_media->getNumFormat(); 2199 for ( int f = 0; f < num_format; f++ ) 2200 { 2201 Offer::Media remote_media; 2202 remote_media.type = sdp_media->getMedia(); 2203 remote_media.transport = sdp_media->getTransport(); 2204 remote_media.mline = m; 2205 remote_media.rtp = rtp; 2206 remote_media.videoCoder.coderPayloadType = atoi(sdp_media->getFormat(f)); 2207 remote_media.videoCoder.coderType = CODER_TYPE_NONSTANDARD; 2208 remote_media.videoCoder.maxBitRate = bandwidth; 2209 2210 /* Initialise any static coders as the rtpmap is optional. 2211 */ 2212 Coders::video_coders_t::const_iterator i = videoCoders.begin(); 2213 for ( ; i != videoCoders.end(); ++i ) 2214 { 2215 if ( ((*i).coderPayloadType == remote_media.videoCoder.coderPayloadType) && 2216 ((*i).coderPayloadType < 96) ) 2217 { 2218 remote_media.videoCoder = (*i); 2219 break; 2220 } 2221 } 2222 offer_.media.push_back(remote_media); 2223 } 2224 2225 SdpAttributeList* attribute_list = md->attributeList(); 2226 const int num_attribute = attribute_list->numItem(); 2227 2228 /* First pass, read in rtpmap attibutes. */ 2229 for ( int a = 0; a < num_attribute; a++ ) 2230 { 2231 SdpAttribute* attribute = attribute_list->getItem(a); 2232 2233 if ( strcmp(attribute->getProperty(), "rtpmap") == 0 ) 2234 { 2235 StringTokeniser rtpmap(attribute->getPropertyValue()); 2236 2237 int payload = atoi(rtpmap.token(' ').c_str()); 2238 std::string encoding = rtpmap.token('/'); 2239 unsigned int clockrate = atoi(rtpmap.token().c_str()); 2240 if ( clockrate != 90000 ) 2241 { 2242 LOGDEBUG("IpmDevice::parseSdp() payload: " << payload << 2243 " has an unsupported clockrate: " << clockrate); 2244 } 2245 Offer::media_t::iterator i; 2246 for ( i = offer_.media.begin(); i != offer_.media.end(); ++i ) 2247 { 2248 if ( ((*i).type == "video") && ((*i).videoCoder.coderPayloadType == payload) ) 2249 { 2250 const VideoCoderInfo* video_coder = 0; 2251 2252 Coders::video_coders_t::const_iterator j = videoCoders.begin(); 2253 for ( ; j != videoCoders.end(); ++j ) 2254 { 2255 if ( strcasecmp(encoding.c_str(), (*j).encoding.c_str()) == 0 ) 2256 { 2257 video_coder = &(*j); 2258 break; 2259 } 2260 } 2261 2262 if ( video_coder ) 2263 { 2264 (*i).videoCoder = *video_coder; 2265 (*i).videoCoder.coderPayloadType = payload; 2266 (*i).videoCoder.maxBitRate = bandwidth; 2267 } 2268 2269 (*i).videoCoder.encoding = encoding; 2270 break; 2271 } 2272 } 2273 } 2274 } 2275 /* Second pass, read none rtpmap attributes. */ 2276 for ( int a = 0; a < num_attribute; a++ ) 2277 { 2278 SdpAttribute* attribute = attribute_list->getItem(a); 2279 if ( strcmp(attribute->getProperty(), "fmtp") == 0 ) 2280 { 2281 StringTokeniser fmtp(attribute->getPropertyValue()); 2282 2283 int payload = atoi(fmtp.token(' ').c_str()); 2284 2285 Offer::media_t::iterator i; 2286 for ( i = offer_.media.begin(); i != offer_.media.end(); ++i ) 2287 { 2288 if ( ((*i).type == "video") && ((*i).videoCoder.coderPayloadType == payload) ) 2289 { 2290 /* Container for matched formats, on completion its 2291 * contents will be used to replace the coder's 2292 * available formats. 2293 */ 2294 std::vector<VideoCoderInfo::Fmt> matched_fmts; 2295 2296 bool done = false; 2297 while ( !done ) 2298 { 2299 VideoCoderInfo::Fmt fmt; 2300 2301 std::string name = fmtp.token('='); 2302 trim(name); 2303 if ( name.empty() ) 2304 { 2305 break; 2306 } 2307 std::string value = fmtp.token("; "); 2308 trim(value); 2309 if ( value.empty() ) 2310 { 2311 value = fmtp.token(); 2312 done = true; 2313 } 2314 2315 if ( (name == "CIF") || (name == "QCIF") || (name == "SQCIF") ) 2316 { 2317 eVIDEO_IMAGE_WIDTH width = VIDEO_IMAGE_WIDTH_CIF; 2318 eVIDEO_IMAGE_HEIGHT height = VIDEO_IMAGE_HEIGHT_CIF; 2319 if ( name == "QCIF" ) 2320 { 2321 width = VIDEO_IMAGE_WIDTH_QCIF; 2322 height = VIDEO_IMAGE_HEIGHT_QCIF; 2323 } 2324 else if ( name == "Sub-QCIF" ) 2325 { 2326 width = VIDEO_IMAGE_WIDTH_SQCIF; 2327 height = VIDEO_IMAGE_HEIGHT_SQCIF; 2328 } 2329 2330 eVIDEO_FRAMESPERSEC fps = mpi2fps(atoi(value.c_str())); 2331 2332 std::vector<VideoCoderInfo::Fmt>::const_iterator j = (*i).videoCoder.available_fmts.begin(); 2333 for ( ; j != (*i).videoCoder.available_fmts.end(); ++j ) 2334 { 2335 if ( ((*j).imageWidth == width) && 2336 ((*j).imageHeight == height) && 2337 ((*j).framesPerSec == fps) ) 2338 { 2339 fmt.profile = (*j).profile; 2340 fmt.level = (*j).level; 2341 fmt.imageWidth = (*j).imageWidth; 2342 fmt.imageHeight = (*j).imageHeight; 2343 fmt.framesPerSec = (*j).framesPerSec; 2344 fmt.bitRate = (*j).bitRate; 2345 matched_fmts.push_back(fmt); 2346 break; 2347 } 2348 } 2349 } 2350 else if ( name == "profile" ) 2351 { 2352 ; 2353 } 2354 else if ( name == "level" ) 2355 { 2356 ; 2357 } 2358 else if ( name == "profile-level-id" ) 2359 { 2360 if ( (*i).videoCoder.coderType == CODER_TYPE_MP4V_ES ) 2361 { 2362 eVIDEO_PROFILE profile_level = static_cast<eVIDEO_PROFILE>(0); 2363 2364 if ( value == "0" ) 2365 { 2366 profile_level = VIDEO_PROFILE_LEVEL_SP0_MPEG4; 2367 } 2368 else if ( value == "1" ) 2369 { 2370 profile_level = VIDEO_PROFILE_LEVEL_SP1_MPEG4; 2371 } 2372 else if ( value == "2" ) 2373 { 2374 profile_level = VIDEO_PROFILE_LEVEL_SP2_MPEG4; 2375 } 2376 else if ( value == "3" ) 2377 { 2378 profile_level = VIDEO_PROFILE_LEVEL_SP3_MPEG4; 2379 } 2380 else 2381 { 2382 ; 2383 } 2384 2385 std::vector<VideoCoderInfo::Fmt>::const_iterator j = (*i).videoCoder.available_fmts.begin(); 2386 for ( ; j != (*i).videoCoder.available_fmts.end(); ++j ) 2387 { 2388 if ( (*j).profile == profile_level ) 2389 { 2390 fmt.profile = (*j).profile; 2391 fmt.level = (*j).level; 2392 fmt.imageWidth = (*j).imageWidth; 2393 fmt.imageHeight = (*j).imageHeight; 2394 fmt.framesPerSec = (*j).framesPerSec; 2395 fmt.bitRate = (*j).bitRate; 2396 matched_fmts.push_back(fmt); 2397 break; 2398 } 2399 } 2400 } 2401 2402 if ( (*i).videoCoder.coderType == CODER_TYPE_H264 ) 2403 { 2404 int h264level; 2405 if ( sscanf(value.c_str(), "%x", &h264level) == 1 ) 2406 { 2407 bool h264_1B = (h264level >> 12) & 1; 2408 2409 eVIDEO_LEVEL level = static_cast<eVIDEO_LEVEL>(h264level & 0xFF); 2410 if ( (level == VIDEO_LEVEL_1_1_H264) && h264_1B ) 2411 { 2412 level = VIDEO_LEVEL_1_B_H264; 2413 } 2414 2415 std::vector<VideoCoderInfo::Fmt>::const_iterator j = (*i).videoCoder.available_fmts.begin(); 2416 for ( ; j != (*i).videoCoder.available_fmts.end(); ++j ) 2417 { 2418 if ( (*j).level == level ) 2419 { 2420 fmt.profile = (*j).profile; 2421 fmt.level = (*j).level; 2422 fmt.imageWidth = (*j).imageWidth; 2423 fmt.imageHeight = (*j).imageHeight; 2424 fmt.framesPerSec = (*j).framesPerSec; 2425 fmt.bitRate = (*j).bitRate; 2426 matched_fmts.push_back(fmt); 2427 break; 2428 } 2429 } 2430 } 2431 } 2432 } 2433 else if ( name == "MaxBR" ) 2434 { 2435 (*i).videoCoder.maxBitRate = atoi(value.c_str()) * 100; 2436 } 2437 else if ( name == "max-br" ) 2438 { 2439 (*i).videoCoder.maxBitRate = atoi(value.c_str()) * 1000; 2440 } 2441 else if ( name == "packetization-mode" ) 2442 { 2443 (*i).videoCoder.packetizationMode = atoi(value.c_str()); 2444 } 2445 else 2446 { 2447 continue; /* Ignore unsupported params. */ 2448 } 2449 } 2450 /* Use the default format, if known format was provided. 2451 */ 2452 if ( matched_fmts.empty() ) 2453 { 2454 VideoCoderInfo::Fmt fmt; 2455 fmt.profile = (*i).videoCoder.active_fmt.profile; 2456 fmt.level = (*i).videoCoder.active_fmt.level; 2457 fmt.imageWidth = (*i).videoCoder.active_fmt.imageWidth; 2458 fmt.imageHeight = (*i).videoCoder.active_fmt.imageHeight; 2459 fmt.framesPerSec = (*i).videoCoder.active_fmt.framesPerSec; 2460 fmt.bitRate = (*i).videoCoder.active_fmt.bitRate; 2461 matched_fmts.push_back(fmt); 2462 } 2463 (*i).videoCoder.available_fmts = matched_fmts; 2464 break; 2465 } 2466 } 2467 } /* end "fmtp" */ 2468 } 2469 } 2470 else /* Unknown media, save details so that it can be rejected. */ 2471 { 2472 const int num_format = sdp_media->getNumFormat(); 2473 for ( int f = 0; f < num_format; f++ ) 2474 { 2475 Offer::Media remote_media; 2476 remote_media.type = sdp_media->getMedia(); 2477 remote_media.transport = sdp_media->getTransport(); 2478 remote_media.mline = m; 2479 /* Just need somewhere to save the format. */ 2480 remote_media.audioCoder.coderPayloadType = atoi(sdp_media->getFormat(f)); 2481 remote_media.audioCoder.coderType = CODER_TYPE_NONSTANDARD; 2482 offer_.media.push_back(remote_media); 2483 } 2484 } 2485 } 2486 } 2487 2488 2489 /* 2490 * Forward to event specific handler. 2491 */ 2492 bool IpmDevice::processEvent( METAEVENT& metaevent ) 2493 { 2494 switch ( metaevent.evttype ) 2495 { 2496 case IPMEV_OPEN: 2497 onOpen(); 2498 break; 2499 2500 case IPMEV_EVENT_ENABLED: 2501 onEventEnabled(); 2502 break; 2503 2504 case IPMEV_GET_LOCAL_MEDIA_INFO: 2505 onLocalMediaInfo(static_cast<IPM_MEDIA_INFO*>(sr_getevtdatap())); 2506 break; 2507 2508 case IPMEV_STARTMEDIA: 2509 onStartMedia(); 2510 break; 2511 2512 case IPMEV_STOPPED: 2513 onStopped(); 2514 break; 2515 2516 case IPMEV_LISTEN: 2517 onListen(); 2518 break; 2519 2520 case IPMEV_UNLISTEN: 2521 onUnListen(); 2522 break; 2523 2524 case IPMEV_GENERATEIFRAME: 2525 LOGINFO("IpmDevice::processEvent() IPMEV_GENERATEIFRAME device: " << getDeviceName()); 2526 busy_ = false; 2527 processPendingCommand(); 2528 break; 2529 2530 case IPMEV_GENERATEIFRAME_FAIL: 2531 LOGERROR("IpmDevice::processEvent() IPMEV_GENERATEIFRAME_FAIL device: " << getDeviceName()); 2532 busy_ = false; 2533 processPendingCommand(); 2534 break; 2535 2536 case IPMEV_ERROR: 2537 onError(); 2538 break; 2539 2540 case IPMEV_TELEPHONY_EVENT: 2541 onTelephonyEvent(static_cast<IPM_TELEPHONY_INFO*>(sr_getevtdatap())); 2542 break; 2543 2544 case DMEV_GET_TX_PORT_INFO: 2545 onGetTxPortInfo(static_cast<DM_PORT_INFO_LIST*>(sr_getevtdatap())); 2546 break; 2547 2548 case DMEV_GET_TX_PORT_INFO_FAIL: 2549 onPortGetFail(); 2550 break; 2551 2552 case DMEV_GET_RX_PORT_INFO: 2553 onGetRxPortInfo(static_cast<DM_PORT_INFO_LIST*>(sr_getevtdatap())); 2554 break; 2555 2556 case DMEV_GET_RX_PORT_INFO_FAIL: 2557 onPortGetFail(); 2558 break; 2559 2560 case DMEV_PORT_CONNECT: 2561 onPortConnect(); 2562 break; 2563 2564 case DMEV_PORT_CONNECT_FAIL: 2565 onPortConnectFail(); 2566 break; 2567 2568 case DMEV_PORT_DISCONNECT: 2569 onPortDisconnect(); 2570 break; 2571 2572 case DMEV_PORT_DISCONNECT_FAIL: 2573 LOGERROR("IpmDevice::processEvent() DMEV_PORT_DISCONNECT_FAIL device: " << getDeviceName()); 2574 break; 2575 2576 case DMEV_CONNECT: 2577 LOGINFO("IpmDevice::processEvent() DMEV_CONNECT for device: " << getDeviceName()); 2578 break; 2579 2580 case DMEV_CONNECT_FAIL: 2581 LOGERROR("IpmDevice::processEvent() DMEV_CONNECT_FAIL for device: " << getDeviceName()); 2582 break; 2583 2584 case DMEV_DISCONNECT: 2585 LOGINFO("IpmDevice::processEvent() DMEV_DISCONNECT for device: " << getDeviceName()); 2586 break; 2587 2588 case DMEV_DISCONNECT_FAIL: 2589 LOGERROR("IpmDevice::processEvent() DMEV_DISCONNECT_FAIL for device: " << getDeviceName()); 2590 break; 2591 2592 case SMEV_ADD_OVERLAY: 2593 onAddOverlay(); 2594 break; 2595 2596 case SMEV_ADD_OVERLAY_FAIL: 2597 onAddOverlayFail(); 2598 break; 2599 2600 case SMEV_REMOVE_OVERLAY: 2601 onRemoveOverlay(); 2602 break; 2603 2604 case SMEV_REMOVE_OVERLAY_FAIL: 2605 onRemoveOverlayFail(); 2606 break; 2607 2608 case SMEV_ERROR: 2609 LOGERROR("IpmDevice::processEvent() SMEV_ERROR device: " << getDeviceName()); 2610 break; 2611 2612 case APP_IMAGEMAKER_OK: 2613 onImageMaker(static_cast<ImageMakerEvent*>(sr_getevtdatap())); 2614 break; 2615 2616 case APP_IMAGEMAKER_FAIL: 2617 LOGERROR("IpmDevice::processEvent() APP_IMAGEMAKER_FAIL device: " << getDeviceName()); 2618 break; 2619 2620 case APP_RTSP_EVENT: 2621 onRtsp(static_cast<RtspEvent*>(sr_getevtdatap())); 2622 break; 2623 2624 default: 2625 LOGWARN("IpmDevice::processEvent() unhandled event: 0x" << 2626 std::hex << metaevent.evttype << " for device: " << getDeviceName()); 2627 return false; 2628 } 2629 return true; 2630 } 2631 2632 2633 /* 2634 * Handler for IPMEV_OPEN events. 2635 */ 2636 void IpmDevice::onOpen() 2637 { 2638 LOGINFO("IpmDevice::onOpen() device: " << getDeviceName()); 2639 2640 other_audio_ = 0; 2641 other_video_ = 0; 2642 2643 /* Get and save the transmit timeslot on CTBus. 2644 */ 2645 SC_TSINFO tsinfo; 2646 tsinfo.sc_numts = 1; 2647 tsinfo.sc_tsarrayp = getXmitTimeslotPtr(); 2648 if ( ipm_GetXmitSlot(devHandle_, &tsinfo, EV_SYNC) == -1 ) 2649 { 2650 LOGERROR("ipm_GetXmitSlot() failed" ); 2651 } 2652 2653 /* Enable dtmf events. 2654 */ 2655 eIPM_EVENT event = EVT_RFC2833; 2656 if ( ipm_EnableEvents(devHandle_, &event, 1, EV_SYNC) < 0 ) 2657 { 2658 LOGERROR("ipm_EnableEvent() EVT_RFC2833 failed on device:" << devHandle_); 2659 } 2660 2661 /* Request port info. 2662 */ 2663 if ( dev_GetTransmitPortInfo(devHandle_, this) == -1 ) 2664 { 2665 LOGERROR("dev_GetTransmitPortInfo() failed"); 2666 } 2667 if ( dev_GetReceivePortInfo(devHandle_, this) == -1 ) 2668 { 2669 LOGERROR("dev_GetReceivePortInfo() failed"); 2670 } 2671 2672 /* Request the local media information. 2673 */ 2674 IPM_MEDIA_INFO media_info; 2675 memset(&media_info, 0, sizeof(IPM_MEDIA_INFO)); 2676 media_info.unCount = 2; 2677 media_info.MediaData[0].eMediaType = MEDIATYPE_AUDIO_LOCAL_RTP_INFO; 2678 media_info.MediaData[1].eMediaType = MEDIATYPE_VIDEO_LOCAL_RTP_INFO; 2679 2680 if ( ipm_GetLocalMediaInfo(devHandle_, &media_info, EV_ASYNC) == -1 ) 2681 { 2682 LOGERROR("ipm_GetLocalMediaInfo() failed for device: " << 2683 getDeviceName() << " with error: " << ATDV_LASTERR(devHandle_)); 2684 } 2685 2686 /* Update init state. 2687 */ 2688 state_ = IPM_INITIALIZATION_START; 2689 initStepsRemaining_--; 2690 if ( initStepsRemaining_ == 0 ) 2691 { 2692 state_ = IPM_IDLE; 2693 } 2694 } 2695 2696 2697 /* 2698 * Handler for DMEV_GET_TX_PORT_INFO events. 2699 */ 2700 void IpmDevice::onGetTxPortInfo( DM_PORT_INFO_LIST* portInfoList ) 2701 { 2702 LOGINFO("IpmDevice::onGetTxPortInfo() device: " << getDeviceName()); 2703 2704 txPortInfoList_ = *portInfoList; 2705 LOGDEBUG(std::endl << txPortInfoList_); 2706 2707 for ( unsigned int i = 0; i < txPortInfoList_.unCount; i++ ) 2708 { 2709 switch ( txPortInfoList_.port_info[i].port_media_type ) 2710 { 2711 case DM_PORT_MEDIA_TYPE_AUDIO: 2712 audioPortTxInfo_ = txPortInfoList_.port_info[i]; 2713 break; 2714 2715 case DM_PORT_MEDIA_TYPE_VIDEO: 2716 videoPortTxInfo_ = txPortInfoList_.port_info[i]; 2717 break; 2718 2719 default: 2720 break; 2721 } 2722 } 2723 2724 initStepsRemaining_--; 2725 if ( initStepsRemaining_ == 0 ) 2726 { 2727 state_ = IPM_IDLE; 2728 } 2729 } 2730 2731 2732 /* 2733 * Handler for DMEV_GET_RX_PORT_INFO events. 2734 */ 2735 void IpmDevice::onGetRxPortInfo( DM_PORT_INFO_LIST* portInfoList ) 2736 { 2737 LOGINFO("IpmDevice::onGetRxPortInfo() device: " << getDeviceName()); 2738 2739 rxPortInfoList_ = *portInfoList; 2740 LOGDEBUG(std::endl << rxPortInfoList_); 2741 2742 for ( unsigned int i = 0; i < rxPortInfoList_.unCount; i++ ) 2743 { 2744 switch ( rxPortInfoList_.port_info[i].port_media_type ) 2745 { 2746 case DM_PORT_MEDIA_TYPE_AUDIO: 2747 audioPortRxInfo_ = rxPortInfoList_.port_info[i]; 2748 break; 2749 2750 case DM_PORT_MEDIA_TYPE_VIDEO: 2751 videoPortRxInfo_ = rxPortInfoList_.port_info[i]; 2752 break; 2753 2754 default: 2755 break; 2756 } 2757 } 2758 2759 initStepsRemaining_--; 2760 if ( initStepsRemaining_ == 0 ) 2761 { 2762 state_ = IPM_IDLE; 2763 } 2764 } 2765 2766 2767 /* 2768 * Handler for DMEV_GET_TX_PORT_INFO_FAIL and DMEV_GET_RX_PORT_INFO_FAIL 2769 * events. 2770 */ 2771 void IpmDevice::onPortGetFail() 2772 { 2773 LOGERROR("IpmDevice::onPortGetFail() device: " << getDeviceName()); 2774 2775 state_ = IPM_INVALID; /* ideas? */ 2776 } 2777 2778 2779 /* 2780 * Handler for IPMEV_ERROR events. 2781 */ 2782 void IpmDevice::onError() 2783 { 2784 LOGERROR("IpmDevice::onError() device: " << getDeviceName() << 2785 " error: " << ATDV_ERRMSGP(devHandle_)); 2786 2787 state_ = IPM_INVALID; 2788 2789 busy_ = false; 2790 processPendingCommand(); 2791 } 2792 2793 2794 /* 2795 * Handler for IPMEV_TELEPHONY_EVENT events. 2796 */ 2797 void IpmDevice::onTelephonyEvent( IPM_TELEPHONY_INFO* info ) 2798 { 2799 LOGINFO("IpmDevice::processEvent() IPMEV_TELEPHONY_EVENT device: " << getDeviceName() ); 2800 2801 switch ( info->eTelInfoType ) 2802 { 2803 case TEL_INFOTYPE_EVENT: 2804 { 2805 int event_id = info->TelephonyInfo.TelEvtInfo.eTelephonyEventID; 2806 LOGDEBUG("TelephonyEventID: 0x" << std::hex << event_id); 2807 if ( (event_id >= 0) && (event_id <= 15) ) 2808 { 2809 if ( channel_ ) 2810 { 2811 const std::string dtmf = "0123456789*#ABCD"; 2812 channel_->onDtmf(dtmf[event_id]); 2813 } 2814 } 2815 break; 2816 } 2817 2818 default: 2819 break; 2820 } 2821 } 2822 2823 2824 /* 2825 * Handler for IPMEV_GET_LOCAL_MEDIA_INFO events. 2826 */ 2827 void IpmDevice::onLocalMediaInfo( IPM_MEDIA_INFO* mediaInfo ) 2828 { 2829 LOGINFO("IpmDevice::onLocalMediaInfo() device: " << getDeviceName()); 2830 LOGDEBUG(std::endl << *mediaInfo); 2831 2832 for( unsigned int i = 0; i < mediaInfo->unCount; i++ ) 2833 { 2834 switch ( mediaInfo->MediaData[i].eMediaType ) 2835 { 2836 case MEDIATYPE_AUDIO_LOCAL_RTP_INFO: 2837 localMedia_.audioRtp.setAddress(mediaInfo->MediaData[i].mediaInfo.PortInfo.cIPAddress); 2838 localMedia_.audioRtp.setPort(mediaInfo->MediaData[i].mediaInfo.PortInfo.unPortId); 2839 break; 2840 2841 case MEDIATYPE_AUDIO_LOCAL_RTCP_INFO: 2842 localMedia_.audioRtcp.setAddress(mediaInfo->MediaData[i].mediaInfo.PortInfo.cIPAddress); 2843 localMedia_.audioRtcp.setPort(mediaInfo->MediaData[i].mediaInfo.PortInfo.unPortId); 2844 break; 2845 2846 case MEDIATYPE_VIDEO_LOCAL_RTP_INFO: 2847 localMedia_.videoRtp.setAddress(mediaInfo->MediaData[i].mediaInfo.PortInfo.cIPAddress); 2848 localMedia_.videoRtp.setPort(mediaInfo->MediaData[i].mediaInfo.PortInfo.unPortId); 2849 break; 2850 2851 case MEDIATYPE_VIDEO_LOCAL_RTCP_INFO: 2852 localMedia_.videoRtcp.setAddress(mediaInfo->MediaData[i].mediaInfo.PortInfo.cIPAddress); 2853 localMedia_.videoRtcp.setPort(mediaInfo->MediaData[i].mediaInfo.PortInfo.unPortId); 2854 break; 2855 2856 default: 2857 break; 2858 } 2859 } 2860 } 2861 2862 2863 /* 2864 * Handler for IPMEV_EVENT_ENABLED events. 2865 */ 2866 void IpmDevice::onEventEnabled() 2867 { 2868 LOGINFO("IpmDevice::onEventEnabled() device: " << getDeviceName()); 2869 2870 initStepsRemaining_--; 2871 if ( initStepsRemaining_ == 0 ) 2872 { 2873 state_ = IPM_IDLE; 2874 } 2875 } 2876 2877 2878 /* 2879 * Handler for IPMEV_STARTMEDIA events. 2880 */ 2881 void IpmDevice::onStartMedia() 2882 { 2883 LOGINFO("IpmDevice::onStartMedia() device: " << getDeviceName()); 2884 state_ = IPM_STREAMING; 2885 if ( ipt_ ) 2886 { 2887 ipt_->sendIFrameRequest(); 2888 } 2889 busy_ = false; 2890 processPendingCommand(); 2891 } 2892 2893 2894 /* 2895 * Handler for IPMEV_STOPPED events. 2896 */ 2897 void IpmDevice::onStopped() 2898 { 2899 LOGINFO("IpmDevice::onStopped() device: " << getDeviceName()); 2900 state_ = IPM_IDLE; 2901 busy_ = false; 2902 processPendingCommand(); 2903 } 2904 2905 2906 /* 2907 * Handler for IPMEV_LISTEN events. 2908 */ 2909 void IpmDevice::onListen() 2910 { 2911 LOGINFO("IpmDevice::onListen() device: " << getDeviceName()); 2912 busy_ = false; 2913 processPendingCommand(); 2914 } 2915 2916 2917 /* 2918 * Handler for IPMEV__UNLISTEN events. 2919 */ 2920 void IpmDevice::onUnListen() 2921 { 2922 LOGINFO("IpmDevice::onUnListen() device: " << getDeviceName()); 2923 busy_ = false; 2924 processPendingCommand(); 2925 } 2926 2927 2928 /* 2929 * Handler for DMEV_PORT_CONNECT events. 2930 */ 2931 void IpmDevice::onPortConnect() 2932 { 2933 LOGINFO("IpmDevice::onPortConnect() device: " << getDeviceName()); 2934 2935 if ( channel_ ) 2936 { 2937 channel_->onConnectCompleted(this); 2938 } 2939 2940 busy_ = false; 2941 if ( (state_ == IPM_STREAMING) && other_video_ ) 2942 { 2943 if ( ipt_ ) 2944 { 2945 ipt_->sendIFrameRequest(); 2946 } 2947 } 2948 processPendingCommand(); 2949 } 2950 2951 2952 /* 2953 * Handler for DMEV_PORT_CONNECT_FAIL events. 2954 */ 2955 void IpmDevice::onPortConnectFail() 2956 { 2957 LOGERROR("IpmDevice::onPortConnectFail() device: " << getDeviceName()); 2958 busy_ = false; 2959 processPendingCommand(); 2960 } 2961 2962 2963 /* 2964 * Handler for DMEV_PORT_DISCONNECT events. 2965 */ 2966 void IpmDevice::onPortDisconnect() 2967 { 2968 LOGINFO("IpmDevice::onPortDisconnect() device: " << getDeviceName()); 2969 2970 if ( channel_ ) 2971 { 2972 channel_->onDisconnectCompleted(this); 2973 } 2974 busy_ = false; 2975 processPendingCommand(); 2976 } 2977 2978 2979 /* 2980 * Handler for SMEV_ADD_OVERLAY events. 2981 */ 2982 void IpmDevice::onAddOverlay() 2983 { 2984 LOGINFO("IpmDevice::onOverlayAdd() device: " << getDeviceName()); 2985 2986 if ( overlay_ ) 2987 { 2988 void* evtContext = sr_getUserContext(); 2989 void* evtData = sr_getevtdatap(); 2990 overlay_->onOverlayAdd(evtData, evtContext); 2991 } 2992 if ( channel_ ) 2993 { 2994 channel_->onOverlayAdded(); 2995 } 2996 busy_ = false; 2997 generateIFrame(true); 2998 processPendingCommand(); 2999 } 3000 3001 3002 /* 3003 * Handler for SMEV_ADD_OVERLAY_FAIL events. 3004 */ 3005 void IpmDevice::onAddOverlayFail() 3006 { 3007 LOGERROR("IpmDevice::onAddOverlayFail() device: " << getDeviceName()); 3008 overlayActive_ = false; 3009 if ( channel_ ) 3010 { 3011 channel_->onOverlayAdded(); 3012 } 3013 busy_ = false; 3014 processPendingCommand(); 3015 } 3016 3017 3018 /* 3019 * Handler for SMEV_REMOVE_OVERLAY events. 3020 */ 3021 void IpmDevice::onRemoveOverlay() 3022 { 3023 LOGINFO("IpmDevice::onRemoveOverlay() device: " << getDeviceName()); 3024 3025 if ( overlay_ ) 3026 { 3027 void* evtContext = sr_getUserContext(); 3028 void* evtData = sr_getevtdatap(); 3029 overlay_->onOverlayRemove(evtData, evtContext); 3030 } 3031 if ( channel_ ) 3032 { 3033 channel_->onOverlayRemoved(); 3034 } 3035 overlayActive_ = false; 3036 busy_ = false; 3037 processPendingCommand(); 3038 } 3039 3040 3041 /* 3042 * Handler for SMEV_REMOVE_OVERLAY_FAIL events. 3043 */ 3044 void IpmDevice::onRemoveOverlayFail() 3045 { 3046 LOGERROR("IpmDevice::onRemoveOverlayFail() device: " << getDeviceName()); 3047 busy_ = false; 3048 if ( channel_ ) 3049 { 3050 channel_->onOverlayRemoved(); 3051 } 3052 processPendingCommand(); 3053 } 3054 3055 3056 /* 3057 * Handler for APP_IMAGEMAKER_OK events. 3058 */ 3059 void IpmDevice::onImageMaker( ImageMakerEvent* imageMakerEvent ) 3060 { 3061 std::stringstream ss; 3062 ss << ", filename: " << imageMakerEvent->filename; 3063 ss << ", height: " << imageMakerEvent->height; 3064 ss << ", width: " << imageMakerEvent->width; 3065 ss << ", top: " << imageMakerEvent->top; 3066 ss << ", left: " << imageMakerEvent->left; 3067 3068 LOGINFO("IpmDevice::onImageMaker() device: " << getDeviceName() << ss.str()); 3069 3070 OverlayInfo* overlayInfo = new OverlayInfo; 3071 3072 overlayInfo->direction = imageMakerEvent->direction; 3073 overlayInfo->imageFormat = eMTK_IMAGE_FORMAT_JPEG; 3074 overlayInfo->ovlTemplate = MTK_ERROR; 3075 overlayInfo->deviceOvlSnapshot = MTK_ERROR; 3076 overlayInfo->boundingFrameTemplate = MTK_ERROR; 3077 overlayInfo->framePosition_x = imageMakerEvent->left; 3078 overlayInfo->framePosition_y = imageMakerEvent->top; 3079 overlayInfo->positionType = eMTK_POSITION_TYPE_PIXEL; 3080 overlayInfo->frameWidth = imageMakerEvent->width; 3081 overlayInfo->frameHeight = imageMakerEvent->height; 3082 overlayInfo->sizeType = eMTK_SIZE_TYPE_PIXEL; 3083 overlayInfo->boundingSnapshot = MTK_ERROR; 3084 overlayInfo->duration_ms = imageMakerEvent->duration_ms; 3085 overlayInfo->imageHeight = 0; 3086 overlayInfo->imageWidth = 0; 3087 overlayInfo->imageName = imageMakerEvent->filename; 3088 3089 addOverlay(overlayInfo); 3090 } 3091 3092 3093 /* 3094 * Handler for APP_RTSP_EVENT events. Recode to common format and forward to 3095 * the channel. 3096 */ 3097 void IpmDevice::onRtsp( RtspEvent* rtsp_event ) 3098 { 3099 LOGINFO("IpmDevice::onRtsp() device: " << getDeviceName() << 3100 std::endl << *rtsp_event); 3101 3102 if ( channel_ ) 3103 { 3104 if ( rtsp_event->type == RTSP_EVT_OPEN_OK ) 3105 { 3106 std::string audio_encoding; 3107 switch ( rtsp_event->audio_codec ) 3108 { 3109 case RTSP_CODEC_NONE: 3110 break; 3111 case RTSP_CODEC_PCMU: 3112 audio_encoding = "pcmu"; 3113 break; 3114 case RTSP_CODEC_PCMA: 3115 audio_encoding = "pcma"; 3116 break; 3117 case RTSP_CODEC_AMR: 3118 audio_encoding = "amr"; 3119 break; 3120 case RTSP_CODEC_G726_32: 3121 audio_encoding = "g726-32"; 3122 break; 3123 case RTSP_CODEC_G722: 3124 audio_encoding = "g722"; 3125 break; 3126 case RTSP_CODEC_G729: 3127 audio_encoding = "g729"; 3128 break; 3129 case RTSP_CODEC_AMR_WB: 3130 audio_encoding = "amr-wb"; 3131 break; 3132 default: 3133 break; 3134 } 3135 const AudioCoderInfo* audioCoderInfo = channelMgr_.getCoders().getAudioCoder(audio_encoding); 3136 if ( audioCoderInfo ) 3137 { 3138 LOGDEBUG("IpmDevice::onRtsp() audio codec: \"" << audioCoderInfo->encoding << 3139 "\", device: " << getDeviceName()); 3140 remoteMedia_.audioCoder = *audioCoderInfo; 3141 remoteMedia_.audioCoder.coderPayloadType = rtsp_event->audio_payload_format; 3142 localMedia_.audioCoder = remoteMedia_.audioCoder; 3143 } 3144 else 3145 { 3146 if ( rtsp_event->audio_codec != RTSP_CODEC_NONE ) 3147 { 3148 LOGERROR("IpmDevice::onRtsp() unsupported audio codec: " << 3149 rtsp_event->audio_codec << ", device: " << getDeviceName()); 3150 } 3151 } 3152 3153 int width = 0; 3154 int height = 0; 3155 int fps = 0; 3156 3157 std::string video_encoding; 3158 switch ( rtsp_event->video_codec ) 3159 { 3160 case RTSP_CODEC_NONE: 3161 break; 3162 case RTSP_CODEC_H263: 3163 video_encoding = "h263"; 3164 break; 3165 case RTSP_CODEC_H263_1998: 3166 video_encoding = "h263-1998"; 3167 break; 3168 case RTSP_CODEC_H264: 3169 video_encoding = "h264"; 3170 break; 3171 case RTSP_CODEC_MP4VES: 3172 video_encoding = "mp4v-es"; 3173 break; 3174 default: 3175 LOGERROR("IpmDevice::onRtsp() unsupported video codec: " << 3176 rtsp_event->video_codec << ", device: " << getDeviceName()); 3177 break; 3178 } 3179 const VideoCoderInfo* videoCoderInfo = channelMgr_.getCoders().getVideoCoder(video_encoding); 3180 if ( videoCoderInfo ) 3181 { 3182 LOGDEBUG("IpmDevice::onRtsp() video codec: \"" << videoCoderInfo->encoding << 3183 "\", device: " << getDeviceName()); 3184 3185 remoteMedia_.videoCoder = *videoCoderInfo; 3186 remoteMedia_.videoCoder.coderPayloadType = rtsp_event->video_payload_format; 3187 3188 if ( (rtsp_event->video_codec == RTSP_CODEC_H263) || 3189 (rtsp_event->video_codec == RTSP_CODEC_H263_1998) ) 3190 { 3191 if ( (rtsp_event->width != 0) && 3192 (rtsp_event->height != 0) && 3193 (rtsp_event->fps != 0) ) 3194 { 3195 remoteMedia_.videoCoder.active_fmt.imageWidth = static_cast<eVIDEO_IMAGE_WIDTH>(rtsp_event->width); 3196 remoteMedia_.videoCoder.active_fmt.imageHeight = static_cast<eVIDEO_IMAGE_HEIGHT>(rtsp_event->height); 3197 remoteMedia_.videoCoder.active_fmt.framesPerSec = static_cast<eVIDEO_FRAMESPERSEC>(rtsp_event->fps); 3198 } 3199 } 3200 else if ( rtsp_event->video_codec == RTSP_CODEC_MP4VES ) 3201 { 3202 eVIDEO_PROFILE profile_level = static_cast<eVIDEO_PROFILE>(0); 3203 3204 if ( rtsp_event->profile_level_id == 0 ) 3205 { 3206 profile_level = VIDEO_PROFILE_LEVEL_SP0_MPEG4; 3207 } 3208 else if ( rtsp_event->profile_level_id == 1) 3209 { 3210 profile_level = VIDEO_PROFILE_LEVEL_SP1_MPEG4; 3211 } 3212 else if ( rtsp_event->profile_level_id == 2 ) 3213 { 3214 profile_level = VIDEO_PROFILE_LEVEL_SP2_MPEG4; 3215 } 3216 else if ( rtsp_event->profile_level_id == 3 ) 3217 { 3218 profile_level = VIDEO_PROFILE_LEVEL_SP3_MPEG4; 3219 } 3220 else 3221 { 3222 ; /* Force default */ 3223 } 3224 3225 std::vector<VideoCoderInfo::Fmt>::const_iterator i = remoteMedia_.videoCoder.available_fmts.begin(); 3226 for ( ; i != remoteMedia_.videoCoder.available_fmts.end(); ++i ) 3227 { 3228 if ( (*i).profile == profile_level ) 3229 { 3230 remoteMedia_.videoCoder.active_fmt.profile = (*i).profile; 3231 remoteMedia_.videoCoder.active_fmt.level = (*i).level; 3232 remoteMedia_.videoCoder.active_fmt.imageWidth = (*i).imageWidth; 3233 remoteMedia_.videoCoder.active_fmt.imageHeight = (*i).imageHeight; 3234 remoteMedia_.videoCoder.active_fmt.framesPerSec = (*i).framesPerSec; 3235 remoteMedia_.videoCoder.active_fmt.bitRate = (*i).bitRate; 3236 break; 3237 } 3238 } 3239 } 3240 else if ( rtsp_event->video_codec == RTSP_CODEC_H264 ) 3241 { 3242 bool h264_1B = (rtsp_event->profile_level_id >> 12) & 1; 3243 3244 eVIDEO_LEVEL level = static_cast<eVIDEO_LEVEL>(rtsp_event->profile_level_id & 0xFF); 3245 if ( (level == VIDEO_LEVEL_1_1_H264) && h264_1B ) 3246 { 3247 level = VIDEO_LEVEL_1_B_H264; 3248 } 3249 3250 std::vector<VideoCoderInfo::Fmt>::const_iterator i = remoteMedia_.videoCoder.available_fmts.begin(); 3251 for ( ; i != remoteMedia_.videoCoder.available_fmts.end(); ++i ) 3252 { 3253 if ( (*i).level == level ) 3254 { 3255 remoteMedia_.videoCoder.active_fmt.profile = (*i).profile; 3256 remoteMedia_.videoCoder.active_fmt.level = (*i).level; 3257 remoteMedia_.videoCoder.active_fmt.imageWidth = (*i).imageWidth; 3258 remoteMedia_.videoCoder.active_fmt.imageHeight = (*i).imageHeight; 3259 remoteMedia_.videoCoder.active_fmt.framesPerSec = (*i).framesPerSec; 3260 remoteMedia_.videoCoder.active_fmt.bitRate = (*i).bitRate; 3261 break; 3262 } 3263 } 3264 } 3265 3266 width = remoteMedia_.videoCoder.active_fmt.imageWidth; 3267 height = remoteMedia_.videoCoder.active_fmt.imageHeight; 3268 fps = remoteMedia_.videoCoder.active_fmt.framesPerSec; 3269 3270 localMedia_.videoCoder = remoteMedia_.videoCoder; 3271 localMedia_.videoCoder.active_fmt.visualConfiguration = rtsp_event->dci; 3272 } 3273 else 3274 { 3275 if ( rtsp_event->video_codec != RTSP_CODEC_NONE ) 3276 { 3277 LOGERROR("IpmDevice::onRtsp() unsupported video codec: " << 3278 rtsp_event->video_codec << ", device: " << getDeviceName()); 3279 } 3280 } 3281 3282 channel_->onRtspSession(rtsp_event->session_id, 3283 audio_encoding, 3284 video_encoding, 3285 width, 3286 height, 3287 fps); 3288 } 3289 else if ( rtsp_event->type == RTSP_EVT_OPEN_FAILED ) 3290 { 3291 channel_->onPlayFailed(this); 3292 } 3293 else if ( rtsp_event->type == RTSP_EVT_PLAY_OK ) 3294 { 3295 channel_->onPlayStarted(this); 3296 } 3297 else if ( rtsp_event->type == RTSP_EVT_PLAY_FAILED ) 3298 { 3299 channel_->onPlayCompleted(PLAY_ERROR, 0); 3300 } 3301 else if ( rtsp_event->type == RTSP_EVT_PLAY_COMPLETED ) 3302 { 3303 channel_->onPlayCompleted(PLAY_END_MEDIA, 0); 3304 } 3305 else if ( rtsp_event->type == RTSP_EVT_STOP_OK ) 3306 { 3307 channel_->onPlayCompleted(PLAY_STOPPED, 0); 3308 } 3309 else if ( rtsp_event->type == RTSP_EVT_STOP_FAILED ) 3310 { 3311 ; 3312 } 3313 } 3314 } 3315 3316 3317 /* vim:ts=4:set nu: 3318 * EOF 3319 */
| No admin address has been configured | ViewVC Help |
| Powered by ViewVC 1.0.8 |