// RTPAudioSource.cpp: implementation of the RTPAudioSource class.
|
//
|
//////////////////////////////////////////////////////////////////////
|
|
#include "RTPPacket.h"
|
#include "RTPAudioSource.h"
|
#include "AudioSample.h"
|
#include "AudioSampleManager.h"
|
|
using namespace std;
|
|
//////////////////////////////////////////////////////////////////////
|
// Construction/Destruction
|
//////////////////////////////////////////////////////////////////////
|
|
RTPAudioSource::RTPAudioSource()
|
{
|
char subFacilityName[100];
|
sprintf(subFacilityName, "RTPAudioSource:%x", this);
|
tracer.SetSubFacilityName(subFacilityName);
|
SetTraceLevel();
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "Constructor begin\n");
|
rtpSocket = NULL;
|
rtcpSocket = NULL;
|
receivePort = 0;
|
boundReceivePort = 0;
|
mode = PASSIVE_MODE;
|
bRunning = false;
|
InitializeCriticalSection(&filterMutex);
|
WSADATA wsaData;
|
int result = WSAStartup(MAKEWORD(1,1), &wsaData);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "Constructor end : %d 0x%x\n", result, result);
|
}
|
|
RTPAudioSource::~RTPAudioSource()
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "Destructor begin\n");
|
int result(0);
|
result = CloseSockets();
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "RTPAudioSource~ : entered filterMutex\n");
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "RTPAudioSource~ : left filterMutex\n");
|
DeleteCriticalSection(&filterMutex);
|
result = WSACleanup();
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "Destructor end : %d 0x%x\n", result, result);
|
}
|
|
int
|
RTPAudioSource::SetTraceLevel()
|
{
|
long SystemMask = 0;
|
if ((SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "AllComponents", 0x0)) == 0)
|
{
|
SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "RTPAudioSource", 0x100000);
|
}
|
tracer.SetSystemMask(SystemMask);
|
return 0;
|
}
|
|
int
|
RTPAudioSource::PrepareSource()
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "PrepareSource\n");
|
int result(0);
|
int returnCode;
|
if (!rtpSocket)
|
{
|
do
|
{
|
returnCode = CreateSockets();
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "PrepareSource : e-CreateSockets : %d 0x%x\n", returnCode, returnCode);
|
result = -10;
|
break;
|
}
|
returnCode = SetReceivePort(receivePort);
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "PrepareSource : e-SetReceivePort : %d 0x%x\n", returnCode, returnCode);
|
result = -20;
|
break;
|
}
|
}
|
while (false);
|
}
|
if (result == 0 && rtpSocket)
|
{
|
/* while(true)
|
{
|
// clear up all packets in the socket's input queue
|
fd_set sdSet;
|
FD_ZERO(&sdSet);
|
FD_SET(rtpSocket, &sdSet);
|
timeval timeOut;
|
timeOut.tv_sec = 0;
|
timeOut.tv_usec = 0;
|
tracer.tracef(SDI_LEVEL_DETAILED, "PrepareSource : select\n");
|
select(0, &sdSet, NULL, NULL, &timeOut);
|
if (FD_ISSET(rtpSocket, &sdSet))
|
{
|
tracer.tracef(SDI_LEVEL_DETAILED, "PrepareSource : recv\n");
|
int bytesRead = recv(rtpSocket, receiveBuffer, RTPAUDIOSOURCE_RECEIVEBUFFER_SIZE, 0);
|
tracer.tracef(SDI_LEVEL_DETAILED, "PrepareSource : recv : got %d bytes\n", bytesRead);
|
if (bytesRead <= 0)
|
{
|
break;
|
}
|
}
|
else
|
{
|
break;
|
}
|
}
|
*/ }
|
SetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "ReceivePort", boundReceivePort);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~PrepareSource : returning %d\n", result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::UnprepareSource()
|
{
|
int result(0);
|
int returnCode(0);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "UnprepareSource\n");
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "UnprepareSource : entered filterMutex\n");
|
returnCode = CloseSockets();
|
if (returnCode != 0)
|
{
|
tracer.tracef(ERR, "UnprepareSource : e-CloseSocket : %d 0x%x\n", returnCode, returnCode);
|
result = -10;
|
}
|
SetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "ReceivePort", 0);
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "UnprepareSource : left filterMutex\n");
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~UnprepareSource : returning %d\n", result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::SourceStarted()
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceStarted\n");
|
int result(0);
|
int returnCode(0);
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceStarted : entered filterMutex\n");
|
do
|
{
|
if (bRunning)
|
{
|
tracer.tracef(ERR, "SourceStarted : e-error : already running\n");
|
result = -10;
|
break;
|
}
|
returnCode = PrepareSource();
|
if (returnCode != 0)
|
{
|
tracer.tracef(ERR, "SourceStarted : e-PrepareSource : %d 0x%x\n", returnCode, returnCode);
|
result = -20;
|
break;
|
}
|
bRunning = true;
|
}
|
while(false);
|
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceStarted : left filterMutex\n");
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceStarted : %d 0x%x\n", result, result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::SourceStopped()
|
{
|
int result(0);
|
int returnCode(0);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceStopped\n");
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceStopped : entered filterMutex\n");
|
do
|
{
|
if (!bRunning)
|
{
|
tracer.tracef(ERR, "SourceStopped : e-error : not running\n");
|
result = -10;
|
break;
|
}
|
returnCode = UnprepareSource();
|
if (returnCode != 0)
|
{
|
tracer.tracef(ERR, "SourceStopped : e-CloseSocket : %d 0x%x\n", result, result);
|
result = -20;
|
break;
|
}
|
bRunning = false;
|
mode = PASSIVE_MODE;
|
}
|
while (false);
|
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceStopped : left filterMutex\n");
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceStopped : %d 0x%x\n", result, result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::SourceThreadStarted(HANDLE sourceThreadHandle, DWORD sourceThreadID)
|
{
|
int returnCode(0);
|
int result(0);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceThreadStarted\n");
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceThreadStarted : entered filterMutex\n");
|
do
|
{
|
returnCode = SetThreadPriority(sourceThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
|
if (returnCode == 0)
|
{
|
returnCode = GetLastError();
|
tracer.tracef(ERR, "SourceThreadStarted : e-SetThreadPriority : %d 0x%x\n", returnCode, returnCode);
|
}
|
returnCode = PrepareSource();
|
if (returnCode != 0)
|
{
|
tracer.tracef(ERR, "SourceThreadStarted : e-PrepareSource : %d 0x%x\n", returnCode, returnCode);
|
result = -10;
|
break;
|
}
|
bRunning = true;
|
mode = ACTIVE_MODE;
|
}
|
while(false);
|
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceThreadStarted : left filterMutex\n");
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceThreadStarted : %d 0x%x\n", result, result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::SourceThreadStopped(HANDLE sourceThreadHandle, DWORD sourceThreadID)
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceThreadStopped\n");
|
int result(0);
|
int returnCode(0);
|
EnterCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceThreadStopped : entered filterMutex\n");
|
do
|
{
|
returnCode = UnprepareSource();
|
if (returnCode != 0)
|
{
|
tracer.tracef(ERR, "SourceStoppedThread : e-UnprepareSource : %d 0x%x\n", returnCode, returnCode);
|
result = -10;
|
break;
|
}
|
bRunning = false;
|
mode = PASSIVE_MODE;
|
}
|
while(false);
|
|
// begin - CSCdw85651 workaround : SoftPhone audio not heard in Conferene Connection
|
CreateSockets();
|
Sleep(250);
|
SetReceivePort(receivePort);
|
// end - CSCdw85651 workaround : SoftPhone audio not heard in Conferene Connection
|
|
LeaveCriticalSection(&filterMutex);
|
tracer.tracef(ARB, "SourceThreadStopped : left filterMutex\n");
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceThreadStopped : %d 0x%x\n", result, result);
|
return result;
|
}
|
|
int RTPAudioSource::BindSocketToPort(SOCKET sock, unsigned short port)
|
{
|
tracer.tracef(EE, "BindSocketToPort : socket = %d, port = %u\n", sock, port);
|
int returnValue(0);
|
int result(0);
|
sockaddr_in localSockAddr;
|
|
if (socket == 0)
|
{
|
tracer.tracef(ERR, "BindSocketToPort : invalid socket value %d\n", sock);
|
result = -10;
|
}
|
else
|
{
|
memset((char *)&localSockAddr, 0, sizeof(localSockAddr));
|
localSockAddr.sin_family = AF_INET;
|
localSockAddr.sin_port = htons(port);
|
localSockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
|
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "BindSocketToPort : calling bind\n");
|
returnValue = bind(sock, (sockaddr *)&localSockAddr, sizeof(localSockAddr));
|
if (returnValue != 0)
|
{
|
returnValue = WSAGetLastError();
|
tracer.tracef(ERR, "BindSocketToPort : e-bind : %d, 0x%x\n", returnValue, returnValue);
|
result = -20;
|
}
|
}
|
tracer.tracef(EE, "~BindSocketToPort : returning %d\n", result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::GetReceivePort(unsigned short *receivePort)
|
{
|
int result(0);
|
tracer.tracef(EE, "GetReceivePort\n");
|
*receivePort = boundReceivePort;
|
tracer.tracef(EE, "GetReceivePort : returning boundReceivePort = %u\n", boundReceivePort);
|
return 0;
|
}
|
|
int
|
RTPAudioSource::SetReceivePort(unsigned short receivePort)
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetReceivePort %u, boundReceivePort = %u\n", receivePort, boundReceivePort);
|
int result(0);
|
int returnValue(0);
|
bool needToBind = true;
|
this->receivePort = receivePort;
|
|
do
|
{
|
if(!rtpSocket || !rtcpSocket)
|
{
|
CloseSockets();
|
needToBind = true;
|
break;
|
}
|
if (boundReceivePort == receivePort && boundReceivePort != 0)
|
{
|
tracer.tracef(ARB, "SetAudioReceivePort : boundReceivePort == receivePort. Bind not needed\n");
|
needToBind = false;
|
break;
|
}
|
if (boundReceivePort != 0)
|
{
|
CloseSockets();
|
needToBind = true;
|
break;
|
}
|
needToBind = true;
|
}
|
while (false);
|
|
if (!rtpSocket || !rtcpSocket)
|
{
|
CreateSockets();
|
needToBind = true;
|
}
|
|
if (needToBind)
|
{
|
tracer.tracef(ARB, "SetReceivePort : binding RTP port\n");
|
returnValue = BindSocketToPort(rtpSocket, receivePort);
|
if (returnValue != 0)
|
{
|
tracer.tracef(ERR, "SetReceivePort : error binding RTP port ! Closing sockets\n");
|
CloseSockets();
|
result = -10;;
|
}
|
else
|
{
|
boundReceivePort = receivePort;
|
SetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "ReceivePort", boundReceivePort);
|
tracer.tracef(ARB, "SetReceivePort : binding RTCP port\n");
|
returnValue = BindSocketToPort(rtcpSocket, receivePort + 1);
|
if (returnValue != 0)
|
{
|
tracer.tracef(ERR, "SetReceivePort : error binding RCTP port ! ignoring\n");
|
}
|
}
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetReceivePort : %d 0x%x\n", result, result);
|
return result;
|
}
|
|
int
|
RTPAudioSource::CreateSockets()
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "CreateSockets\n");
|
int result(0);
|
|
if (rtpSocket || rtcpSocket)
|
{
|
result = CloseSockets();
|
}
|
|
rtpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
rtcpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (!rtpSocket || !rtcpSocket)
|
{
|
tracer.tracef(ERR, "CreateSockets : socket create error. rtpSocket = %d, rtcpSocket = %d\n", rtpSocket, rtcpSocket);
|
}
|
|
/* LINGER linger;
|
linger.l_onoff = 1;
|
linger.l_linger = 0;
|
BOOL dontLinger = 0;
|
int sockoptValue = setsockopt(rtpSocket, SOL_SOCKET, SO_DONTLINGER, (char *)(&dontLinger), sizeof(BOOL));
|
if (sockoptValue != 0)
|
{
|
sockoptValue = WSAGetLastError();
|
tracer.tracef(SIG, "CreateSockets : e-setsockopt : %d\n", sockoptValue);
|
}
|
*/
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~CreateSockets : %d 0x%x. rtpSocket = %d, rtcpSocket = %d\n", result, result, rtpSocket, rtcpSocket);
|
return result;
|
}
|
|
int
|
RTPAudioSource::CloseSockets()
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "CloseSockets\n");
|
int result(0);
|
int returnValue(0);
|
if (rtpSocket)
|
{
|
tracer.tracef(ARB, "CloseSockets : Closing RTP socket\n");
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "CloseSockets : calling shutdown\n");
|
returnValue = shutdown(rtpSocket, 0); // SD_RECEIVE = 0, SD_SEND = 1, SD_BOTH = 2
|
if (returnValue != 0)
|
{
|
returnValue = WSAGetLastError();
|
tracer.tracef(ERR, "CloseSockets : e-shutdown : %d 0x%x\n", returnValue, returnValue);
|
}
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "CloseSockets : calling closesocket\n");
|
returnValue = closesocket(rtpSocket);
|
if (returnValue != 0)
|
{
|
returnValue = WSAGetLastError();
|
tracer.tracef(ERR, "CloseSockets : e-closesocket : %d 0x%x\n", returnValue, returnValue);
|
result = -20;
|
}
|
rtpSocket = 0;
|
}
|
boundReceivePort = 0;
|
|
if (rtcpSocket)
|
{
|
tracer.tracef(ARB, "CloseSockets : Closing RTCP socket\n");
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "CloseSockets : calling shutdown\n");
|
returnValue = shutdown(rtcpSocket, 0); // SD_RECEIVE = 0, SD_SEND = 1, SD_BOTH = 2
|
if (returnValue != 0)
|
{
|
returnValue = WSAGetLastError();
|
tracer.tracef(ERR, "CloseSockets : e-shutdown : %d 0x%x\n", returnValue, returnValue);
|
}
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "CloseSockets : calling closesocket\n");
|
returnValue = closesocket(rtcpSocket);
|
if (returnValue != 0)
|
{
|
returnValue = WSAGetLastError();
|
tracer.tracef(ERR, "CloseSockets : e-closesocket : %d 0x%x\n", returnValue, returnValue);
|
}
|
rtcpSocket = 0;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~CloseSockets : %d 0x%x. rtpSocket = %d, rtcpSocket = %d\n", result, result, rtpSocket, rtcpSocket);
|
return result;
|
}
|
|
int
|
RTPAudioSource::ReceiveUDPPacket()
|
{
|
int result(0);
|
if (bRunning && rtpSocket)
|
{
|
if (mode == ACTIVE_MODE)
|
{
|
// then this filter drives timing. so wait for packets
|
tracer.tracef(SDI_LEVEL_DETAILED, "ReceiveUDPPacket : recv : active\n");
|
result = recv(rtpSocket, receiveBuffer, RTPAUDIOSOURCE_RECEIVEBUFFER_SIZE, 0);
|
}
|
else
|
{
|
// passive mode means other filter somewhere is driving timing. in that case
|
// do not delay. return immediately if there are no packets
|
result = 0;
|
fd_set sdSet;
|
FD_ZERO(&sdSet);
|
FD_SET(rtpSocket, &sdSet);
|
timeval timeOut;
|
timeOut.tv_sec = 0;
|
timeOut.tv_usec = 0;
|
tracer.tracef(SDI_LEVEL_DETAILED, "ReceiveUDPPacket : select\n");
|
select(0, &sdSet, NULL, NULL, &timeOut);
|
if (FD_ISSET(rtpSocket, &sdSet))
|
{
|
tracer.tracef(SDI_LEVEL_DETAILED, "ReceiveUDPPacket : recv : inactive\n");
|
result = recv(rtpSocket, receiveBuffer, RTPAUDIOSOURCE_RECEIVEBUFFER_SIZE, 0);
|
}
|
}
|
}
|
else
|
{
|
tracer.tracef(ERR, "ReceiveUDPPacket : bRunning = %d, rtpSocket = %d\n", bRunning, rtpSocket);
|
result = -10;
|
}
|
return result;
|
}
|
|
int
|
RTPAudioSource::GenerateData(AudioSample **ppAudioSample)
|
{
|
tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData\n");
|
int result(0);
|
int recvResult(0);
|
AudioSample *audioSample = NULL;
|
*ppAudioSample = NULL;
|
result = (AudioSampleManager::GetInstance())->GetAudioSample(&audioSample, this);
|
if (audioSample)
|
{
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1));
|
audioSample->SetSilenceDuration(20);
|
audioSample->SetDataSize(0);
|
|
while (true)
|
{
|
recvResult = ReceiveUDPPacket();
|
tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : ReceiveUDPPacket : %d\n", recvResult);
|
if (recvResult > 0)
|
{
|
// actual bytes received
|
RTPPacket *rtpPacket = RTPPacket::CreateRTPPacket(receiveBuffer, recvResult, &tracer);
|
if (rtpPacket)
|
{
|
tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : memcpy(0x%x, 0x%x, %d)\n", audioSample->Data(), rtpPacket->RtpData(), rtpPacket->DataLen());
|
memcpy(audioSample->Data(), rtpPacket->RtpData(), rtpPacket->DataLen());
|
audioSample->SetDataSize(rtpPacket->DataLen());
|
audioSample->SetSilenceDuration(0);
|
audioSample->SetRTPHeader(rtpPacket);
|
switch(rtpPacket->PayloadType())
|
{
|
case RTP_PAYLOADTYPE_G711_ULAW:
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_ULaw));
|
break;
|
case RTP_PAYLOADTYPE_G711_ALAW:
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_ALaw));
|
break;
|
case RTP_PAYLOADTYPE_G723:
|
if (rtpPacket->DataLen() % 20 == 0)
|
{
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_G723_53));
|
}
|
else
|
{
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_G723_63));
|
}
|
break;
|
case RTP_PAYLOADTYPE_G729:
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_G729));
|
break;
|
case RTP_PAYLOADTYPE_SID:
|
audioSample->SetFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1));
|
audioSample->SetDataSize(0);
|
audioSample->SetSilenceDuration(20);
|
break;
|
default:
|
tracer.tracef(ERR, "GenerateData : rtpPacket has invalid PAYLOAD_TYPE %d\n", rtpPacket->PayloadType());
|
continue;
|
}
|
}
|
else
|
{
|
tracer.tracef(SDI_LEVEL_ERROR, "GenerateData : invalid RTP Packet\n");
|
continue;
|
}
|
break;
|
}
|
else
|
{
|
tracer.tracef(ERR, "GenerateData : socket error or socket closed ! recv returned value %d <= 0\n", recvResult);
|
result = -10;
|
audioSample->Release(this);
|
audioSample = NULL;
|
break;
|
}
|
}
|
}
|
else
|
{
|
result = -20;
|
tracer.tracef(ERR, "GenerateData : could not get audioSample. Returning error %d\n", result);
|
}
|
|
if (result != 0)
|
{
|
if (audioSample)
|
{
|
audioSample->Release(this);
|
audioSample = NULL;
|
}
|
}
|
*ppAudioSample = audioSample;
|
if (result == 0)
|
{
|
tracer.tracef(SDI_LEVEL_DETAILED, "~GenerateData : %d bytes: 0x%x\n", recvResult, *ppAudioSample);
|
}
|
else
|
{
|
tracer.tracef(ERR, "~GenerateData : %d : 0x%x\n", result, *ppAudioSample);
|
}
|
return result;
|
}
|