// CCNMediaTerm.cpp : Implementation of CCCNMediaTerm
|
|
#include "stdafx.h"
|
#include "stdlib.h"
|
|
#include "CCNSMT.h"
|
#include "CCNMediaTerm.h"
|
#include "AudioCodecs.h"
|
#include "../MTC/AudioSampleManager.h"
|
#include "../MTC/Exception.h"
|
|
#include <math.h>
|
|
extern "C" {
|
#include "../MTC/DSP/FIRCoefficients.h"
|
}
|
|
#include <string>
|
#include <vector>
|
|
using namespace std;
|
|
long nextCookie;
|
|
int FilePlay::numOutstandingEvents;
|
bool FilePlay::closing;
|
CRITICAL_SECTION FilePlay::fireEventThreadMutex;
|
HANDLE FilePlay::fireEventThreadEvent;
|
CCCNMediaTerm * FilePlay::mediaTerm;
|
|
// #define NO_RECV_MIXER
|
|
int Connect(AudioSource *source, AudioSink *sink)
|
{
|
source->SubscribeAudioSink(sink);
|
sink->SubscribeAudioSource(source);
|
return 0;
|
}
|
|
int Disconnect(AudioSource *source, AudioSink *sink)
|
{
|
source->UnsubscribeAudioSink(sink);
|
sink->UnsubscribeAudioSource(source);
|
return 0;
|
}
|
|
int
|
CCCNMediaTerm::SetTraceLevel() {
|
long SystemMask = 0;
|
GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "MTC", 0x100000);
|
if ((SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "AllComponents", 0x0)) == 0)
|
SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "MTC", 0x100000);
|
tracer.SetSystemMask(SystemMask);
|
return NOERROR;
|
}
|
|
|
// #define WM_GRAPHNOTIFY WM_USER + 13
|
|
|
// using namespace std;
|
|
/////////////////////////////////////////////////////////////////////////////
|
// CCCNMediaTerm
|
|
HRESULT
|
CCCNMediaTerm::Initialize()
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "Initialize\n");
|
if (!initialized)
|
{
|
AudioSampleManager::Initialize();
|
InitializeCriticalSection(&filesPlayingMutex);
|
waveSource = new WaveAudioSource();
|
waveSink = new WaveAudioSink();
|
filePlayWaveSink = new WaveAudioSink();
|
rtpSink = new RTPAudioSink();
|
rtpSource = new RTPAudioSource();
|
inputFIRTransformer = new FIRTransformer();
|
inputFIRTransformer->SetCoefficients(FIR_TELECASTER_TX, FIR_TELECASTER_TX_NUM, 16);
|
outputFIRTransformer = new FIRTransformer();
|
outputFIRTransformer->SetCoefficients(FIR_TELECASTER_RX, FIR_TELECASTER_RX_NUM, 16);
|
pcm2G711Transformer = new PCM2G711Transformer();
|
g7112PcmTransformer = new G7112PCMTransformer();
|
limiter = new Limiter(-8.0, 0.075, -0.00075);
|
voiceActivityDetector = new VoiceActivityDetector();
|
rtpJitterBuffer = new RTPJitterBuffer();
|
fixedSizeAudioBuffer = new FixedSizeAudioBuffer();
|
genericRTP2PCMDecoder = new GenericRTP2PCMDecoder();
|
rxPCMMixer = new PCMMixer();
|
txPCMMixer = new PCMMixer();
|
pcmVolumeMaximizer = new PCMVolumeMaximizer;
|
rxTransformer = g7112PcmTransformer;
|
txTransformer = pcm2G711Transformer;
|
txDuration = 20;
|
rxDuration = 20;
|
filesPlaying.clear();
|
extraFilePlay = NULL;
|
brxRunning = false;
|
btxRunning = false;
|
bFilePlayRunning = false;
|
nextCookie = 0;
|
waveinDeviceID = WAVE_MAPPER;
|
waveoutDeviceID = WAVE_MAPPER;
|
|
FilePlay::Initialize(this);
|
|
initialized = true;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~Initialize\n");
|
return NOERROR;
|
}
|
|
|
HRESULT
|
CCCNMediaTerm::UnInitialize()
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(EE, "UnInitialize\n");
|
if (initialized)
|
{
|
tracer.tracef(EE, "UnInitialize : Stopping streaming\n");
|
StopRX();
|
StopTX();
|
if (extraFilePlay && extraFilePlay->IsRunning())
|
{
|
StopPlayingFileRX(extraFilePlay->GetCookie());
|
}
|
RemoveNonPlayingFiles();
|
if (g7112PcmTransformer)
|
{
|
delete g7112PcmTransformer;
|
}
|
if (pcm2G711Transformer)
|
{
|
delete pcm2G711Transformer;
|
}
|
if (waveSink)
|
{
|
delete waveSink;
|
}
|
if (filePlayWaveSink)
|
{
|
delete filePlayWaveSink;
|
}
|
if (waveSource)
|
{
|
delete waveSource;
|
}
|
if (rtpSource)
|
{
|
delete rtpSource;
|
}
|
if (rtpSink)
|
{
|
delete rtpSink;
|
}
|
if (inputFIRTransformer)
|
{
|
delete inputFIRTransformer;
|
}
|
if (outputFIRTransformer)
|
{
|
delete outputFIRTransformer;
|
}
|
if (limiter)
|
{
|
delete limiter;
|
}
|
if (voiceActivityDetector)
|
{
|
delete voiceActivityDetector;
|
}
|
if (rxPCMMixer)
|
{
|
delete rxPCMMixer;
|
}
|
if (txPCMMixer)
|
{
|
delete txPCMMixer;
|
}
|
if (rtpJitterBuffer)
|
{
|
delete rtpJitterBuffer;
|
}
|
if (fixedSizeAudioBuffer)
|
{
|
delete fixedSizeAudioBuffer;
|
}
|
if (genericRTP2PCMDecoder)
|
{
|
delete genericRTP2PCMDecoder;
|
}
|
if (pcmVolumeMaximizer)
|
{
|
delete pcmVolumeMaximizer;
|
}
|
DeleteCriticalSection(&filesPlayingMutex);
|
|
FilePlay::Uninitialize();
|
|
AudioSampleManager::Uninitialize();
|
|
initialized = false;
|
}
|
else
|
{
|
tracer.tracef(EE, "UnInitialize : initialize = false\n");
|
}
|
tracer.tracef(EE, "~UnInitialize\n");
|
return NOERROR;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::SetAudioCodecRX(long CompressionType, long MillisecPacketSize, long EchoCancellationValue, long G723BitRate)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioCodecRX : %d %d %d %d\n", CompressionType, MillisecPacketSize, EchoCancellationValue, G723BitRate);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
SetTraceLevel();
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioCodecRX : brxRunning = %d\n", brxRunning);
|
bool restart = false;
|
int result(0);
|
int resultCode(0);
|
|
bool needToSet = true;
|
if (brxRunning)
|
{
|
needToSet = false;
|
do
|
{
|
if (CompressionType != rxParameters.CompressionType)
|
{
|
needToSet = true;
|
break;
|
}
|
if (CompressionType == Media_Payload_G7231 && G723BitRate != rxParameters.G723BitRate)
|
{
|
needToSet = true;
|
break;
|
}
|
} while (false);
|
}
|
if (needToSet)
|
{
|
// update rxParameters
|
rxParameters.CompressionType = CompressionType;
|
rxParameters.EchoCancellationValue = EchoCancellationValue;
|
rxParameters.G723BitRate = G723BitRate;
|
rxParameters.MillisecPacketSize = MillisecPacketSize;
|
|
if (brxRunning)
|
{
|
result = StopRX();
|
if (result < 0)
|
{
|
resultCode = -10;
|
}
|
restart = true;
|
}
|
|
if (resultCode == 0)
|
{
|
rxDuration = MillisecPacketSize;
|
waveSink->SetFrameSize(16 * MillisecPacketSize);
|
|
switch (CompressionType)
|
{
|
case Media_Payload_AutoDetect:
|
rxTransformer = genericRTP2PCMDecoder;
|
break;
|
case Media_Payload_G711Ulaw64k:
|
rxTransformer = g7112PcmTransformer;
|
g7112PcmTransformer->SetULaw();
|
break;
|
case Media_Payload_G711Alaw64k:
|
rxTransformer = g7112PcmTransformer;
|
g7112PcmTransformer->SetALaw();
|
break;
|
default:
|
tracer.tracef(SDI_LEVEL_ERROR, "SetAudioCodecRX : Invalid Codec # %d\n", CompressionType);
|
return -30;
|
}
|
|
if (restart)
|
{
|
result = StartRX(waveoutDeviceID);
|
if (result < 0)
|
{
|
resultCode = -20;
|
}
|
}
|
}
|
}
|
else
|
{
|
tracer.tracef(ARB, "SetAudioCodecRX : no need to restart\n");
|
}
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetAudioCodecRX : %d\n", resultCode);
|
return resultCode;
|
}
|
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::SetAudioCodecTX(long CompressionType, long MillisecPacketSize, long PrecedenceValue, long SilenceSuppression, unsigned short MaxFramesPerPacket, long G723BitRate)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioCodecTX : %d %d %d %d %d %d\n", CompressionType, MillisecPacketSize, PrecedenceValue, SilenceSuppression, MaxFramesPerPacket, G723BitRate);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
SetTraceLevel();
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioCodecTX : btxRunning = %d\n", btxRunning);
|
bool needToSet = false;
|
bool forceVADOff = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "ForceVADOff", false);
|
int resultCode(0);
|
|
SilenceSuppression = forceVADOff && SilenceSuppression;
|
|
if (CompressionType != txParameters.CompressionType ||
|
MillisecPacketSize != txParameters.MillisecPacketSize ||
|
SilenceSuppression != txParameters.SilenceSuppression ||
|
(CompressionType == Media_Payload_G7231 && G723BitRate != txParameters.G723BitRate)
|
)
|
{
|
needToSet = true;
|
}
|
|
if (needToSet)
|
{
|
bool restart = false;
|
int result(0);
|
|
if (btxRunning)
|
{
|
result = StopTX();
|
if (result < 0)
|
{
|
resultCode = -10;
|
}
|
restart = true;
|
}
|
|
// update btxVAD after StopTX, so that StopTX knows whether VAD was on or off the last time
|
btxVAD = SilenceSuppression == 0 ? false : true;
|
|
if (resultCode == 0)
|
{
|
txDuration = MillisecPacketSize;
|
waveSource->SetBufferSize(MillisecPacketSize * 16);
|
switch (CompressionType)
|
{
|
case Media_Payload_G711Ulaw64k:
|
txTransformer = pcm2G711Transformer;
|
pcm2G711Transformer->SetULaw();
|
break;
|
|
case Media_Payload_G711Alaw64k:
|
txTransformer = pcm2G711Transformer;
|
pcm2G711Transformer->SetALaw();
|
break;
|
|
default:
|
tracer.tracef(SDI_LEVEL_ERROR, "SetAudioCodecTX : Invalid Codec # %d\n", CompressionType);
|
return -30;
|
}
|
|
if (restart)
|
{
|
result = StartTX(waveinDeviceID);
|
if (result < 0)
|
{
|
resultCode = -20;
|
}
|
}
|
}
|
}
|
|
if (resultCode == 0)
|
{
|
txParameters.CompressionType = CompressionType;
|
txParameters.G723BitRate = G723BitRate;
|
txParameters.MaxFramesPerPacket = MaxFramesPerPacket;
|
txParameters.MillisecPacketSize = MillisecPacketSize;
|
txParameters.PrecedenceValue = PrecedenceValue;
|
txParameters.SilenceSuppression = SilenceSuppression;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetAudioCodecTX : %d\n", resultCode);
|
return resultCode;
|
}
|
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::SetAudioDestination(BSTR strHostName, long nUDPPortNumber)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
USES_CONVERSION;
|
LPSTR hostname = W2A((wchar_t *) strHostName);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioDestination %s %d\n", hostname, nUDPPortNumber);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioDestination : entered Mutex\n");
|
int resultCode(0);
|
|
bool bUseFixedTransmitPort = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "UseFixedTransmitPort", false);
|
if (bUseFixedTransmitPort)
|
{
|
unsigned short localTransmitPort = (unsigned short)(GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "TransmitPort", 0) % 65536);
|
rtpSink->SetLocalPort(localTransmitPort);
|
}
|
resultCode = rtpSink->SetDestination(hostname, (short)nUDPPortNumber);
|
strcpy(txParameters.strHostName, hostname);
|
txParameters.UDPPortNumber = nUDPPortNumber;
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetAudioDestination : %d\n", resultCode);
|
return resultCode;
|
}
|
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::SetAudioReceivePort(long nUDPPortNumber)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioReceivePort %d\n", nUDPPortNumber);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetAudioReceivePort : entered Mutex\n");
|
bool restart = false;
|
int result(0);
|
int resultCode(0);
|
|
bool needToSet = false;
|
unsigned short currentReceivePort(0);
|
resultCode = rtpSource->GetReceivePort(¤tReceivePort);
|
if (resultCode != 0 || currentReceivePort != (unsigned short)nUDPPortNumber)
|
{
|
needToSet = true;
|
}
|
|
if (needToSet)
|
{
|
if (brxRunning)
|
{
|
result = StopRX();
|
if (result < 0)
|
{
|
resultCode = -10;
|
}
|
restart = true;
|
}
|
|
if (resultCode == 0)
|
{
|
result = rtpSource->SetReceivePort(nUDPPortNumber);
|
if (result < 0)
|
{
|
resultCode = -20;
|
}
|
}
|
|
// update rxParameters
|
|
if (resultCode == 0)
|
{
|
if (restart)
|
{
|
result = StartRX(waveoutDeviceID);
|
}
|
if (result < 0)
|
{
|
resultCode = -30;
|
}
|
}
|
}
|
else
|
{
|
tracer.tracef(ARB, "SetAudioReceivePort : no need to restart\n");
|
}
|
|
rtpSource->GetReceivePort(¤tReceivePort);
|
rxParameters.UDPPortNumber = currentReceivePort;
|
|
if (resultCode == 0)
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetAudioReceivePort : %d\n", resultCode);
|
}
|
else
|
{
|
tracer.tracef(ERR, "~StartAudioReceivePort : error %d\n", resultCode);
|
}
|
return resultCode;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::StartPlayingFileTX(BSTR Filename, unsigned long Mode, unsigned long volume, long * Cookie)
|
{
|
USES_CONVERSION;
|
int result(0);
|
std::string filename = std::string(W2A((wchar_t *)Filename));
|
tracer.tracef(EE, "StartPlayingFileTX file = %s, mode = %d\n", filename.c_str(), Mode);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
try
|
{
|
tracer.tracef(ARB, "StartPlayingFileTX : calling RemoveNonPlayingFiles()\n");
|
RemoveNonPlayingFiles();
|
if (btxRunning)
|
{
|
int returnCode(0);
|
tracer.tracef(ARB, "StartPlayingFileTX : btxRunning = true. Playing file\n");
|
FilePlay *newFilePlay = new FilePlay(txPCMMixer, txDuration, true);
|
returnCode = newFilePlay->LoadFile(filename.c_str());
|
if (returnCode != 0)
|
{
|
delete newFilePlay;
|
newFilePlay = NULL;
|
throw Exception(-10, "Error loading file %s", filename.c_str());
|
}
|
if (Mode == 0)
|
{
|
newFilePlay->PlayInLoop();
|
}
|
newFilePlay->SetVolume((int)volume);
|
newFilePlay->SetDestinationFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1));
|
tracer.tracef(ARB, "StartPlayingFileTX : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
filesPlaying[newFilePlay->GetCookie()] = newFilePlay;
|
*Cookie = newFilePlay->GetCookie();
|
newFilePlay->Start();
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StartPlayingFileTX : Left filesPlayingMutex\n");
|
}
|
}
|
catch (Exception ex)
|
{
|
tracer.tracef(ERR, "StartPlayingFileTX : %s\n", ex.ErrorMessage());
|
result = ex.ErrorCode();
|
}
|
tracer.tracef(EE, "~StartPlayingFileTX : cookie = %d\n", *Cookie);
|
return result;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::StopPlayingFileTX(unsigned long Cookie)
|
{
|
tracer.tracef(EE, "StopPlayingFileTX : cookie = %u\n", Cookie);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(ARB, "StopPlayingFileTX : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
map<unsigned int, FilePlay *>::iterator iter = filesPlaying.find(Cookie);
|
if (iter != filesPlaying.end())
|
{
|
FilePlay *filePlay = (*iter).second;
|
if (filePlay->Transmitting() == true)
|
{
|
filePlay->StopImmediately();
|
}
|
}
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StopPlayingFileTX : Left filesPlayingMutex\n");
|
tracer.tracef(EE, "~StopPlayingFileTX\n");
|
return NOERROR;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::StartPlayingFileRX(BSTR Filename, unsigned long Mode, unsigned long waveoutDeviceID, unsigned long volume, long * Cookie)
|
{
|
USES_CONVERSION;
|
int result(0);
|
std::string filename = std::string(W2A((wchar_t *)Filename));
|
tracer.tracef(EE, "StartPlayingFileRX file = %s, mode = %d, waveOutDeviceID = %d\n", filename.c_str(), Mode, waveoutDeviceID);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
try
|
{
|
tracer.tracef(ARB, "StartPlayingFileRX : calling RemoveNonPlayingFiles()\n");
|
RemoveNonPlayingFiles();
|
if (brxRunning && waveoutDeviceID == this->waveoutDeviceID)
|
{
|
tracer.tracef(ARB, "StartPlayingFileRX : playing file in audio stream\n");
|
int resultCode(0);
|
FilePlay *newFilePlay = new FilePlay(rxPCMMixer, rxDuration, false);
|
resultCode = newFilePlay->LoadFile(filename.c_str());
|
if (resultCode != 0)
|
{
|
delete newFilePlay;
|
newFilePlay = NULL;
|
throw Exception(-10, "Error loading file %s", filename.c_str());
|
}
|
if (Mode == 0)
|
{
|
newFilePlay->PlayInLoop();
|
}
|
newFilePlay->SetVolume((int)volume);
|
newFilePlay->SetDestinationFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1));
|
tracer.tracef(ARB, "StartPlayingFileRX : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
filesPlaying[newFilePlay->GetCookie()] = newFilePlay;
|
*Cookie = newFilePlay->GetCookie();
|
newFilePlay->Start();
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StartPlayingFileRX : Left filesPlayingMutex\n");
|
}
|
else
|
{
|
if (bFilePlayRunning)
|
{
|
if (extraFilePlay == NULL)
|
{
|
tracer.tracef(ERR, "StartPlayingFileRX : bFilePlayRunning = true but extraFilePlay = NULL\n");
|
bFilePlayRunning = false;
|
}
|
else
|
{
|
tracer.tracef(ARB, "StartPlayingFileRX : bFilePlayRunning = true. Calling StopPlayingFileRX\n");
|
StopPlayingFileRX(extraFilePlay->GetCookie());
|
}
|
}
|
if (extraFilePlay == NULL)
|
{
|
tracer.tracef(ARB, "StartPlayingFileRX : extraFilePlay = NULL. Playing file\n");
|
int resultCode(0);
|
extraFilePlay = new FilePlay(filePlayWaveSink, 60, false);
|
resultCode = extraFilePlay->LoadFile(filename.c_str());
|
if (resultCode != 0)
|
{
|
delete extraFilePlay;
|
extraFilePlay = NULL;
|
throw Exception(-20, "Error loading file %s to extraFilePlay", filename.c_str());
|
}
|
extraFilePlay->SetDestinationFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1));
|
extraFilePlay->SetVolume((int)volume);
|
if (Mode == 0)
|
{
|
extraFilePlay->PlayInLoop();
|
}
|
filePlayWaveSink->SetDeviceID(waveoutDeviceID);
|
filePlayWaveSink->SetFrameSize(60 * 16);
|
filePlayWaveSink->SetNumFrames(10);
|
filePlayWaveSink->SetFormat(WaveFormat_PCM_16_8_1);
|
tracer.tracef(ARB, "StartPlayingFileRX : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
*Cookie = extraFilePlay->GetCookie();
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StartPlayingFileRX : Left filesPlayingMutex\n");
|
extraFilePlay->Start();
|
filePlayWaveSink->StartSinkThread();
|
bFilePlayRunning = true;
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
tracer.tracef(ERR, "StartPlayingFileRX : %s\n", ex.ErrorMessage());
|
result = ex.ErrorCode();
|
*Cookie = 0;
|
}
|
if (result == 0)
|
{
|
tracer.tracef(EE, "~StartPlayingFileRX : cookie = %u\n", *Cookie);
|
}
|
else
|
{
|
tracer.tracef(ERR, "~StartPlayingFileRX : returning error code %d\n", result);
|
}
|
return result;
|
}
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::StopPlayingFileRX(unsigned long Cookie)
|
{
|
tracer.tracef(EE, "StopPlayingFileRX %u\n", Cookie);
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
tracer.tracef(ARB, "StopPlayingFileRX : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
map<unsigned int, FilePlay *>::iterator iter = filesPlaying.find(Cookie);
|
if (iter != filesPlaying.end())
|
{
|
FilePlay *filePlay = (*iter).second;
|
if (filePlay->Transmitting() == false)
|
{
|
filePlay->StopImmediately();
|
}
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StopPlayingFileRX : Left filesPlayingMutex\n");
|
}
|
else
|
{
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StopPlayingFileRX : Left filesPlayingMutex\n");
|
if (extraFilePlay)
|
{
|
tracer.tracef(DET, "StopPlayingFileRX : extraFilePlay->cookie = %d\n", extraFilePlay->GetCookie());
|
if (Cookie == extraFilePlay->GetCookie())
|
{
|
tracer.tracef(DET, "StopPlayingFileRX : calling filePlayWaveSink->StopSinkThread\n");
|
int i;
|
i = filePlayWaveSink->StopSinkThread();
|
if (i != 0)
|
{
|
tracer.tracef(ERR, "StopPlayingFileRX : e-filePlayWaveSink->StopSinkThread() : %d\n", i);
|
}
|
tracer.tracef(DET, "StopPlayingFileRX : calling extraFilePlay->StopImmediately\n");
|
i = extraFilePlay->StopImmediately();
|
if (i != 0)
|
{
|
tracer.tracef(ERR, "StopPlayingFileRX : e-extraFilePlay->StopImmediately() : %d\n", i);
|
}
|
if (!extraFilePlay->IsRunning())
|
{
|
bFilePlayRunning = false;
|
tracer.tracef(DET, "StopPlayingFileRX : deleting extraFilePlay\n");
|
delete extraFilePlay;
|
extraFilePlay = NULL;
|
}
|
else
|
{
|
int i=10;
|
}
|
}
|
}
|
}
|
tracer.tracef(EE, "~StopPlayingFileRX\n");
|
return S_OK;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::StartTX(unsigned long waveinDeviceID)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StartTX\n");
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
int resultCode(0);
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StartTX : 0\n");
|
if (!btxRunning)
|
{
|
// find out if pre-emphasis needs to be done, and if so with what parameters
|
btxPreEmphasis = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "MicrophonePreprocess", true);
|
long txFIRFilter = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "TxFIRFilter", 1);
|
if (txFIRFilter == 2)
|
{
|
outputFIRTransformer->SetCoefficients(FIR_TELECASTER_TX, FIR_TELECASTER_TX_NUM, 16);
|
}
|
else
|
{
|
outputFIRTransformer->SetCoefficients(FIR_ITU_TX_IRS, FIR_ITU_TX_IRS_NUM, 16);
|
}
|
|
this->waveinDeviceID = waveinDeviceID;
|
waveSource->SetDeviceID(waveinDeviceID);
|
|
AudioSource *temp = waveSource;
|
|
if (btxPreEmphasis)
|
{
|
Connect(temp, outputFIRTransformer);
|
temp = outputFIRTransformer;
|
}
|
if (btxVAD)
|
{
|
Connect(temp, voiceActivityDetector);
|
temp = voiceActivityDetector;
|
}
|
Connect(temp, txPCMMixer);
|
Connect(txPCMMixer, txTransformer);
|
Connect(txTransformer, rtpSink);
|
|
do
|
{
|
int result(0);
|
long transmitTOS = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "TransmitTOS", 0xb8);
|
unsigned char tos = (unsigned char)transmitTOS;
|
result = rtpSink->SetTOS(tos);
|
result = rtpSink->StartSink();
|
if (result < 0)
|
{
|
resultCode = -10;
|
break;
|
}
|
result = txTransformer->StartTransform();
|
if (result < 0)
|
{
|
rtpSink->StopSink();
|
resultCode = -20;
|
break;
|
}
|
result = txPCMMixer->StartTransform();
|
if (result < 0)
|
{
|
rtpSink->StopSink();
|
txTransformer->StopTransform();
|
resultCode = -30;
|
break;
|
}
|
if (btxVAD)
|
{
|
voiceActivityDetector->EnableDetection();
|
result = voiceActivityDetector->StartTransform();
|
if (result < 0)
|
{
|
rtpSink->StopSink();
|
txTransformer->StopTransform();
|
txPCMMixer->StopTransform();
|
resultCode = -40;
|
break;
|
}
|
}
|
if (btxPreEmphasis)
|
{
|
result = outputFIRTransformer->StartTransform();
|
if (result < 0)
|
{
|
rtpSink->StopSink();
|
txTransformer->StopTransform();
|
txPCMMixer->StopTransform();
|
if (btxVAD)
|
{
|
voiceActivityDetector->StopTransform();
|
}
|
resultCode = -50;
|
break;
|
}
|
}
|
result = waveSource->StartSourceThread();
|
if (result < 0)
|
{
|
rtpSink->StopSink();
|
txTransformer->StopTransform();
|
txPCMMixer->StopTransform();
|
if (btxVAD)
|
{
|
voiceActivityDetector->StopTransform();
|
}
|
if (btxPreEmphasis)
|
{
|
outputFIRTransformer->StopTransform();
|
}
|
resultCode = -60;
|
break;
|
}
|
} while (false);
|
}
|
if (resultCode == 0)
|
{
|
btxRunning = true;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~StartTX : %d\n", resultCode);
|
return resultCode;
|
}
|
|
|
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::StopTX()
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StopTX\n");
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
|
bool bError(false);
|
int resultCode(0);
|
tracer.tracef(ARB, "StopTX : after cLock.Lock()\n");
|
if (btxRunning)
|
{
|
int result(0);
|
result = StopAllFiles(true);
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-StopAllFiles %d\n", result);
|
}
|
tracer.tracef(ARB, "StopTX : before waveSource->StopSourceThread()\n");
|
result = waveSource->StopSourceThread();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-waveSource->StopSourceThread %d\n", result);
|
}
|
if (btxPreEmphasis)
|
{
|
tracer.tracef(ARB, "StopTX : before outputFIRTransformer->StopTransform()\n");
|
result = outputFIRTransformer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-outputFIRTransformer->StopTransform %d\n", result);
|
}
|
}
|
if (btxVAD)
|
{
|
tracer.tracef(ARB, "StopTX : before voiceActivityDetector->StopTransform()\n");
|
result = voiceActivityDetector->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-voiceActivityDetector->StopTransform %d\n", result);
|
}
|
}
|
tracer.tracef(ARB, "StopTX : before txPCMMixer->StopTransform()\n");
|
result = txPCMMixer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-txPCMMixer->StopTransform %d\n", result);
|
}
|
tracer.tracef(ARB, "StopTX : before txTransformer->StopTransform()\n");
|
result = txTransformer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-txTransformer->StopTransform %d\n", result);
|
}
|
tracer.tracef(ARB, "StopTX : before rtpSink->StopSink()\n");
|
result = rtpSink->StopSink();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopTX : e-rtpSink->StopSink %d\n", result);
|
}
|
tracer.tracef(ARB, "StopTX : before Disconnects\n");
|
|
AudioSource *temp = waveSource;
|
if (btxPreEmphasis)
|
{
|
Disconnect(temp, outputFIRTransformer);
|
temp = outputFIRTransformer;
|
}
|
if (btxVAD)
|
{
|
Disconnect(temp, voiceActivityDetector);
|
temp = voiceActivityDetector;
|
}
|
Disconnect(temp, txPCMMixer);
|
Disconnect(txPCMMixer, txTransformer);
|
Disconnect(txTransformer, rtpSink);
|
|
tracer.tracef(ARB, "StopTX : after Disconnects\n");
|
}
|
if (!bError)
|
{
|
btxRunning = false;
|
}
|
else
|
{
|
resultCode = -10;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~StopTX : %d\n", resultCode);
|
return resultCode;
|
}
|
|
|
|
|
STDMETHODIMP
|
CCCNMediaTerm::StartRX(unsigned long waveoutDeviceID)
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StartRX\n");
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
|
int result(0);
|
int returnCode(0);
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StartRX : brxRunning = %d\n", brxRunning);
|
if (!brxRunning)
|
{
|
brxPostEmphasis = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "SpeakerPostprocess", true);
|
brxVolumeLimit = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "LimitVolume", true);
|
|
// set up the post emphasis filter
|
long rxFIRFilter = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "RxFIRFilter", 1);
|
if (rxFIRFilter == 2)
|
{
|
inputFIRTransformer->SetCoefficients(FIR_TELECASTER_RX, FIR_TELECASTER_RX_NUM, 16);
|
}
|
else
|
{
|
inputFIRTransformer->SetCoefficients(FIR_ITU_RX_IRS, FIR_ITU_RX_IRS_NUM, 16);
|
}
|
|
// set up the limiter
|
// set up RTP jitter buffer and fixed size audio buffer
|
long jitterBufferDepth = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "JitterBufferTime", 100);
|
rtpJitterBuffer->SetJitterBufferDepth(jitterBufferDepth);
|
fixedSizeAudioBuffer->SetOutputDuration(rxDuration);
|
int numFrames = _winmajor < 5 ? 10 : 6;
|
bool useDynamicJitterBuffer = GetRegKeyBool(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "UseDynamicJitterBuffer", true);
|
if (useDynamicJitterBuffer)
|
{
|
waveSink->SetNumFrames(numFrames);
|
}
|
else
|
{
|
waveSink->SetNumFrames(max(numFrames, jitterBufferDepth/rxDuration));
|
}
|
|
double threshold;
|
double lossIncrement;
|
double lossDecrement;
|
std::string strThreshold = GetRegKeyString(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "LimiterThreshold", "-8.0");
|
std::string strLossIncrement = GetRegKeyString(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "LimiterLossIncrement", "0.075");
|
std::string strLossDecrement = GetRegKeyString(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "LimiterLossDecrement", "-0.00075");
|
threshold = atof(strThreshold.c_str());
|
lossIncrement = atof(strLossIncrement.c_str());
|
lossDecrement = atof(strLossDecrement.c_str());
|
limiter->SetParameters(threshold, lossIncrement, lossDecrement);
|
|
this->waveoutDeviceID = waveoutDeviceID;
|
waveSink->SetDeviceID(waveoutDeviceID);
|
|
double volumeMaximizePercentile = atof((GetRegKeyString(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "VolumeMaximizePercentile", "95.00")).c_str());
|
double volumeMaximizeMaxAmplification = fabs(atof((GetRegKeyString(HKEY_CURRENT_USER, "Software\\Cisco Systems\\CCNMediaTerm\\1.0", "VolumeMaximizeMaxGain", "8.00")).c_str()));
|
unsigned int maxGain = (unsigned int)(volumeMaximizeMaxAmplification * 100);
|
pcmVolumeMaximizer->SetMaximizePercentile(volumeMaximizePercentile);
|
pcmVolumeMaximizer->SetMaximumAmplification(maxGain);
|
|
Connect(rtpSource, rxTransformer);
|
Connect(rxTransformer, rtpJitterBuffer);
|
Connect(rtpJitterBuffer, fixedSizeAudioBuffer);
|
Connect(fixedSizeAudioBuffer, pcmVolumeMaximizer);
|
Connect(pcmVolumeMaximizer, rxPCMMixer);
|
AudioSource *tempSource = rxPCMMixer;
|
if (brxPostEmphasis)
|
{
|
Connect(tempSource, inputFIRTransformer);
|
tempSource = inputFIRTransformer;
|
}
|
if (brxVolumeLimit)
|
{
|
Connect(tempSource, limiter);
|
tempSource = limiter;
|
}
|
Connect(tempSource, waveSink);
|
|
do
|
{
|
result = rxTransformer->StartTransform();
|
if (result < 0)
|
{
|
returnCode = -10;
|
break;
|
}
|
result = rtpJitterBuffer->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
returnCode = -20;
|
break;
|
}
|
result = fixedSizeAudioBuffer->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
returnCode = -30;
|
break;
|
}
|
result = pcmVolumeMaximizer->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
returnCode = -40;
|
break;
|
}
|
result = rxPCMMixer->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
pcmVolumeMaximizer->StopTransform();
|
returnCode = -50;
|
break;
|
}
|
if (brxPostEmphasis)
|
{
|
result = inputFIRTransformer->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
pcmVolumeMaximizer->StopTransform();
|
rxPCMMixer->StopTransform();
|
returnCode = -60;
|
break;
|
}
|
}
|
if (brxVolumeLimit)
|
{
|
result = limiter->StartTransform();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
pcmVolumeMaximizer->StopTransform();
|
rxPCMMixer->StopTransform();
|
inputFIRTransformer->StopTransform();
|
returnCode = -70;
|
break;
|
}
|
}
|
result = waveSink->StartSinkThread();
|
if (result < 0)
|
{
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
pcmVolumeMaximizer->StopTransform();
|
rxPCMMixer->StopTransform();
|
inputFIRTransformer->StopTransform();
|
limiter->StopTransform();
|
returnCode = -80;
|
break;
|
}
|
result = rtpSource->StartSourceThread();
|
if (result < 0)
|
{
|
waveSink->StopSinkThread();
|
rxTransformer->StopTransform();
|
rtpJitterBuffer->StopTransform();
|
fixedSizeAudioBuffer->StopTransform();
|
pcmVolumeMaximizer->StopTransform();
|
rxPCMMixer->StopTransform();
|
inputFIRTransformer->StopTransform();
|
limiter->StopTransform();
|
returnCode = -90;
|
break;
|
}
|
} while (false);
|
}
|
if (returnCode == 0)
|
{
|
brxRunning = true;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~StartRX : returning %d\n", returnCode);
|
return returnCode;
|
}
|
|
STDMETHODIMP
|
CCCNMediaTerm::StopRX()
|
{
|
AFX_MANAGE_STATE(AfxGetStaticModuleState())
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "StopRX\n");
|
CSingleLock cLock(&Mutex);
|
cLock.Lock();
|
|
bool bError = false;
|
int resultCode(0);
|
tracer.tracef(ARB, "StopRX : brxRunning = %d\n", brxRunning);
|
if (brxRunning)
|
{
|
int result(0);
|
tracer.tracef(ARB, "StopRX : calling StopAllFiles(false)\n");
|
result = StopAllFiles(false);
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-StopAllFiles = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling waveSink->StopSinkThread()\n");
|
result = waveSink->StopSinkThread();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-waveSink->StopSinkThread = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling rtpSource->UnprepareSource()\n");
|
result = rtpSource->UnprepareSource();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-rtpSource->UnprepareSource = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling rtpSource->StopSourceThread()\n");
|
result = rtpSource->StopSourceThread();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-rtpSource->StopSourceThread = %d\n", result);
|
}
|
if (brxVolumeLimit)
|
{
|
tracer.tracef(ARB, "StopRX : calling limiter->StopTransform()\n");
|
result = limiter->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-limiter->StopTransform = %d\n", result);
|
}
|
}
|
if (brxPostEmphasis)
|
{
|
tracer.tracef(ARB, "StopRX : calling inputFIRTransformer->StopTransform()\n");
|
result = inputFIRTransformer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-inputFIRTransformer->StopTransform = %d\n", result);
|
}
|
}
|
tracer.tracef(ARB, "StopRX : calling rxPCMMixer->StopTransform()\n");
|
result = rxPCMMixer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-rxPCMMixer->StopTransform = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling pcmVolumeMaximizer->StopTransform()\n");
|
result = pcmVolumeMaximizer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-pcmVolumeMaximizer->StopTransform = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling fixedSizeAudioBuffer->StopTransform()\n");
|
result = fixedSizeAudioBuffer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-fixedSizeAudioBuffer->StopTransform = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling rtpJitterBuffer->StopTransform()\n");
|
result = rtpJitterBuffer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-rtpJitterBuffer->StopTransform = %d\n", result);
|
}
|
tracer.tracef(ARB, "StopRX : calling rxTransformer->StopTransform()\n");
|
result = rxTransformer->StopTransform();
|
if (result < 0)
|
{
|
bError = true;
|
tracer.tracef(ERR, "StopRX : e-rxTransformer->StopTransform = %d\n", result);
|
}
|
|
tracer.tracef(ARB, "StopRX : disconnecting filters\n");
|
Disconnect(rtpSource, rxTransformer);
|
Disconnect(rxTransformer, rtpJitterBuffer);
|
Disconnect(rtpJitterBuffer, fixedSizeAudioBuffer);
|
Disconnect(fixedSizeAudioBuffer, pcmVolumeMaximizer);
|
Disconnect(pcmVolumeMaximizer, rxPCMMixer);
|
AudioSource *tempSource = rxPCMMixer;
|
if (brxPostEmphasis)
|
{
|
Disconnect(tempSource, inputFIRTransformer);
|
tempSource = inputFIRTransformer;
|
}
|
if (brxVolumeLimit)
|
{
|
Disconnect(tempSource, limiter);
|
tempSource = limiter;
|
}
|
Disconnect(tempSource, waveSink);
|
}
|
if (!bError)
|
{
|
brxRunning = false;
|
}
|
else
|
{
|
resultCode = -10;
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~StopRX : %d\n", resultCode);
|
return resultCode;
|
}
|
|
int
|
CCCNMediaTerm::RemoveNonPlayingFiles()
|
{
|
tracer.tracef(EE, "RemoveNonPlayingFiles\n");
|
tracer.tracef(ARB, "RemoveNonPlayingFiles : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
vector<map<unsigned int, FilePlay *>::iterator> filesToDelete;
|
map<unsigned int, FilePlay *>::iterator iter = filesPlaying.begin();
|
while (iter != filesPlaying.end())
|
{
|
FilePlay *filePlay = (*iter).second;
|
tracer.tracef(DET, "RemoveNonPlayingFiles : file found with cookie = %d\n", filePlay->GetCookie());
|
if (!(filePlay->IsRunning()))
|
{
|
tracer.tracef(DET, "RemoveNonPlayingFiles : file with cookie = %d is not playing\n", filePlay->GetCookie());
|
filesToDelete.push_back(iter);
|
}
|
iter++;
|
}
|
tracer.tracef(DET, "RemoveNonPlayingFiles : deleting non-playing files from list\n");
|
for (int i=0; i<filesToDelete.size(); i++)
|
{
|
map<unsigned int, FilePlay *>::iterator iter = filesToDelete[i];
|
FilePlay *filePlay = (*iter).second;
|
filesPlaying.erase(iter);
|
delete filePlay;
|
}
|
if (extraFilePlay)
|
{
|
if (!extraFilePlay->IsRunning())
|
{
|
tracer.tracef(DET, "RemoveNonPlayingFiles : extrafileplay found with cookie = %d\n", extraFilePlay->GetCookie());
|
tracer.tracef(DET, "RemoveNonPlayingFiles : deleting extraFilePlay\n");
|
delete extraFilePlay;
|
extraFilePlay = NULL;
|
bFilePlayRunning = false;
|
}
|
}
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "RemoveNonPlayingFiles : Left filesPlayingMutex\n");
|
tracer.tracef(EE, "~RemoveNonPlayingFiles\n");
|
return NOERROR;
|
}
|
|
int
|
CCCNMediaTerm::StopAllFiles(bool transmitSide)
|
{
|
tracer.tracef(EE, "StopAllFiles %d\n", transmitSide);
|
tracer.tracef(ARB, "StopAllFiles : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
map<unsigned int, FilePlay *>::iterator iter = filesPlaying.begin();
|
while(iter != filesPlaying.end())
|
{
|
FilePlay *filePlay = (*iter).second;
|
tracer.tracef(DET, "StopAllFiles : file with cookie = %d\n", filePlay->GetCookie());
|
if (filePlay->IsRunning() && filePlay->Transmitting() == transmitSide)
|
{
|
tracer.tracef(DET, "StopAllFiles : stopping filePlay with cookie = %d\n", filePlay->GetCookie());
|
filePlay->StopImmediately();
|
}
|
iter++;
|
}
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "StopAllFiles : Left filesPlayingMutex\n");
|
tracer.tracef(EE, "~StopAllFiles\n");
|
return 0;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::SetSpeakerVolume(unsigned long deviceID, unsigned long volume)
|
{
|
tracer.tracef(EE, "SetSpeakerVolume device=%u, volume=%u\n", deviceID, volume);
|
int result(0);
|
if (deviceID == filePlayWaveSink->GetDeviceID() && bFilePlayRunning)
|
{
|
result = filePlayWaveSink->SetVolume(volume);
|
}
|
else if (deviceID == waveSink->GetDeviceID() && brxRunning)
|
{
|
result = waveSink->SetVolume(volume);
|
}
|
tracer.tracef(EE, "~SetSpeakerVolume : returning %d 0x%x\n", result, result);
|
return result;
|
}
|
|
|
|
// sets the components internal setting for mic volume. max volume = system's current mic volume setting
|
STDMETHODIMP
|
CCCNMediaTerm::SetMicrophoneVolume(unsigned long deviceID, unsigned long volume)
|
{
|
tracer.tracef(EE, "SetMicrophoneVolume device=%u, volume=%u\n", deviceID, volume);
|
waveSource->SetVolume(volume);
|
tracer.tracef(EE, "~SetMicrophoneVolume\n");
|
return S_OK;
|
}
|
|
|
|
// changes the system's microphone volume setting
|
HRESULT
|
CCCNMediaTerm::SetSystemMicrophoneVolume(unsigned long volume)
|
{
|
return S_OK;
|
}
|
|
|
bool
|
CCCNMediaTerm::SpeakerAvailable()
|
{
|
bool available = true;
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SpeakerAvailable\n");
|
|
WAVEFORMATEX waveFormatex;
|
waveFormatex.nAvgBytesPerSec = 16000;
|
waveFormatex.wFormatTag = WAVE_FORMAT_PCM;
|
waveFormatex.wBitsPerSample = 16;
|
waveFormatex.nChannels = 1;
|
waveFormatex.nBlockAlign = 2;
|
waveFormatex.nSamplesPerSec = 8000;
|
waveFormatex.cbSize = 0;
|
|
// see if the speaker is available
|
HWAVEOUT hWaveOut;
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SpeakerAvailable : opening wave device\n");
|
MMRESULT mmr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormatex, NULL, NULL, CALLBACK_NULL);
|
if (mmr != MMSYSERR_NOERROR) {
|
available = false;
|
int retryInterval = 2000;
|
tracer.tracef(SDI_LEVEL_ERROR, "SpeakerAvailable : error : could not open wave device. waveOutOpen returned 0x%x\n", mmr);
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "SpeakerAvailable : trying again after %d ms\n", retryInterval);
|
Sleep(retryInterval);
|
MMRESULT mmr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormatex, NULL, NULL, CALLBACK_NULL);
|
if (mmr != MMSYSERR_NOERROR) {
|
tracer.tracef(SDI_LEVEL_ERROR, "SpeakerAvailable : error : still could not open wave device. waveOutOpen returned 0x%x\n", mmr);
|
}
|
else {
|
tracer.tracef(SDI_LEVEL_ARBITRARY, "SpeakerAvailable : got the speaker second time\n");
|
waveOutReset(hWaveOut);
|
waveOutClose(hWaveOut);
|
available = true;
|
}
|
}
|
else {
|
waveOutReset(hWaveOut);
|
waveOutClose(hWaveOut);
|
available = true;
|
}
|
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SpeakerAvailable : returning %d\n", available);
|
return available;
|
}
|
|
|
|
|
bool
|
CCCNMediaTerm::MicrophoneAvailable()
|
{
|
bool available = true;
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "MicrophoneAvailable\n");
|
|
WAVEFORMATEX waveFormatex;
|
waveFormatex.nAvgBytesPerSec = 16000;
|
waveFormatex.wFormatTag = WAVE_FORMAT_PCM;
|
waveFormatex.wBitsPerSample = 16;
|
waveFormatex.nChannels = 1;
|
waveFormatex.nBlockAlign = 2;
|
waveFormatex.nSamplesPerSec = 8000;
|
waveFormatex.cbSize = 0;
|
|
// see if the microphone is available
|
HWAVEIN hwaveIn;
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "MicrophoneAvailable : opening wavein device\n");
|
MMRESULT mmr = waveInOpen(&hwaveIn, WAVE_MAPPER, &waveFormatex, NULL, NULL, CALLBACK_NULL);
|
if (mmr != MMSYSERR_NOERROR) {
|
tracer.tracef(SDI_LEVEL_ERROR, "MicrophoneAvailable : error : could not open wavein device. waveInOpen returned 0x%x\n", mmr);
|
available = false;
|
}
|
|
else {
|
waveInReset(hwaveIn);
|
waveInClose(hwaveIn);
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~MicrophoneAvailable : returning %d\n", available);
|
return available;
|
}
|
|
|
|
STDMETHODIMP CCCNMediaTerm::SetFilePlayVolume(unsigned long cookie, unsigned long volume)
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetFilePlayVolume cookie=%u volume=%u\n", cookie, volume);
|
if (bFilePlayRunning && extraFilePlay && cookie == extraFilePlay->GetCookie())
|
{
|
tracer.tracef(ARB, "SetFilePlayVolume : Setting volume for extraFilePlay\n");
|
extraFilePlay->SetVolume((int)volume);
|
}
|
else
|
{
|
tracer.tracef(ARB, "SetFilePlayVolume : Entering filesPlayingMutex\n");
|
EnterCriticalSection(&filesPlayingMutex);
|
map<unsigned int, FilePlay *>::iterator iter = filesPlaying.find(cookie);
|
if (iter != filesPlaying.end())
|
{
|
FilePlay *filePlay = (*iter).second;
|
filePlay->SetVolume((int)volume);
|
}
|
LeaveCriticalSection(&filesPlayingMutex);
|
tracer.tracef(ARB, "SetFilePlayVolume : Left filesPlayingMutex\n");
|
}
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetFilePlayVolume\n");
|
return S_OK;
|
}
|
|
void
|
CCCNMediaTerm::FireEndOfFileRX(unsigned long cookie)
|
{
|
int resultCode(0);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "FireEndOfFileRX cookie=%u\n", cookie);
|
if ((extraFilePlay && (cookie == extraFilePlay->GetCookie())) ||
|
!bFilePlayRunning
|
)
|
{
|
resultCode = filePlayWaveSink->StopSinkThread();
|
if (resultCode != 0)
|
{
|
if (resultCode != -10)
|
{
|
tracer.tracef(ERR, "FireEndOfFileRX : e-filePlayWaveSink->StopSinkThread() : %d\n", resultCode);
|
}
|
else
|
{
|
tracer.tracef(SIG, "FireEndOfFileRX : e-filePlayWaveSink->StopSinkThread() : %d\n", resultCode);
|
}
|
}
|
tracer.tracef(DET, "FireEndOfFileRX : setting bFilePlayRunning to false\n");
|
bFilePlayRunning = false;
|
}
|
Fire_EndOfFileEventRX(cookie);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~FireEndOfFileRX\n");
|
}
|
|
void
|
CCCNMediaTerm::FireEndOfFileTX(unsigned long cookie)
|
{
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "FireEndOfFileTX cookie=%u\n", cookie);
|
Fire_EndOfFileEventTX(cookie);
|
tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~FireEndOfFileTX\n");
|
}
|
|
STDMETHODIMP CCCNMediaTerm::NetworkMonitor(unsigned long, unsigned long)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StartDtmfTone(long, long, long)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StopDtmfTone(void)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StopAudioReceive(void)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StartAudioReceive(void)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StopMicrophone(void)
|
{
|
return S_OK;
|
}
|
|
STDMETHODIMP CCCNMediaTerm::StartMicrophone(void)
|
{
|
return S_OK;
|
}
|
|
int
|
FilePlay::Initialize(CCCNMediaTerm *mediaTerm)
|
{
|
FilePlay::mediaTerm = mediaTerm;
|
InitializeCriticalSection(&fireEventThreadMutex);
|
fireEventThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
numOutstandingEvents = 0;
|
closing = false;
|
return 0;
|
}
|
|
int
|
FilePlay::Uninitialize()
|
{
|
EnterCriticalSection(&fireEventThreadMutex);
|
closing = true;
|
LeaveCriticalSection(&fireEventThreadMutex);
|
while (true)
|
{
|
EnterCriticalSection(&fireEventThreadMutex);
|
{
|
if (numOutstandingEvents > 0)
|
{
|
LeaveCriticalSection(&fireEventThreadMutex);
|
WaitForSingleObject(fireEventThreadEvent, INFINITE);
|
}
|
else
|
{
|
LeaveCriticalSection(&fireEventThreadMutex);
|
break;
|
}
|
}
|
}
|
DeleteCriticalSection(&fireEventThreadMutex);
|
CloseHandle(fireEventThreadEvent);
|
return 0;
|
}
|
|
DWORD WINAPI
|
FilePlay::FireEventThread(LPVOID params)
|
{
|
if (FilePlay::closing)
|
{
|
return 0;
|
}
|
|
EnterCriticalSection(&fireEventThreadMutex);
|
numOutstandingEvents++;
|
LeaveCriticalSection(&fireEventThreadMutex);
|
|
FireEventThreadParams *fetParams = (FireEventThreadParams *)params;
|
if (fetParams->receiveSide)
|
{
|
mediaTerm->FireEndOfFileRX(fetParams->cookie);
|
}
|
else
|
{
|
mediaTerm->FireEndOfFileTX(fetParams->cookie);
|
}
|
|
SetEvent(FilePlay::fireEventThreadEvent);
|
delete fetParams;
|
EnterCriticalSection(&fireEventThreadMutex);
|
numOutstandingEvents--;
|
LeaveCriticalSection(&fireEventThreadMutex);
|
return 0;
|
}
|
|
FilePlay::FilePlay(AudioSink *audioSink, int outputDuration, bool bTransmit)
|
{
|
char subFacilityName[100];
|
sprintf(subFacilityName, "FilePlay:%x", this);
|
tracer.SetSubFacilityName(subFacilityName);
|
SetTraceLevel();
|
InitializeCriticalSection(&stateMutex);
|
stateChangedEvent = CreateEvent(NULL, NULL, FALSE, NULL);
|
this->bTransmit = bTransmit;
|
waveFileSource = new WaveFileSource();
|
waveFileSource->AddFilePlayListener(this);
|
acmTransformer = new ACMTransformer();
|
acmTransformer->SetOutputDuration(outputDuration);
|
pcmVolumeTransformer = new PCMVolumeTransformer();
|
this->audioSink = NULL; // will be set in the call to Connect(audioSink) below
|
currentState = STATE_STOPPED;
|
|
::Connect(waveFileSource, acmTransformer);
|
::Connect(acmTransformer, pcmVolumeTransformer);
|
Connect(audioSink);
|
|
cookie = ++nextCookie;
|
}
|
|
FilePlay::~FilePlay()
|
{
|
StopImmediately();
|
Disconnect();
|
delete waveFileSource;
|
delete acmTransformer;
|
delete pcmVolumeTransformer;
|
DeleteCriticalSection(&stateMutex);
|
CloseHandle(stateChangedEvent);
|
}
|
|
int
|
FilePlay::SetTraceLevel() {
|
long SystemMask = 0;
|
GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "FilePlay", 0x100000);
|
if ((SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "AllComponents", 0x0)) == 0)
|
SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "FilePlay", 0x100000);
|
tracer.SetSystemMask(SystemMask);
|
return NOERROR;
|
}
|
|
bool
|
FilePlay::IsRunning()
|
{
|
tracer.tracef(EE, "IsRunning\n");
|
bool isRunning(true);
|
tracer.tracef(ARB, "IsRunning : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState == STATE_STOPPED)
|
{
|
isRunning = false;
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "IsRunning : left stateMutex\n");
|
tracer.tracef(EE, "~IsRunning : returning %d\n", isRunning);
|
return isRunning;
|
}
|
|
int
|
FilePlay::LoadFile(const char *fileName)
|
{
|
tracer.tracef(EE, "LoadFile %s\n", fileName);
|
int result = waveFileSource->OpenWaveFile(fileName);
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "LoadFile : e-waveFileSource->OpenWaveFile : %d\n", result);
|
}
|
tracer.tracef(EE, "~LoadFile : %d\n", result);
|
return result;
|
}
|
|
int
|
FilePlay::PlayOnce()
|
{
|
tracer.tracef(EE, "PlayOnce\n");
|
int result = waveFileSource->PlayOnce();
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "LoadFile : e-waveFileSource->PlayOnce : %d\n", result);
|
}
|
tracer.tracef(EE, "~PlayOnce : %d\n", result);
|
return result;
|
}
|
|
int
|
FilePlay::PlayInLoop()
|
{
|
tracer.tracef(EE, "PlayInLoop\n");
|
int result = waveFileSource->PlayInLoop();
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "LoadFile : e-waveFileSource->PlayInLoop : %d\n", result);
|
}
|
tracer.tracef(EE, "~PlayInLoop : %d\n", result);
|
return result;
|
}
|
|
int
|
FilePlay::Start()
|
{
|
tracer.tracef(EE, "Start\n");
|
int returnCode(0);
|
tracer.tracef(ARB, "Start : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start : currentState = %d\n", currentState);
|
bool startNeeded = false;
|
switch(currentState)
|
{
|
case STATE_STOPPED:
|
currentState = STATE_STARTING;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "Start STATE_STOPPED: setting stateChangedEvent. Went to STATE_STARTING\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start STATE_STOPPED: left stateMutex\n");
|
returnCode = 0;
|
startNeeded = true;
|
break;
|
case STATE_RUNNING:
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start STATE_RUNNING: left stateMutex\n");
|
returnCode = 0;
|
break;
|
case STATE_STARTING:
|
while (currentState != STATE_RUNNING && currentState != STATE_STOPPED)
|
{
|
tracer.tracef(ARB, "Start STATE_STARTING: currentState = %d\n", currentState);
|
ResetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "Start STATE_STARTING: resetting stateChangedEvent\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start STATE_STARTING: left stateMutex\n");
|
tracer.tracef(ARB, "Start STATE_STARTING: waiting for stateChangedEvent\n");
|
WaitForSingleObject(stateChangedEvent, INFINITE);
|
tracer.tracef(ARB, "Start STATE_STARTING: entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
}
|
if (currentState == STATE_STOPPED)
|
{
|
tracer.tracef(ERR, "Start STATE_STARTING: went to STATE_STOPPED ! Returning error\n");
|
returnCode = -10;
|
}
|
else
|
{
|
returnCode = 0;
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start STATE_STARTING: left stateMutex\n");
|
break;
|
case STATE_STOPPING:
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start STATE_STOPPING: left stateMutex\n");
|
tracer.tracef(ERR, "Start STATE_STOPPING: invalid state to call Start\n");
|
returnCode = -20;
|
break;
|
default:
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start default: left stateMutex\n");
|
tracer.tracef(ERR, "Start default: Error : invalid current state %d\n", currentState);
|
returnCode = -30;
|
break;
|
}
|
|
if (returnCode == 0 && startNeeded)
|
{
|
int result(0);
|
tracer.tracef(ARB, "Start : bRunning = false\n");
|
WAVEFORMATEX wfx;
|
do
|
{
|
tracer.tracef(DET, "Start : calling waveFileSource->GetFormat\n");
|
result = waveFileSource->GetFormat(&wfx);
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "Start : e-waveFileSource->GetFormat : %d %x\n", result, result);
|
returnCode = -35;
|
break;
|
}
|
tracer.tracef(DET, "Start : calling acmTransformer->SetSourceFormat\n");
|
result = acmTransformer->SetSourceFormat(wfx);
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "Start : e-acmTransformer->SetSourceFormat : %d %x\n", result, result);
|
returnCode = -40;
|
break;
|
}
|
tracer.tracef(DET, "Start : calling pcmVolumeTransformer->StartTransform\n");
|
result = pcmVolumeTransformer->StartTransform();
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "Start : e-pcmVolumeTransformer->StartTransform : %d %x\n", result, result);
|
returnCode = -50;
|
break;
|
}
|
tracer.tracef(DET, "Start : calling acmTransformer->StartTransform\n");
|
result = acmTransformer->StartTransform();
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "Start : e-acmTransformer->StartTransform : %d %x\n", result, result);
|
pcmVolumeTransformer->StopTransform();
|
returnCode = -60;
|
break;
|
}
|
tracer.tracef(DET, "Start : calling waveFileSource->StartSourceThread\n");
|
waveFileSource->StartSourceThread();
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "Start : e-waveFileSource->StartSourceThread : %d %x\n", result, result);
|
pcmVolumeTransformer->StopTransform();
|
acmTransformer->StopTransform();
|
returnCode = -70;
|
break;
|
}
|
} while (false);
|
if (returnCode == 0)
|
{
|
// this means start was successful. then FilePlayStarted would have
|
// set the current State to STATE_RUNNING
|
tracer.tracef(ARB, "Start : successful start\n");
|
}
|
else
|
{
|
tracer.tracef(ARB, "Start : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
tracer.tracef(ERR, "Start : unsuccessful start. Going to STOPPED state\n");
|
currentState = STATE_STOPPED;
|
tracer.tracef(ARB, "Start : setting stateChangedEvent. Went to STATE_STOPPED\n");
|
SetEvent(stateChangedEvent);
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Start : left stateMutex\n");
|
}
|
}
|
if (returnCode == 0)
|
{
|
tracer.tracef(EE, "~Start : success\n");
|
}
|
else
|
{
|
tracer.tracef(ERR, "~Start : e-Start : failure : returnCode = %d\n", returnCode);
|
}
|
return returnCode;
|
}
|
|
void FilePlay::Cleanup()
|
{
|
tracer.tracef(EE, "Cleanup\n");
|
tracer.tracef(ARB, "Cleanup : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState != STATE_STOPPING)
|
{
|
tracer.tracef(ERR, "Cleanup : invalid state %d to call Cleanup\n", currentState);
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Cleanup : left stateMutex\n");
|
tracer.tracef(ARB, "Cleanup : calling ::Disconnect(waveFileSource, acmTransformer)\n");
|
::Disconnect(waveFileSource, acmTransformer);
|
tracer.tracef(ARB, "Cleanup : calling acmTransformer->StopTransform\n");
|
acmTransformer->StopTransform();
|
tracer.tracef(ARB, "Cleanup : calling pcmVolumeTransformer->StopTransform\n");
|
pcmVolumeTransformer->StopTransform();
|
tracer.tracef(ARB, "Cleanup : calling ::Disconnect(acmTransformer, pcmVolumeTransformer)\n");
|
::Disconnect(acmTransformer, pcmVolumeTransformer);
|
tracer.tracef(ARB, "Cleanup : calling Disconnect\n");
|
Disconnect();
|
|
FireEventThreadParams *fetParams = new FireEventThreadParams();
|
fetParams->cookie = cookie;
|
DWORD threadID;
|
if (bTransmit)
|
{
|
tracer.tracef(ARB, "Cleanup : calling mediaTerm->FireEndOfFileTX\n");
|
fetParams->receiveSide = false;
|
}
|
else
|
{
|
tracer.tracef(ARB, "Cleanup : calling mediaTerm->FireEndOfFileRX\n");
|
fetParams->receiveSide = true;
|
}
|
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FireEventThread, (LPVOID)fetParams, 0, &threadID);
|
tracer.tracef(ARB, "CleanupImmediately : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState != STATE_STOPPING)
|
{
|
tracer.tracef(ERR, "Cleanup : invalid state %d to call Cleanup\n", currentState);
|
}
|
currentState = STATE_STOPPED;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "Cleanup : setting stateChangedEvent. Went to STATE_STOPPED\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "Cleanup : left stateMutex\n");
|
|
tracer.tracef(EE, "~Cleanup\n");
|
}
|
|
void FilePlay::CleanupImmediately()
|
{
|
tracer.tracef(EE, "CleanupImmediately\n");
|
tracer.tracef(ARB, "CleanupImmediately : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState != STATE_STOPPING)
|
{
|
tracer.tracef(ERR, "CleanupImmediately : invalid state %d to call CleanupImmediately\n", currentState);
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "CleanupImmediately : left stateMutex\n");
|
tracer.tracef(ARB, "CleanupImmediately : calling acmTransformer->StopTransform\n");
|
acmTransformer->StopTransform();
|
tracer.tracef(ARB, "CleanupImmediately : calling pcmVolumeTransformer->StopTransform\n");
|
pcmVolumeTransformer->StopTransform();
|
tracer.tracef(ARB, "CleanupImmediately : calling ::Disconnect(waveFileSource, acmTransformer)\n");
|
::Disconnect(waveFileSource, acmTransformer);
|
tracer.tracef(ARB, "CleanupImmediately : calling ::Disconnect(acmTransformer, pcmVolumeTransformer)\n");
|
::Disconnect(acmTransformer, pcmVolumeTransformer);
|
tracer.tracef(ARB, "CleanupImmediately : calling Disconnect\n");
|
Disconnect();
|
if (bTransmit)
|
{
|
tracer.tracef(ARB, "CleanupImmediately : calling mediaTerm->FireEndOfFileTX\n");
|
mediaTerm->FireEndOfFileTX(cookie);
|
}
|
else
|
{
|
tracer.tracef(ARB, "CleanupImmediately : calling mediaTerm->FireEndOfFileRX\n");
|
mediaTerm->FireEndOfFileRX(cookie);
|
}
|
tracer.tracef(ARB, "CleanupImmediately : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState != STATE_STOPPING)
|
{
|
tracer.tracef(ERR, "CleanupImmediately : invalid state %d to call CleanupImmediately\n", currentState);
|
}
|
currentState = STATE_STOPPED;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "CleanupImmediately : setting stateChangedEvent. Went to STATE_STOPPED\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "CleanupImmediately : left stateMutex\n");
|
tracer.tracef(EE, "~CleanupImmediately\n");
|
}
|
|
int
|
FilePlay::Stop()
|
{
|
tracer.tracef(ERR, "Stop : should not be called\n");
|
/* tracer.tracef(ARB, "Stop : calling waveFileSource->StopSourceThread\n");
|
waveFileSource->StopSourceThread();
|
tracer.tracef(ARB, "Stop : calling Cleanup\n");
|
Cleanup();
|
}
|
else
|
{
|
tracer.tracef(ARB, "Stop : bRunning = false\n");
|
}
|
*/ tracer.tracef(EE, "~Stop : did nothing\n");
|
return 0;
|
}
|
|
int
|
FilePlay::StopImmediately()
|
{
|
tracer.tracef(EE, "StopImmediately\n");
|
int result(0);
|
bool stopNeeded(false);
|
tracer.tracef(ARB, "StopImmediately : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately : currentState = %d\n", currentState);
|
switch(currentState)
|
{
|
case STATE_STOPPED:
|
result = 0;
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPED: already stopped\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPED: left stateMutex\n");
|
break;
|
case STATE_STARTING:
|
result = -10;
|
tracer.tracef(ARB, "StopImmediately STATE_STARTING: invalid state to call StopImmediately\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately STATE_STARTING: left stateMutex\n");
|
break;
|
case STATE_RUNNING:
|
result = 0;
|
stopNeeded = true;
|
currentState = STATE_STOPPING;
|
tracer.tracef(ARB, "StopImmediately STATE_RUNNING: trying to stop the file play\n");
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "StopImmediately STATE_RUNNING: setting stateChangedEvent. Went to STATE_STOPPING\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately STATE_RUNNING: left stateMutex\n");
|
break;
|
case STATE_STOPPING:
|
while(currentState != STATE_STOPPED)
|
{
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: current state = %d\n", currentState);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: resetting stateChangedEvent\n");
|
ResetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: flushing acmTransformer buffer\n");
|
acmTransformer->FlushBuffer();
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: left stateMutex\n");
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: waiting for stateChangedEvent\n");
|
WaitForSingleObject(stateChangedEvent, INFINITE);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately STATE_STOPPING: left stateMutex\n");
|
result = 0;
|
stopNeeded = false;
|
break;
|
default:
|
tracer.tracef(ARB, "StopImmediately default : invalid state %d\n", currentState);
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately default : left stateMutex\n");
|
break;
|
}
|
|
if (result == 0 && stopNeeded)
|
{
|
// in case we are already stopping because file ran out, then we need to stop
|
// right away before buffer is finished. Guarantees that FilePlayStopped will
|
// return soon so entering stateMutex will not wait forever
|
tracer.tracef(ARB, "StopImmediately : flushing acmTransformer buffer\n");
|
acmTransformer->FlushBuffer();
|
tracer.tracef(ARB, "StopImmediately : calling acmTransformer->StopTransform\n");
|
acmTransformer->StopTransform();
|
tracer.tracef(ARB, "StopImmediately : calling waveFileSource->StopSourceThread\n");
|
waveFileSource->StopSourceThread();
|
tracer.tracef(ARB, "StopImmediately : calling CleanupImmediately\n");
|
CleanupImmediately();
|
tracer.tracef(ARB, "Start : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
currentState = STATE_STOPPED;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "StopImmediately : setting stateChangedEvent. Went to STATE_STOPPED\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "StopImmediately : left stateMutex\n");
|
}
|
if (result == 0)
|
{
|
tracer.tracef(EE, "~StopImmediately\n");
|
}
|
else
|
{
|
tracer.tracef(ERR, "~StopImmediately : returning %d\n", result);
|
}
|
return result;
|
}
|
|
int
|
FilePlay::SetVolume(int volume)
|
{
|
tracer.tracef(EE, "SetVolume %d\n", volume);
|
int result = pcmVolumeTransformer->SetVolume(volume);
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "SetVolume : e-pcmVolumeTransformer->SetVolume : %d\n", result);
|
}
|
tracer.tracef(EE, "~SetVolume : %d\n", result);
|
return result;
|
}
|
|
int
|
FilePlay::GetVolume()
|
{
|
tracer.tracef(EE, "GetVolume\n");
|
int result = pcmVolumeTransformer->GetVolume();
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "GetVolume : e-pcmVolumeTransformer->GetVolume: %d\n", result);
|
}
|
tracer.tracef(EE, "~GetVolume : %d\n", result);
|
return result;
|
}
|
|
unsigned int
|
FilePlay::GetCookie()
|
{
|
return cookie;
|
}
|
|
int
|
FilePlay::Connect(AudioSink *audioSink)
|
{
|
tracer.tracef(EE, "Connect\n");
|
tracer.tracef(ARB, "Connect : calling Disconnect\n");
|
Disconnect();
|
if (audioSink)
|
{
|
tracer.tracef(ARB, "Connect : calling ::Connect(pcmVolumeTransformer, audioSink)\n");
|
::Connect(pcmVolumeTransformer, audioSink);
|
}
|
this->audioSink = audioSink;
|
tracer.tracef(EE, "~Connect\n");
|
return 0;
|
}
|
|
int
|
FilePlay::Disconnect()
|
{
|
tracer.tracef(EE, "Disconnect\n");
|
if (audioSink)
|
{
|
tracer.tracef(ARB, "Disconnect : calling ::Disconnect(pcmVolumeTransformer, audioSink)\n");
|
::Disconnect(pcmVolumeTransformer, audioSink);
|
}
|
audioSink = NULL;
|
tracer.tracef(EE, "~Disconnect\n");
|
return 0;
|
}
|
|
void
|
FilePlay::FilePlayStarted(WaveFileSource *waveFileSource, char *waveFileName)
|
{
|
tracer.tracef(EE, "FilePlayStarted : %s\n", waveFileName);
|
tracer.tracef(ARB, "FilePlayStarted : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
if (currentState != STATE_STARTING)
|
{
|
tracer.tracef(ERR, "FilePlayStarted : invalid current state %d\n", currentState);
|
}
|
currentState = STATE_RUNNING;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "FilePlayStarted : setting stateChangedEvent. Went to STATE_RUNNING\n");
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "FilePlayStarted : left stateMutex\n");
|
tracer.tracef(EE, "~FilePlayStarted\n");
|
}
|
|
void
|
FilePlay::FilePlayStopped(WaveFileSource *waveFileSource, char *waveFileName)
|
{
|
tracer.tracef(EE, "FilePlayStopped : %s\n", waveFileName);
|
bool needToCallCleanup = false;
|
tracer.tracef(ARB, "FilePlayStopped : entering stateMutex\n");
|
EnterCriticalSection(&stateMutex);
|
// if we are in STATE_STOPPING this is because StopImmediately was called
|
// StopImmediately will call CleanupImmediately which will also set the
|
// state to STATE_STOPPED
|
if (currentState != STATE_RUNNING && currentState != STATE_STOPPING)
|
{
|
tracer.tracef(ERR, "FilePlayStopped : invalid current state %d\n", currentState);
|
}
|
if (currentState == STATE_RUNNING)
|
{
|
tracer.tracef(ARB, "FilePlayStopped : currently RUNNING. need to call cleanup\n");
|
needToCallCleanup = true;
|
currentState = STATE_STOPPING;
|
SetEvent(stateChangedEvent);
|
tracer.tracef(ARB, "FilePlayStopped : setting stateChangedEvent. Went to STATE_STOPPING\n");
|
}
|
LeaveCriticalSection(&stateMutex);
|
tracer.tracef(ARB, "FilePlayStopped : left stateMutex\n");
|
if (needToCallCleanup)
|
{
|
tracer.tracef(ARB, "FilePlayStopped : calling Cleanup\n");
|
Cleanup();
|
// Cleanup will set the state to STATE_STOPPED
|
}
|
tracer.tracef(EE, "~FilePlayStopped\n");
|
}
|
|
int
|
FilePlay::SetOutputDuration(int outputDuration)
|
{
|
tracer.tracef(EE, "SetOutputDuration %d\n", outputDuration);
|
int result = acmTransformer->SetOutputDuration(outputDuration);
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "SetOutputDuration : e-acmTransformer->SetOutputDuration : %d\n", result);
|
}
|
tracer.tracef(EE, "~SetOutputDuration : %d\n", result);
|
return result;
|
}
|
|
int
|
FilePlay::SetDestinationFormat(WAVEFORMATEX wfx)
|
{
|
tracer.tracef(EE, "SetDestinationFormat\n");
|
int result = acmTransformer->SetDestinationFormat(wfx);
|
if (result != 0)
|
{
|
tracer.tracef(ERR, "SetDestinationFormat : e-acmTransformer->SetDestinationFormat : %d\n", result);
|
}
|
tracer.tracef(EE, "~SetDestinationFormat : %d\n", result);
|
return result;
|
}
|
|
bool
|
FilePlay::Transmitting()
|
{
|
return bTransmit;
|
}
|