// 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; }