[server] / trunk / server / src / ipmdevice.cxx Repository:
ViewVC logotype

View of /trunk/server/src/ipmdevice.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1218 - (download) (annotate)
Wed Jun 6 13:16:07 2012 UTC (11 months, 2 weeks ago) by jtarlton
File size: 94802 byte(s)
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