rtpaudiosink.cxx

来自「rtp在linux下的实现」· CXX 代码 · 共 502 行

CXX
502
字号
// RTPAudioSink.cpp: implementation of the RTPAudioSink class.
//
//////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include "RTPPacket.h"
#include "RTPAudioSink.h"
#include "AudioSample.h"

#ifndef WIN32
#include "NetworkAddress.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#endif

using namespace std;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

RTPAudioSink::RTPAudioSink()
{
	char subFacilityName[100];
	sprintf(subFacilityName, "RTPAudioSink:%x", this);
	tracer.SetSubFacilityName(subFacilityName);
	SetTraceLevel();
	tracer.tracef(EE, "Constructor begin\n");
	rtpSocket = NULL;
	destinationIP = 0;
	destinationIPString = "127.0.0.1";
	destinationPort = 0;
	localPort = 0;
	tos = 0;
	bRunning = false;
	InitializeCriticalSection(&filterMutex);
#ifdef WIN32
	WSADATA wsaData;
	int result = WSAStartup(MAKEWORD(1,1), &wsaData);
	tracer.tracef(EE, "Constructor end : 0x%x\n", result);
#endif
}

RTPAudioSink::~RTPAudioSink()
{
	tracer.tracef(EE, "Destructor begin\n");
	int result(0);
	EnterCriticalSection(&filterMutex);
	tracer.tracef(ARB, "RTPAudioSink~ : entered filterMutex\n");
	LeaveCriticalSection(&filterMutex);
	tracer.tracef(ARB, "RTPAudioSink~ : left filterMutex\n");
	result = CloseSocket();
#ifdef WIn32
	result = WSACleanup();
	DeleteCriticalSection(&filterMutex);
#endif
	tracer.tracef(EE, "Destructor end : 0x%x\n", result);
}

int
RTPAudioSink::SetTraceLevel()
{
#ifdef WIN32
	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", "RTPAudioSink", 0x100000);
	}
	tracer.SetSystemMask(SystemMask);
#endif
	return 0;
}

int
RTPAudioSink::SetDestination(std::string ipAddress, unsigned short udpPort)
{
	tracer.tracef(EE, "SetDestination %s %u\n", ipAddress.c_str(), udpPort);
	int result = 0;
	destinationIPString = ipAddress;
	destinationPort = udpPort;

#ifdef WIN32
        destinationIP = inet_addr(ipAddress.c_str());
#else
        NetworkAddress na(ipAddress.c_str());
        destinationIP  = na.getIp4Address();
#endif

	if (!rtpSocket)
	{
		int result = CreateSocket();
	}
	if (result == 0)
	{
		sockaddr_in destinationAddr;
		memset((char *)&destinationAddr, 0, sizeof(destinationAddr));
		destinationAddr.sin_family = AF_INET;
		destinationAddr.sin_port = htons(destinationPort);

#ifdef WIN32
		destinationAddr.sin_addr.S_un.S_addr = destinationIP;
                fcntl( rtpSocket, F_SETFL, O_NDELAY);
		result = connect(rtpSocket, (sockaddr *)&destinationAddr, sizeof(destinationAddr));
		tracer.tracef(EE, "~SetDestination : %d 0x%x\n", result, result);
#else
                destinationAddr.sin_addr.s_addr = destinationIP;
		result = connect(rtpSocket, (sockaddr *)&destinationAddr, sizeof(destinationAddr));
#endif
	}
	return result;
}

int
RTPAudioSink::SetTOS(unsigned char tosByte)
{
	tracer.tracef(EE, "SetTOS 0x%x\n", tosByte);
	int result = 0;
#ifdef WIN32
	tos = tosByte;
	int tosValueInt = (int)tos;
	int tosLen = sizeof(int);
	if (rtpSocket)
	{
		tracer.tracef(SDI_LEVEL_ARBITRARY, "SetTOS : setsockopt\n");
		result = setsockopt(rtpSocket, IPPROTO_IP, IP_TOS, (char *)&tosValueInt, tosLen);
		if (result != 0)
		{
			result = WSAGetLastError();
			tracer.tracef(ERR, "SetTOS : e-setsockopt 0x%x\n", result);
		}
	}
	tracer.tracef(EE, "~SetTOS : %d 0x%x\n", result, result);
#endif
	return result;
}

