/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include "functionTest.h" #include "event_wrapper.h" #include "trace.h" #include "thread_wrapper.h" #include "webrtc_vad.h" #if (defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)) #include #define MY_PERMISSION_MASK S_IRWXU | S_IRWXG | S_IRWXO #define MKDIR(directory) mkdir(directory,MY_PERMISSION_MASK) #else // defined(WINDOWS) #include #define MKDIR(directory) mkdir(directory) #endif int main(int /*argc*/, char* /*argv[]*/) { // Initialize random number generator //unsigned int seed = 1220716312; // just a seed that can be used unsigned int seed = (unsigned)time( NULL ); srand(seed); std::cout << "Starting function test. Seed = " << seed << std::endl; std::cout << "Press enter to continue" << std::endl; getchar(); MixerWrapper* testInstance1 = MixerWrapper::CreateMixerWrapper(); MixerWrapper* testInstance2 = MixerWrapper::CreateMixerWrapper(); if((testInstance1 == NULL) || (testInstance2 == NULL)) { assert(false); return 0; } char versionString[256] = ""; WebRtc_UWord32 remainingBufferInBytes = 256; WebRtc_UWord32 position = 0; AudioConferenceMixer::GetVersion(versionString,remainingBufferInBytes,position); int read = 1; while(read != 0) { std::cout << versionString << std::endl; std::cout << "--------Menu-----------" << std::endl; std::cout << std::endl; std::cout << "0. Quit" << std::endl; std::cout << "2. StartMixing" << std::endl; std::cout << "3. StopMixing" << std::endl; std::cout << "4. Create participant(s)" << std::endl; std::cout << "5. Delete participant(s)" << std::endl; std::cout << "6. List participants " << std::endl; std::cout << "7. Print mix status " << std::endl; std::cout << "8. Run identical scenario:" << std::endl; std::cout << " a. 1 VIP, 3 regular, amount of mixed = 3" << std::endl; std::cout << " b. 1 anonymous, 3 regular, amount of mixed = 2" << std::endl; scanf("%i",&read); getchar(); MixerParticipant::ParticipantType participantType; int option = 0; WebRtc_UWord32 id = 0; ListItem* item = NULL; ListWrapper participants; if(read == 0) { // donothing } else if(read == 1) { } else if(read == 2) { testInstance1->StartMixing(); } else if(read == 3) { testInstance1->StopMixing(); } else if(read == 4) { while(true) { std::cout << "VIP(music) = " << MixerParticipant::VIP << std::endl; std::cout << "Regular(speech) = " << MixerParticipant::REGULAR << std::endl; std::cout << "Anonymous(music) = " << MixerParticipant::MIXED_ANONYMOUS << std::endl; std::cout << "Select type of participant: "; scanf("%i",&option); if(option == MixerParticipant::VIP || option == MixerParticipant::REGULAR || option == MixerParticipant::MIXED_ANONYMOUS) { break; } } participantType = (MixerParticipant::ParticipantType)option; testInstance1->CreateParticipant(participantType); } else if(read == 5) { std::cout << "Select participant to delete: "; scanf("%i",&option); id = option; testInstance1->DeleteParticipant(id); break; } else if(read == 6) { testInstance1->GetParticipantList(participants); item = participants.First(); std::cout << "The following participants have been created: " << std::endl; while(item) { WebRtc_UWord32 id = item->GetUnsignedItem(); std::cout << id; item = participants.Next(item); if(item != NULL) { std::cout << ", "; } else { std::cout << std::endl; } } } else if(read == 7) { std::cout << "-------------Mixer Status-------------" << std::endl; testInstance1->PrintStatus(); testInstance2->PrintStatus(); std::cout << "Press enter to continue"; getchar(); std::cout << std::endl; std::cout << std::endl; } else if(read == 8) { const WebRtc_Word32 amountOfParticipants = 4; MixerParticipant::ParticipantType instance1Participants[] = {MixerParticipant::VIP, MixerParticipant::REGULAR, MixerParticipant::REGULAR, MixerParticipant::REGULAR}; MixerParticipant::ParticipantType instance2Participants[] = {MixerParticipant::MIXED_ANONYMOUS, MixerParticipant::REGULAR, MixerParticipant::REGULAR, MixerParticipant::REGULAR}; for(WebRtc_Word32 i = 0; i < amountOfParticipants; i++) { WebRtc_Word32 startPosition = 0; GenerateRandomPosition(startPosition); testInstance1->CreateParticipant(instance1Participants[i],startPosition); testInstance2->CreateParticipant(instance2Participants[i],startPosition); } bool success = true; success = testInstance1->StartMixing(); assert(success); success = testInstance2->StartMixing(2); assert(success); } } std::cout << "Press enter to stop" << std::endl; getchar(); delete testInstance1; delete testInstance2; return 0; } FileWriter::FileWriter() : _file(NULL) { } FileWriter::~FileWriter() { if(_file) { fclose(_file); } } bool FileWriter::SetFileName( const char* fileName) { if(_file) { fclose(_file); } _file = fopen(fileName,"wb"); return _file != NULL; } bool FileWriter::WriteToFile( const AudioFrame& audioFrame) { WebRtc_Word32 written = (WebRtc_Word32)fwrite(audioFrame._payloadData,sizeof(WebRtc_Word16),audioFrame._payloadDataLengthInSamples,_file); // Do not flush buffers since that will add (a lot of) delay return written == audioFrame._payloadDataLengthInSamples; } FileReader::FileReader() : _frequency(kDefaultFrequency), _sampleSize((_frequency*kProcessPeriodicityInMs)/1000), _timeStamp(0), _file(NULL), _vadInstr(NULL), _automaticVad(false), _vad(false) { if(WebRtcVad_Create(&_vadInstr) == 0) { if(WebRtcVad_Init(_vadInstr) != 0) { assert(false); WebRtcVad_Free(_vadInstr); _vadInstr = NULL; } } else { assert(false); } } FileReader::~FileReader() { if(_file) { fclose(_file); } if(_vadInstr) { WebRtcVad_Free(_vadInstr); } } bool FileReader::SetFileName( const char* fileName) { if(_file) { fclose(_file); } _file = fopen(fileName,"rb"); return _file != NULL; } bool FileReader::ReadFromFile( AudioFrame& audioFrame) { WebRtc_Word16 buffer[AudioFrame::kMaxAudioFrameSizeSamples]; LoopedFileRead(buffer,AudioFrame::kMaxAudioFrameSizeSamples,_sampleSize,_file); bool vad = false; GetVAD(buffer,_sampleSize,vad); AudioFrame::VADActivity activity = vad ? AudioFrame::kVadActive : AudioFrame::kVadPassive; _volumeCalculator.ComputeLevel(buffer,_sampleSize); const WebRtc_Word32 level = _volumeCalculator.GetLevel(); return audioFrame.UpdateFrame( -1, _timeStamp, buffer, _sampleSize, _frequency, AudioFrame::kNormalSpeech, activity, 0, level) == 0; } bool FileReader::FastForwardFile( const WebRtc_Word32 samples) { WebRtc_Word16* tempBuffer = new WebRtc_Word16[samples]; bool success = LoopedFileRead(tempBuffer,samples,samples,_file); delete[] tempBuffer; return success; } bool FileReader::EnableAutomaticVAD( bool enable, int mode) { if(!_automaticVad && enable) { if(WebRtcVad_Init(_vadInstr) == -1) { return false; } } WebRtcVad_set_mode(_vadInstr,mode); _automaticVad = enable; return true; } bool FileReader::SetVAD( bool vad) { if(_automaticVad) { return false; } _vad = vad; return true; } bool FileReader::GetVAD( WebRtc_Word16* buffer, WebRtc_UWord8 bufferLengthInSamples, bool& vad) { if(_automaticVad) { WebRtc_Word16 result = WebRtcVad_Process(_vadInstr,_frequency,buffer,bufferLengthInSamples); if(result == -1) { assert(false); return false; } _vad = vad = (result == 1); } vad = _vad; return true; } MixerParticipant* MixerParticipant::CreateParticipant( const WebRtc_UWord32 id, ParticipantType participantType, const WebRtc_Word32 startPosition, char* outputPath) { if(participantType == RANDOM) { participantType = (ParticipantType)(rand() % 3); } MixerParticipant* participant = new MixerParticipant(id,participantType); // Randomize the start position so we only need one input file // assume file is smaller than 1 minute wideband = 60 * 16000 // Always start at a multiple of 10ms wideband if(!participant->InitializeFileReader(startPosition) || !participant->InitializeFileWriter(outputPath)) { delete participant; return NULL; } return participant; } MixerParticipant::MixerParticipant( const WebRtc_UWord32 id, ParticipantType participantType) : _id(id), _participantType(participantType), _fileReader(), _fileWriter() { } MixerParticipant::~MixerParticipant() { } WebRtc_Word32 MixerParticipant::GetAudioFrame( const WebRtc_Word32 /*id*/, AudioFrame& audioFrame) { if(!_fileReader.ReadFromFile(audioFrame)) { return -1; } audioFrame._id = _id; return 0; } WebRtc_Word32 MixerParticipant::MixedAudioFrame( const AudioFrame& audioFrame) { return _fileWriter.WriteToFile(audioFrame); } WebRtc_Word32 MixerParticipant::GetParticipantType( ParticipantType& participantType) { participantType = _participantType; return 0; } bool MixerParticipant::InitializeFileReader( const WebRtc_Word32 startPositionInSamples) { char fileName[128] = ""; if(_participantType == REGULAR) { sprintf(fileName,"convFile.pcm"); } else { sprintf(fileName,"musicFile.pcm"); } if(!_fileReader.SetFileName(fileName)) { return false; } if(!_fileReader.EnableAutomaticVAD(true,2)) { assert(false); } return _fileReader.FastForwardFile(startPositionInSamples); } bool MixerParticipant::InitializeFileWriter( char* outputPath) { const WebRtc_Word32 stringsize = 128; char fileName[stringsize] = ""; strncpy(fileName,outputPath,stringsize); fileName[stringsize-1] = '\0'; char tempName[stringsize]; tempName[0] = '\0'; sprintf(tempName,"outputFile%d.pcm",(int)_id); strncat(fileName,tempName,(stringsize - strlen(fileName))); fileName[stringsize-1] = '\0'; return _fileWriter.SetFileName(fileName); } StatusReceiver::StatusReceiver( const WebRtc_Word32 id) : _id(id), _mixedParticipants(NULL), _mixedParticipantsAmount(0), _mixedParticipantsSize(0), _vadPositiveParticipants(NULL), _vadPositiveParticipantsAmount(0), _vadPositiveParticipantsSize(0), _mixedAudioLevel(0) { } StatusReceiver::~StatusReceiver() { delete[] _mixedParticipants; delete[] _vadPositiveParticipants; } void StatusReceiver::MixedParticipants( const WebRtc_Word32 id, const ParticipantStatistics* participantStatistics, const WebRtc_UWord32 size) { if(id != _id) { assert(false); } if(_mixedParticipantsSize < size) { delete[] _mixedParticipants; _mixedParticipantsSize = size; _mixedParticipants = new ParticipantStatistics[size]; } _mixedParticipantsAmount = size; memcpy(_mixedParticipants,participantStatistics,sizeof(ParticipantStatistics)*size); } void StatusReceiver::VADPositiveParticipants( const WebRtc_Word32 id, const ParticipantStatistics* participantStatistics, const WebRtc_UWord32 size) { if(id != _id) { assert(false); } if(_vadPositiveParticipantsSize < size) { delete[] _vadPositiveParticipants; _vadPositiveParticipantsSize = size; _vadPositiveParticipants = new ParticipantStatistics[size]; } _vadPositiveParticipantsAmount = size; memcpy(_vadPositiveParticipants,participantStatistics,sizeof(ParticipantStatistics)*size); } void StatusReceiver::MixedAudioLevel( const WebRtc_Word32 id, const WebRtc_UWord32 level) { if(id != _id) { assert(false); } _mixedAudioLevel = level; } void StatusReceiver::PrintMixedParticipants() { std::cout << "Mixed participants" << std::endl; if(_mixedParticipantsAmount == 0) { std::cout << "N/A" << std::endl; } for(WebRtc_UWord16 i = 0; i < _mixedParticipantsAmount; i++) { std::cout << i + 1 << ". Participant " << _mixedParticipants[i].participant << ": level = " << _mixedParticipants[i].level << std::endl; } } void StatusReceiver::PrintVadPositiveParticipants() { std::cout << "VAD positive participants" << std::endl; if(_mixedParticipantsAmount == 0) { std::cout << "N/A" << std::endl; } for(WebRtc_UWord16 i = 0; i < _mixedParticipantsAmount; i++) { std::cout << i + 1 << ". Participant " << _mixedParticipants[i].participant << ": level = " << _mixedParticipants[i].level << std::endl; } } void StatusReceiver::PrintMixedAudioLevel() { std::cout << "Mixed audio level = " << _mixedAudioLevel << std::endl; } WebRtc_Word32 MixerWrapper::_mixerWrapperIdCounter = 0; MixerWrapper::MixerWrapper() : _processThread(NULL), _threadId(0), _firstProcessCall(true), _previousTime(), _periodicityInTicks(TickTime::MillisecondsToTicks(FileReader::kProcessPeriodicityInMs)), _synchronizationEvent(EventWrapper::Create()), _freeItemIds(), _itemIdCounter(0), _mixerParticipants(), _mixerWrappererId(_mixerWrapperIdCounter++), _instanceOutputPath(), _trace(NULL), _statusReceiver(_mixerWrappererId), _generalAudioWriter() { sprintf(_instanceOutputPath,"instance%d/",(int)_mixerWrappererId); MKDIR(_instanceOutputPath); _mixer = AudioConferenceMixer::CreateAudioConferenceMixer( _mixerWrappererId); if(_mixer != NULL) { bool success = true; success = _mixer->RegisterMixedStreamCallback(*this) == 0; assert(success); success = _mixer->RegisterMixedStreamCallback(*this) == -1; assert(success); success = _mixer->UnRegisterMixedStreamCallback() == 0; assert(success); success = _mixer->UnRegisterMixedStreamCallback() == -1; assert(success); success = _mixer->RegisterMixedStreamCallback(*this) == 0; assert(success); success = _mixer->RegisterMixerStatusCallback(_statusReceiver,2) == 0; assert(success); success = _mixer->RegisterMixerStatusCallback(_statusReceiver,1) == -1; assert(success); success = _mixer->UnRegisterMixerStatusCallback() == 0; assert(success); success = _mixer->UnRegisterMixerStatusCallback() == -1; assert(success); success = _mixer->RegisterMixerStatusCallback(_statusReceiver,1) == 0; assert(success); } else { assert(false); std::cout << "Failed to create mixer instance"; } } MixerWrapper* MixerWrapper::CreateMixerWrapper() { MixerWrapper* mixerWrapper = new MixerWrapper(); if(!mixerWrapper->InitializeFileWriter()) { delete mixerWrapper; return NULL; } return mixerWrapper; } MixerWrapper::~MixerWrapper() { StopMixing(); ClearAllItemIds(); _synchronizationEvent->StopTimer(); delete _synchronizationEvent; delete _mixer; } bool MixerWrapper::CreateParticipant( MixerParticipant::ParticipantType participantType) { WebRtc_Word32 startPosition = 0; GenerateRandomPosition(startPosition); return CreateParticipant(participantType,startPosition); } bool MixerWrapper::CreateParticipant( MixerParticipant::ParticipantType participantType, const WebRtc_Word32 startPosition) { WebRtc_UWord32 id; if(!GetFreeItemIds(id)) { return false; } MixerParticipant* participant = MixerParticipant::CreateParticipant(id,participantType,startPosition,_instanceOutputPath); if(!participant) { return false; } if(_mixerParticipants.Insert(id,static_cast(participant)) != 0) { delete participant; return false; } if(!StartMixingParticipant(id)) { DeleteParticipant(id); return false; } return true; } bool MixerWrapper::DeleteParticipant( const WebRtc_UWord32 id) { bool success = StopMixingParticipant(id); if(!success) { assert(false); return false; } MapItem* item = _mixerParticipants.Find(id); if(item == NULL) { return false; } MixerParticipant* participant = static_cast(item->GetItem()); delete participant; _mixerParticipants.Erase(item); AddFreeItemIds(id); return true; } bool MixerWrapper::StartMixing( const WebRtc_UWord32 mixedParticipants) { if(_processThread) { return false; } if(_mixer->SetAmountOfMixedParticipants(mixedParticipants) != 0) { assert(false); } WebRtc_UWord32 mixedParticipantsTest = 0; _mixer->AmountOfMixedParticipants(mixedParticipantsTest); assert(mixedParticipantsTest == mixedParticipants); if(!_synchronizationEvent->StartTimer(true,10)) { assert(false); return false; } _processThread = ThreadWrapper::CreateThread(Process, this, kLowPriority); if(!_processThread->Start(_threadId)) { delete _processThread; _processThread = NULL; assert(false); return false; } return true; } bool MixerWrapper::StopMixing() { while(_processThread && !_processThread->Stop()) {} _synchronizationEvent->StopTimer(); delete _processThread; _processThread = NULL; return true; } void MixerWrapper::NewMixedAudio( const WebRtc_Word32 id, const AudioFrame& generalAudioFrame, const AudioFrame** uniqueAudioFrames, const WebRtc_UWord32 size) { if(id < 0) { assert(false); } // Store the general audio _generalAudioWriter.WriteToFile(generalAudioFrame); // Send the unique audio frames to its corresponding participants ListWrapper uniqueAudioFrameList; for(WebRtc_UWord32 i = 0; i < size; i++) { WebRtc_UWord32 id = (uniqueAudioFrames[i])->_id; MapItem* resultItem = _mixerParticipants.Find(id); if(resultItem == NULL) { assert(false); continue; } MixerParticipant* participant = static_cast(resultItem->GetItem()); participant->MixedAudioFrame(*(uniqueAudioFrames[i])); uniqueAudioFrameList.PushBack(resultItem->GetItem()); } // Send the general audio frames to the remaining participants MapItem* item = _mixerParticipants.First(); while(item) { bool isUnique = false; ListItem* compareItem = uniqueAudioFrameList.First(); while(compareItem) { if(compareItem->GetItem() == item->GetItem()) { isUnique = true; break; } compareItem = uniqueAudioFrameList.Next(compareItem); } if(!isUnique) { MixerParticipant* participant = static_cast(item->GetItem()); participant->MixedAudioFrame(generalAudioFrame); } item = _mixerParticipants.Next(item); } } bool MixerWrapper::GetParticipantList( ListWrapper& participants) { MapItem* item = _mixerParticipants.First(); while(item) { participants.PushBack(item->GetId()); item = _mixerParticipants.Next(item); } return true; } void MixerWrapper::PrintStatus() { std::cout << "instance " << _mixerWrappererId << std::endl; std::cout << std::endl; _statusReceiver.PrintMixedParticipants(); std::cout << std::endl; _statusReceiver.PrintVadPositiveParticipants(); std::cout << std::endl; _statusReceiver.PrintMixedAudioLevel(); std::cout << "---------------------------------------" << std::endl; } bool MixerWrapper::InitializeFileWriter() { const WebRtc_Word32 stringsize = 128; char fileName[stringsize] = ""; strncpy(fileName,_instanceOutputPath,stringsize); fileName[stringsize-1] = '\0'; strncat(fileName,"generalOutputFile.pcm",(stringsize - strlen(fileName))); fileName[stringsize-1] = '\0'; return _generalAudioWriter.SetFileName(fileName); } bool MixerWrapper::Process( void* instance) { MixerWrapper* mixerWrapper = static_cast(instance); return mixerWrapper->Process(); } bool MixerWrapper::Process() { switch(_synchronizationEvent->Wait(1000)) { case kEventSignaled: // Normal operation, ~10 ms has passed break; case kEventError: // Error occured end the thread and throw an assertion assert(false); return false; case kEventTimeout: // One second has passed without a timeout something is wrong // end the thread and throw an assertion assert(false); return false; } WebRtc_Word32 processOfset = 0; const TickTime currentTime = TickTime::Now(); if(_firstProcessCall) { _previousTime = TickTime::Now(); _firstProcessCall = false; } else { TickInterval deltaTime = (currentTime - _previousTime); _previousTime += _periodicityInTicks; processOfset = (WebRtc_Word32) deltaTime.Milliseconds(); processOfset -= FileReader::kProcessPeriodicityInMs; } _mixer->Process(); WebRtc_Word32 timeUntilNextProcess = _mixer->TimeUntilNextProcess(); if(processOfset > FileReader::kProcessPeriodicityInMs) { std::cout << "Performance Warning: Process running " << processOfset << " too slow" << std::endl; _previousTime = currentTime; if(timeUntilNextProcess > 0) { std::cout << "Performance Warning: test performance and module performance missmatch" << std::endl; } } else if(processOfset < -FileReader::kProcessPeriodicityInMs) { std::cout << "Performance Warning: Process running " << -processOfset << " too fast" << std::endl; _previousTime = currentTime; if(timeUntilNextProcess < FileReader::kProcessPeriodicityInMs) { std::cout << "Performance Warning: test performance and module performance missmatch" << std::endl; } } return true; } bool MixerWrapper::StartMixingParticipant( const WebRtc_UWord32 id) { MapItem* item = _mixerParticipants.Find(id); if(item == NULL) { return false; } MixerParticipant* participant = static_cast(item->GetItem()); MixerParticipant::ParticipantType participantType = MixerParticipant::REGULAR; participant->GetParticipantType(participantType); if(participantType == MixerParticipant::MIXED_ANONYMOUS) { bool anonymouslyMixed = false; bool success = _mixer->SetAnonymousMixabilityStatus(*participant,true) == 0; assert(success); success = _mixer->AnonymousMixabilityStatus(*participant,anonymouslyMixed) == 0; assert(success); assert(anonymouslyMixed); success = _mixer->SetAnonymousMixabilityStatus(*participant,true) == -1; assert(success); success = _mixer->SetAnonymousMixabilityStatus(*participant,false) == 0; assert(success); success = _mixer->AnonymousMixabilityStatus(*participant,anonymouslyMixed) == 0; assert(success); assert(!anonymouslyMixed); success = _mixer->SetAnonymousMixabilityStatus(*participant,false) == -1; assert(success); success = _mixer->SetAnonymousMixabilityStatus(*participant,true) == 0; assert(success); success = _mixer->AnonymousMixabilityStatus(*participant,anonymouslyMixed) == 0; assert(success); assert(anonymouslyMixed); return success; } WebRtc_UWord32 previousAmountOfMixableParticipants = 0; bool success = _mixer->AmountOfMixables(previousAmountOfMixableParticipants) == 0; assert(success); success = _mixer->SetMixabilityStatus(*participant,true) == 0; assert(success); success = _mixer->SetMixabilityStatus(*participant,true) == -1; assert(success); success = _mixer->SetMixabilityStatus(*participant,false) == 0; assert(success); success = _mixer->SetMixabilityStatus(*participant,false) == -1; assert(success); success = _mixer->SetMixabilityStatus(*participant,true) == 0; assert(success); if(!success) { return false; } WebRtc_UWord32 currentAmountOfMixableParticipants = 0; success = _mixer->AmountOfMixables(currentAmountOfMixableParticipants) == 0; assert(currentAmountOfMixableParticipants == previousAmountOfMixableParticipants + 1); bool mixable = true; success = _mixer->MixabilityStatus(*participant,mixable) == 0; assert(success); assert(mixable); if(participantType == MixerParticipant::REGULAR) { return true; } bool IsVIP = false; success = _mixer->SetVIPStatus(*participant,true) == 0; assert(success); success = _mixer->VIPStatus(*participant,IsVIP) == 0; assert(success); assert(IsVIP); success = _mixer->SetVIPStatus(*participant,true) == -1; assert(success); success = _mixer->SetVIPStatus(*participant,false) == 0; assert(success); success = _mixer->VIPStatus(*participant,IsVIP) == 0; assert(success); assert(!IsVIP); success = _mixer->SetVIPStatus(*participant,false) == -1; assert(success); success = _mixer->SetVIPStatus(*participant,true) == 0; assert(success); success = _mixer->VIPStatus(*participant,IsVIP) == 0; assert(success); assert(IsVIP); assert(success); return success; } bool MixerWrapper::StopMixingParticipant( const WebRtc_UWord32 id) { MapItem* item = _mixerParticipants.Find(id); if(item == NULL) { return false; } MixerParticipant* participant = static_cast(item->GetItem()); bool success = false; WebRtc_UWord32 previousAmountOfMixableParticipants = 0; success = _mixer->AmountOfMixables(previousAmountOfMixableParticipants) == 0; assert(success); success = _mixer->SetMixabilityStatus(*participant,false) == 0; assert(success); WebRtc_UWord32 currentAmountOfMixableParticipants = 0; success = _mixer->AmountOfMixables(currentAmountOfMixableParticipants) == 0; assert(success); assert(success ? currentAmountOfMixableParticipants == previousAmountOfMixableParticipants -1 : currentAmountOfMixableParticipants == previousAmountOfMixableParticipants); return success; } bool MixerWrapper::GetFreeItemIds( WebRtc_UWord32& itemId) { if(!_freeItemIds.Empty()) { ListItem* item = _freeItemIds.First(); WebRtc_UWord32* id = static_cast(item->GetItem()); itemId = *id; delete id; return true; } if(_itemIdCounter == (WebRtc_UWord32) -1) { return false; } itemId = _itemIdCounter++; return true; } void MixerWrapper::AddFreeItemIds( const WebRtc_UWord32 itemId) { WebRtc_UWord32* id = new WebRtc_UWord32; *id = itemId; _freeItemIds.PushBack(static_cast(id)); } void MixerWrapper::ClearAllItemIds() { ListItem* item = _freeItemIds.First(); while(item != NULL) { WebRtc_UWord32* id = static_cast(item->GetItem()); delete id; _freeItemIds.Erase(item); item = _freeItemIds.First(); } } bool LoopedFileRead( WebRtc_Word16* buffer, WebRtc_UWord32 bufferSizeInSamples, WebRtc_UWord32 samplesToRead, FILE* file) { if(bufferSizeInSamples < samplesToRead) { return false; } WebRtc_UWord32 gottenSamples = (WebRtc_UWord32)fread(buffer,sizeof(WebRtc_Word16),samplesToRead,file); if(gottenSamples != samplesToRead) { WebRtc_UWord32 missingSamples = samplesToRead - gottenSamples; fseek(file,0,0); gottenSamples += (WebRtc_UWord32)fread(&buffer[gottenSamples],sizeof(WebRtc_Word16),missingSamples,file); } if(gottenSamples != samplesToRead) { return false; } return true; } void GenerateRandomPosition( WebRtc_Word32& startPosition) { startPosition = (rand() % (60*16000/160)) * 160; }