/*
* 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
*/