int
RTPAudioSink::SetLocalPort(unsigned short port)
{
	tracer.tracef(EE, "SetLocalPort %u : localPort %u\n", port, localPort);
	int result(0);
	if (localPort != port)
	{
		localPort = port;
		if (rtpSocket)
		{
			result = CloseSocket();
			if (result == 0)
			{
				result = CreateSocket();
				if (result == 0)
				{
					result = SetDestination(destinationIPString, destinationPort);
				}
			}
		}
	}
	tracer.tracef(EE, "~SetLocalPort : %d 0x%x\n", result, result);
	return result;
}

int
RTPAudioSink::CreateSocket()
{
	tracer.tracef(EE, "CreateSocket\n"); 
	int result;

	if (rtpSocket)
	{
		result = CloseSocket();
	}

	rtpSocket = socket(AF_INET, SOCK_DGRAM, 0);

	sockaddr_in localSockAddr;
	memset((char *)&localSockAddr, 0, sizeof(localSockAddr));
	localSockAddr.sin_family = AF_INET;
	localSockAddr.sin_port = htons(localPort);
#ifdef WIN32
	localSockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	result = bind(rtpSocket, (sockaddr *)&localSockAddr, sizeof(localSockAddr));
	if (result != 0)
	{
		result = WSAGetLastError();
		tracer.tracef(ERR, "CreateSocket : e-bind : 0x%x\n", result);
	}
	result = setsockopt(rtpSocket, IPPROTO_IP, IP_TOS, (char *)&tos, 1);
	if (result != 0)
	{
		result = WSAGetLastError();
		tracer.tracef(ERR, "CreateSocket : e-setsockopt : 0x%x\n", result);
	}
#else
	localSockAddr.sin_addr.s_addr = INADDR_ANY;
	result = bind(rtpSocket, (sockaddr *)&localSockAddr, sizeof(localSockAddr));
        if(result != 0)
        {
        	tracer.tracef(ERR, "CreateSocket : failed : %s\n", strerror(errno));
        }
#endif
	tracer.tracef(EE, "~CreateSocket : %d 0x%x\n", result, result);
	return result;
}


int
RTPAudioSink::CloseSocket()
{
	tracer.tracef(EE, "CloseSocket\n");
	int result(0);
	if (rtpSocket)
	{
#ifdef WIN32
		tracer.tracef(ARB, "CloseSocket : closesocket\n");
		result = closesocket(rtpSocket);
		if (result != 0)
		{
			tracer.tracef(ERR, "CloseSocket : e-closesocket : 0x%x\n", WSAGetLastError());
			result = -10;
		}
#else
                close(rtpSocket);
#endif
	}
	rtpSocket = NULL;
	tracer.tracef(EE, "~CloseSocket : %d 0x%x\n", result, result);
	return 0;
}

