/* * This file is part of Dialogic Woomera Server project. * * More information about this project can be found at: * http://www.opendialogic.org. * * Copyright (C) 2009 Dialogic Corp. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * Alternatively see . * Or see the LICENSE file included within the source tree. * */ /*! * \file ipmdevice.cxx * \brief Dialogic IPM device * \author Antony Martin * \author John Tarlton * \version 2-APR-2009 */ /*------------------------------ Dependencies --------------------------------*/ #include "logger.h" #include "string-util.h" #include "ipmdevice.h" /*----------------------------------------------------------------------------*/ /* * ctor */ IpmDevice::IpmDevice( const std::string& name, DialogicChannelManager& channelMgr ) : DialogicDevice(name, channelMgr) { memset(&localMediaInfo_, 0, sizeof(IPM_MEDIA_INFO)); /* Number of steps in the initialisation sequence, decremented by event * handlers. When zero state is changed to IDLE. * * IPMEV_OPEN, * DMEV_GET_RX_PORT_INFO, * DMEV_GET_TX_PORT_INFO */ initStepsRemaining_ = 3; } /* * dtor */ IpmDevice::~IpmDevice() { } /* * Open the device. */ bool IpmDevice::open() { LOGDEBUG("IpmDevice::open() device: " << devName_); devHandle_ = ipm_Open(devName_.c_str(), NULL, EV_ASYNC); if ( devHandle_ < 0 ) { LOGERROR("ipm_Open() failed"); return false; } state_ = IPM_OPENING; return true; } /* * Close the device */ bool IpmDevice::close() { LOGDEBUG("IpmDevice::close() device: " << devName_); if ( devHandle_ > 0 ) { if ( ipm_Close(devHandle_, NULL) < 0 ) { LOGERROR("ipm_Close() failed"); return false; } devHandle_ = 0; } return true; } /* * Connect media. */ bool IpmDevice::listen( DialogicDevice* other ) { if ( listening_ != other ) { LOGDEBUG("IpmDevice::listen() device: " << devName_ << " other: " << other->getDeviceName()); SC_TSINFO tsinfo; tsinfo.sc_numts = 1; tsinfo.sc_tsarrayp = other->getXmitTimeslotPtr(); if ( ipm_Listen(devHandle_, &tsinfo, EV_ASYNC) == -1 ) { LOGERROR("ipm_Listen() failed on device: " << devName_ << " " << ATDV_ERRMSGP(devHandle_)); return false; } listening_ = other; } return true; } /* * Disconnect media. */ bool IpmDevice::unListen() { if ( listening_ ) { LOGDEBUG("IpmDevice::unListen() device: " << devName_); if ( ipm_UnListen(devHandle_, EV_ASYNC) == -1) { LOGERROR("ipm_UnListen() failed on device: " << devName_ << " " << ATDV_ERRMSGP(devHandle_)); return false; } listening_ = 0; } return true; } /* * Search localMediaInfo_ for the requested information. */ void IpmDevice::getLocalMediaInfo( eIPM_MEDIA_TYPE type, IpInfo& rtp_media ) const { for ( unsigned int i = 0; i < localMediaInfo_.unCount; i++ ) { if ( type == localMediaInfo_.MediaData[i].eMediaType ) { rtp_media.setAddress(localMediaInfo_.MediaData[i].mediaInfo.PortInfo.cIPAddress); rtp_media.setPort(localMediaInfo_.MediaData[i].mediaInfo.PortInfo.unPortId); break; } } } /* * Save the remote params. */ void IpmDevice::setRemoteMediaInfo( eIPM_MEDIA_TYPE type, const IpInfo& rtp_info ) { if ( type == MEDIATYPE_AUDIO_LOCAL_RTP_INFO ) { remoteRtpAudio_ = rtp_info; remoteRtcpAudio_ = rtp_info; remoteRtcpAudio_.setPort(remoteRtpAudio_.getPort() + 1); } } /* * Stop the IPM streaming and/or digit reception */ bool IpmDevice::stop( eIPM_STOP_OPERATION operation ) { if ( state_ == IPM_IDLE ) { return true; /* already stopped */ } if ( ipm_Stop(devHandle_, operation, EV_ASYNC) == -1 ) { LOGERROR("ipm_Stop() on device: " << devName_ << " failed: " << ATDV_LASTERR(devHandle_)); return false; } state_ = IPM_STOPPING; return true; } /* * Start RTP streaming to peer. */ bool IpmDevice::startMedia() { return startMedia(remoteRtpAudio_, remoteRtcpAudio_); } /* * Start RTP streaming using G.711ulaw and local/remote port information. * XXX ulaw/alaw from config */ bool IpmDevice::startMedia( const IpInfo& remote_rtp_audio, const IpInfo& remote_rtcp_audio ) { if ( state_ != IPM_IDLE ) { if ( (state_ == IPM_STARTING) || (state_ == IPM_STREAMING) ) { return true; /* already started */ } LOGERROR("IpmDevice::startMedia() device: " << devName_ << " invalid state: " << state_); return false; } IPM_MEDIA_INFO mediaInfo; memset(&mediaInfo, 0, sizeof(IPM_MEDIA_INFO)); int mediaCnt = 0; /* limit MAX_MEDIA_INFO */ /* remote audio */ mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_CODER_INFO; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eCoderType = CODER_TYPE_G711ULAW64K; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eFrameSize = CODER_FRAMESIZE_20; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unFramesPerPkt = 1; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eVadEnable = CODER_VAD_ENABLE; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unCoderPayloadType = 0; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unRedPayloadType = 0; mediaCnt++; /* local audio */ mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_LOCAL_CODER_INFO; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eCoderType = CODER_TYPE_G711ULAW64K; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eFrameSize = CODER_FRAMESIZE_20; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unFramesPerPkt = 1; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.eVadEnable = CODER_VAD_ENABLE; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unCoderPayloadType = 0; mediaInfo.MediaData[mediaCnt].mediaInfo.CoderInfo.unRedPayloadType = 0; mediaCnt++; /* remote audio ports and IP addresses */ mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_RTP_INFO; copy_string_to_c_array(remote_rtp_audio.getAddress(), mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, IP_ADDR_SIZE); mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_rtp_audio.getPort(); mediaCnt++; mediaInfo.MediaData[mediaCnt].eMediaType = MEDIATYPE_AUDIO_REMOTE_RTCP_INFO; copy_string_to_c_array(remote_rtcp_audio.getAddress(), mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.cIPAddress, IP_ADDR_SIZE); mediaInfo.MediaData[mediaCnt].mediaInfo.PortInfo.unPortId = remote_rtcp_audio.getPort(); mediaCnt++; mediaInfo.unCount = mediaCnt; LOGDEBUG("IpmDevice::startMedia() starting RTP streaming on device: " << devName_ << " remote_rtp_audio: " << remote_rtp_audio << " remote_rtcp_audio: " << remote_rtcp_audio); if ( ipm_StartMedia(devHandle_, &mediaInfo, DATA_IP_TDM_BIDIRECTIONAL, EV_ASYNC) == -1 ) { LOGERROR("ipm_StartMedia failed for device: " << devName_ << " with error: " << ATDV_ERRMSGP(devHandle_)); return false; } state_ = IPM_STARTING; return true; } /* * Forward to event specific handler. */ bool IpmDevice::processEvent( METAEVENT& metaevent ) { switch ( metaevent.evttype ) { case IPMEV_OPEN: onOpen(); break; case IPMEV_EVENT_ENABLED: onEventEnabled(); break; case IPMEV_GET_LOCAL_MEDIA_INFO: onLocalMediaInfo((IPM_MEDIA_INFO*)sr_getevtdatap()); break; case IPMEV_STARTMEDIA: onStartMedia(); break; case IPMEV_STOPPED: onStopped(); break; case IPMEV_LISTEN: onListen(); break; case IPMEV_UNLISTEN: onUnListen(); break; case IPMEV_ERROR: onError(); break; case DMEV_GET_TX_PORT_INFO: onGetTxPortInfo((DM_PORT_INFO_LIST*)sr_getevtdatap()); break; case DMEV_GET_RX_PORT_INFO: onGetRxPortInfo((DM_PORT_INFO_LIST*)sr_getevtdatap()); break; case DMEV_GET_TX_PORT_INFO_FAIL: onPortGetFail(); break; case DMEV_GET_RX_PORT_INFO_FAIL: onPortGetFail(); break; case DMEV_PORT_CONNECT: onPortConnect(); break; default: LOGWARN("IpmDevice::processEvent() unhandled event: 0x" << std::hex << metaevent.evttype << " for device: " << devName_); return false; } return true; } /* * Handler for IPMEV_OPEN events. */ void IpmDevice::onOpen() { LOGINFO("IpmDevice::onOpen() device: " << devName_); listening_ = 0; /* Get and save the transmit timeslot on CTBus */ SC_TSINFO tsinfo; tsinfo.sc_numts = 1; tsinfo.sc_tsarrayp = getXmitTimeslotPtr(); if ( ipm_GetXmitSlot(devHandle_, &tsinfo, EV_SYNC) == -1 ) { LOGERROR("ipm_GetXmitSlot() failed" ); } /* Request port info */ if ( dev_GetTransmitPortInfo(devHandle_, this) == -1 ) { LOGERROR("dev_GetTransmitPortInfo() failed"); } if ( dev_GetReceivePortInfo(devHandle_, this) == -1 ) { LOGERROR("dev_GetReceivePortInfo() failed"); } /* Request the local media information and save it in localMediaInfo_ */ localMediaInfo_.unCount = 3; localMediaInfo_.MediaData[0].eMediaType = MEDIATYPE_AUDIO_LOCAL_RTP_INFO; localMediaInfo_.MediaData[1].eMediaType = MEDIATYPE_VIDEO_LOCAL_RTP_INFO; localMediaInfo_.MediaData[2].eMediaType = MEDIATYPE_NBUP_LOCAL_RTP_INFO; if ( ipm_GetLocalMediaInfo (devHandle_, &localMediaInfo_, EV_ASYNC) == -1 ) { LOGERROR("ipm_GetLocalMediaInfo() failed for device: " << devName_ << " with error: " << ATDV_LASTERR(devHandle_)); } /* update init state */ state_ = IPM_INITIALIZATION_START; initStepsRemaining_--; if ( initStepsRemaining_ == 0 ) { state_ = IPM_IDLE; } } /* * Handler for DMEV_GET_TX_PORT_INFO events. */ void IpmDevice::onGetTxPortInfo( DM_PORT_INFO_LIST* portInfo ) { LOGINFO("IpmDevice::onGetTxPortInfo() device: " << devName_); memcpy(&txPortInfoList_, portInfo, sizeof(DM_PORT_INFO_LIST)); printPortInfo(portInfo); initStepsRemaining_--; if ( initStepsRemaining_ == 0 ) { state_ = IPM_IDLE; } } /* * Handler for DMEV_GET_RX_PORT_INFO events. */ void IpmDevice::onGetRxPortInfo( DM_PORT_INFO_LIST* portInfo ) { LOGINFO("IpmDevice::onGetRxPortInfo() device: " << devName_); memcpy(&rxPortInfoList_, portInfo, sizeof(DM_PORT_INFO_LIST)); printPortInfo(portInfo); initStepsRemaining_--; if ( initStepsRemaining_ == 0 ) { state_ = IPM_IDLE; } } /* * Handler for DMEV_PORT_CONNECT events. */ void IpmDevice::onPortConnect() { LOGINFO("IpmDevice::onPortConnect() device: " << devName_); } /* * Handler for DMEV_GET_TX_PORT_INFO_FAIL and DMEV_GET_RX_PORT_INFO_FAIL * events. */ void IpmDevice::onPortGetFail() { LOGINFO("IpmDevice::onPortGetFail() device: " << devName_); state_ = IPM_INVALID; } /* * Handler for IPMEV_ERROR events. */ void IpmDevice::onError() { LOGERROR("IpmDevice::onError() device: " << devName_ << " error: " << ATDV_ERRMSGP(devHandle_)); state_ = IPM_INVALID; } /* * Handler for IPMEV_EVENT_ENABLED events */ void IpmDevice::onEventEnabled() { LOGINFO("IpmDevice::onEventEnabled() device: " << devName_); initStepsRemaining_--; if ( initStepsRemaining_ == 0 ) { state_ = IPM_IDLE; } } /* * Handler for IPMEV_STARTMEDIA events. */ void IpmDevice::onStartMedia() { LOGINFO("IpmDevice::onStartMedia() device: " << devName_); state_ = IPM_STREAMING; } /* * Handler for IPMEV_STOPPED events. */ void IpmDevice::onStopped() { LOGINFO("IpmDevice::onStopped() device: " << devName_); state_ = IPM_IDLE; } /* * Handler for IPMEV_GET_LOCAL_MEDIA_INFO events. */ void IpmDevice::onLocalMediaInfo( IPM_MEDIA_INFO* mediaInfo ) { LOGINFO("IpmDevice::onLocalMediaInfo() device: " << devName_); memcpy(&localMediaInfo_, mediaInfo, sizeof(IPM_MEDIA_INFO)); printMediaInfo(&localMediaInfo_); } /* * Handler for IPMEV_LISTEN events. */ void IpmDevice::onListen() { LOGINFO("IpmDevice::onListen() device: " << devName_); } /* * Handler for IPMEV__UNLISTEN events. */ void IpmDevice::onUnListen() { LOGINFO("IpmDevice::onUnListen() device: " << devName_); } /* * Debug aid. */ void IpmDevice::printPortInfo( DM_PORT_INFO_LIST* portInfo ) const { std::stringstream ss; for ( unsigned int i = 0; i < portInfo->unCount; i++ ) { DM_PORT_INFO& info = portInfo->port_info[i]; ss << "Port: " << i << " MediaType: " << info.port_media_type << " "; if ( info.port_media_type == DM_PORT_MEDIA_TYPE_AUDIO ) { ss << "Audio"; } else if ( info.port_media_type == DM_PORT_MEDIA_TYPE_VIDEO ) { ss << "Video"; } else if ( info.port_media_type == DM_PORT_MEDIA_TYPE_NBUP ) { ss << "NBUP"; } else { ss << info.port_media_type; } ss << std::endl; } LOGDEBUG(ss.str()); } /* * Debug aid */ void IpmDevice::printMediaInfo( IPM_MEDIA_INFO* mediaInfo ) const { std::stringstream ss; for ( unsigned int i = 0; i < mediaInfo->unCount; i++ ) { ss << "MediaType = "; switch ( mediaInfo->MediaData[i].eMediaType ) { case MEDIATYPE_VIDEO_LOCAL_RTP_INFO: ss << "MEDIATYPE_VIDEO_LOCAL_RTP_INFO"; break; case MEDIATYPE_VIDEO_LOCAL_RTCP_INFO: ss << "MEDIATYPE_VIDEO_LOCAL_RTCP_INFO"; break; case MEDIATYPE_AUDIO_LOCAL_RTP_INFO: ss << "MEDIATYPE_AUDIO_LOCAL_RTP_INFO"; break; case MEDIATYPE_AUDIO_LOCAL_RTCP_INFO: ss << "MEDIATYPE_AUDIO_LOCAL_RTCP_INFO"; break; case MEDIATYPE_NBUP_LOCAL_RTP_INFO: ss << "MEDIATYPE_NBUP_LOCAL_RTP_INFO"; break; default: ss << "MEDIATYPE_??? " << mediaInfo->MediaData[i].eMediaType; break; } ss << " IP = " << mediaInfo->MediaData[i].mediaInfo.PortInfo.cIPAddress; ss << " Port = " << mediaInfo->MediaData[i].mediaInfo.PortInfo.unPortId; ss << std::endl; } LOGDEBUG(ss.str()); } /* vim:ts=4:set nu: * EOF */