int
RTPAudioSink::RenderAudioSamples(std::vector<std::pair<AudioSample*, AudioSource* > > &data)
{
	tracer.tracef(DET, "RenderAudioSamples\n");
        if(data.size() == 0)
        {
             tracer.tracef(DET, "No data to render\n");
             return 0;
        }
	AudioSample *sample = data[0].first;
	int dataSize = 0;
	int durationMillisec;

	char RTPPayloadType;
	bool transmitPacket = false;	// whether a packet will be transmitted
	bool setMarkerBit = false;

	int numBytes = sample->DataSize();
	durationMillisec = sample->GetDuration();
	if (durationMillisec <= 0)
	{
		durationMillisec = sample->GetSilenceDuration();
	}
	tracer.tracef(DET, "RenderAudioSamples : durationMillisec = %d\n", durationMillisec);

	timestamp += durationMillisec * 8;
	seqno = (seqno + 1) % 65536;

	if (numBytes > 0)
	{
		transmitPacket = true;
		setMarkerBit = silenceInterval;
		silenceInterval = false;

		tracer.tracef(DET, "RenderAudioSamples : memcpy(0x%x, 0x%x, %d)\n", sendBuffer+12, sample->Data(), sample->DataSize());
		memcpy(sendBuffer+12, sample->Data(), sample->DataSize());
		dataSize = 12 + sample->DataSize();

		WAVEFORMATEX wfx;
		sample->GetFormat(&wfx);
		switch(wfx.wFormatTag) 
		{
		case WAVE_FORMAT_MULAW		:	RTPPayloadType	= 0x00;
										break;
		case WAVE_FORMAT_ALAW		:	RTPPayloadType	= 0x08;
										break;
		case WAVE_FORMAT_CISCO_G729	:	RTPPayloadType	= 0x12;
										break;
		case WAVE_FORMAT_CISCO_G723_53:	RTPPayloadType	= 0x04;
										break;
		case WAVE_FORMAT_CISCO_G723_63:	RTPPayloadType	= 0x04;
										break;
		default						:	break;
		}
	}
	else if (!silenceInterval)
	{
		transmitPacket	= true;
		silenceInterval	= true;
		RTPPayloadType	= RTP_PAYLOADTYPE_SID;
		// See internet draft "RTP Payload for Comfort Noise". Actually 1 byte of data (although min amount
		// of data in RTP packet is 4 bytes. First byte is important. all others should be zero.
		// first byte = value between 0 to 127. If it is X, then noise level is -X dB. so 0 is loudest, and
		// 127 is quietest.
		// Pascal Huart in Dallas gave me this information
		*((long *)(sendBuffer + 12)) = htonl(0);
		sendBuffer[12] = 100;
		dataSize = 12 + 4;
	}

	if (transmitPacket)
	{
		sendBuffer[0] = 0x80;
		sendBuffer[1] = RTPPayloadType;
		if (setMarkerBit)
		{
			sendBuffer[1] |= 0x80;
		}
		*((short *)(sendBuffer + 2))	= htons((short)seqno);
		*((long  *)(sendBuffer + 4))	= htonl((long)timestamp);
		*((long  *)(sendBuffer + 8))	= htonl((long)ssrc);
		
		tracer.tracef(DET, "RenderAudioSamples : sending %d bytes\n", dataSize);
		send(rtpSocket, (char *)sendBuffer, dataSize, 0);
	}
	tracer.tracef(DET, "~RenderAudioSamples : seqno = %d, timeStamp = %d\n", seqno, timestamp);
	return 0;
}

int
RTPAudioSink::PrepareSink()
{
	int result(0);
	int returnCode(0);
	tracer.tracef(EE, "PrepareSink\n");
#ifdef WIN32
	srand((unsigned int)GetTickCount());
#endif
	ssrc = (unsigned long)rand();
	timestamp = (unsigned long)rand();
	seqno = (unsigned short)((unsigned long)(rand() % 65536));
	silenceInterval = true;		// so that the marker bit is set after the first packet
	tracer.tracef(EE, "PrepareSink : returning %d\n", result);
	return result;
}

int
RTPAudioSink::UnprepareSink()
{
	int result(0);
	int returnCode(0);
	tracer.tracef(EE, "UnprepareSink\n");
	tracer.tracef(EE, "UnprepareSink : returning %d\n", result);
	return result;
}

int
RTPAudioSink::StartSink()
{
	int result(0);
	int returnCode(0);
	SetTraceLevel();
	tracer.tracef(EE, "StartSink\n");
	EnterCriticalSection(&filterMutex);
	tracer.tracef(ARB, "StartSink : entered filterMutex\n");
	do
	{
		if (bRunning)
		{
			tracer.tracef(ERR, "StartSink : e-error : already running\n");
			result = -10;
			break;
		}
		returnCode = PrepareSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "StartSink : e-PrepareSink : %d 0x%x\n", returnCode, returnCode);
			result = -20;
			break;
		}
		returnCode = AudioSink::StartSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "StartSink : e-AudioSink::StartSink : %d 0x%x\n", returnCode, returnCode);
			result = -30;
			break;
		}
		bRunning = true;
	}
	while (false);

	LeaveCriticalSection(&filterMutex);
	tracer.tracef(ARB, "StartSink : left filterMutex\n");
	tracer.tracef(EE, "~StartSink : returning %d\n", result);
	return result;
}

int
RTPAudioSink::StopSink()
{
	int result(0);
	int returnCode(0);
	tracer.tracef(EE, "StopSink\n");
	EnterCriticalSection(&filterMutex);
	tracer.tracef(ARB, "StopSink : entered filterMutex\n");
	do
	{
		if (!bRunning)
		{
			tracer.tracef(ERR, "StopSink : e-error : not running\n");
			result = -10;
			break;
		}
		returnCode = UnprepareSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "StopSink : e-UnprepareSink : %d 0x%x\n", returnCode, returnCode);
			result = -20;
			break;
		}
		returnCode = AudioSink::StopSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "StopSink : e-AudioSink::StopSink : %d 0x%x\n", returnCode, returnCode);
			result = -30;
			break;
		}
		bRunning = false;
	}
	while (false);

	LeaveCriticalSection(&filterMutex);
	tracer.tracef(ARB, "StopSink : left filterMutex\n");
	tracer.tracef(EE, "~StopSink : returning %d\n", result);
	return result;
}

#ifdef WIN32
int
RTPAudioSink::SinkThreadStarted(HANDLE sinkThreadHandle, DWORD sinkThreadID)
#else
int
RTPAudioSink::SinkThreadStarted(vthread_t sinkThreadHandle, DWORD sinkThreadID)
#endif
{
	int returnCode(0);
	int result(0);
	tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkThreadStarted\n");
	EnterCriticalSection(&filterMutex);
	tracer.tracef(ARB, "SinkThreadStarted : entered filterMutex\n");
	do
	{
#ifdef WIN32

		returnCode = SetThreadPriority(sinkThreadHandle, THREAD_PRIORITY_TIME_CRITICAL);
		if (returnCode == 0)
		{
			returnCode = GetLastError();
			tracer.tracef(ERR, "SinkThreadStarted : e-SetThreadPriority : %d 0x%x\n", returnCode, returnCode);
		}
#endif
		returnCode = PrepareSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "SinkThreadStarted : e-PrepareSink : %d 0x%x\n", returnCode, returnCode);
			result = -10;
			break;
		}
		bRunning = true;
	}
	while(false);

	LeaveCriticalSection(&filterMutex);
	tracer.tracef(ARB, "SinkThreadStarted : left filterMutex\n");
	tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkThreadStarted : %d 0x%x\n", result, result);
	return result;
}

#ifdef WIN32
int
RTPAudioSink::SinkThreadStopped(HANDLE sinkThreadHandle, DWORD sinkThreadID)
#else
int
RTPAudioSink::SinkThreadStopped(vthread_t sinkThreadHandle, DWORD sinkThreadID)
#endif
{
	tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkThreadStopped\n");
	int result(0);
	int returnCode(0);
	EnterCriticalSection(&filterMutex);
	tracer.tracef(ARB, "SinkThreadStopped : entered filterMutex\n");
	do
	{
		returnCode = UnprepareSink();
		if (returnCode != 0)
		{
			tracer.tracef(ERR, "SinkThreadStopped : e-UnprepareSink : %d 0x%x\n", returnCode, returnCode);
			result = -10;
			break;
		}
		bRunning = false;
	}
	while(false);

	LeaveCriticalSection(&filterMutex);
	tracer.tracef(ARB, "SinkThreadStopped : left filterMutex\n");
	tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkThreadStopped : %d 0x%x\n", result, result);
	return result;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?