From 066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619 Mon Sep 17 00:00:00 2001 From: "henrike@webrtc.org" Date: Fri, 28 Oct 2011 23:15:47 +0000 Subject: [PATCH] Ray, please verify that this cl fixes the issue. Once the verification has been made, please review: Henrik A: VoE Andrew: audio_conference_mixer Thanks! Review URL: http://webrtc-codereview.appspot.com/241010 git-svn-id: http://webrtc.googlecode.com/svn/trunk@841 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../interface/audio_conference_mixer.h | 10 ++ .../source/audio_conference_mixer_impl.cc | 106 +++++++++++++++++- .../source/audio_conference_mixer_impl.h | 8 ++ src/voice_engine/main/source/channel.cc | 28 +++++ src/voice_engine/main/source/output_mixer.cc | 7 ++ src/voice_engine/main/source/output_mixer.h | 3 + 6 files changed, 160 insertions(+), 2 deletions(-) diff --git a/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h b/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h index 82c40b5b4..c7b182d8e 100644 --- a/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h +++ b/src/modules/audio_conference_mixer/interface/audio_conference_mixer.h @@ -73,6 +73,16 @@ public: virtual WebRtc_Word32 AmountOfMixables( WebRtc_UWord32& amountOfMixableParticipants) = 0; + // Inform the mixer that the participant should always be mixed and not + // count toward the number of mixed participants. Note that a participant + // must have been added to the mixer (by calling SetMixabilityStatus()) + // before this function can be successfully called. + virtual WebRtc_Word32 SetAnonymousMixabilityStatus( + MixerParticipant& participant, const bool mixable) = 0; + // mixable is set to true if the participant is mixed anonymously. + virtual WebRtc_Word32 AnonymousMixabilityStatus( + MixerParticipant& participant, bool& mixable) = 0; + // Set the minimum sampling frequency at which to mix. The mixing algorithm // may still choose to mix at a higher samling frequency to avoid // downsampling of audio contributing to the mixed audio. diff --git a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc index 36c4a141f..7dae24bad 100644 --- a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc +++ b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.cc @@ -89,6 +89,7 @@ AudioConferenceMixerImpl::AudioConferenceMixerImpl(const WebRtc_Word32 id) _outputFrequency(kDefaultFrequency), _sampleSize((_outputFrequency*kProcessPeriodicityInMs)/1000), _participantList(), + _additionalParticipantList(), _amountOfMixableParticipants(0), _timeStamp(0), _timeScheduler(kProcessPeriodicityInMs), @@ -200,6 +201,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process() ListWrapper mixList; ListWrapper rampOutList; + ListWrapper additionalFramesList; MapWrapper mixedParticipantsMap; { CriticalSectionScoped cs(*_cbCrit); @@ -253,6 +255,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process() UpdateToMix(mixList, rampOutList, mixedParticipantsMap, remainingParticipantsAllowedToMix); + GetAdditionalAudio(additionalFramesList); UpdateMixedStatus(mixedParticipantsMap); _scratchParticipantsToMixAmount = mixedParticipantsMap.Size(); } @@ -297,6 +300,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process() _timeStamp += _sampleSize; MixFromList(*mixedAudio,mixList); + MixAnonomouslyFromList(*mixedAudio, additionalFramesList); MixAnonomouslyFromList(*mixedAudio, rampOutList); if(mixedAudio->_payloadDataLengthInSamples == 0) @@ -353,6 +357,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process() _audioFramePool->PushMemory(mixedAudio); ClearAudioFrameList(mixList); ClearAudioFrameList(rampOutList); + ClearAudioFrameList(additionalFramesList); { CriticalSectionScoped cs(*_crit); _processCalls--; @@ -530,6 +535,60 @@ WebRtc_Word32 AudioConferenceMixerImpl::AmountOfMixables( return 0; } +WebRtc_Word32 AudioConferenceMixerImpl::SetAnonymousMixabilityStatus( + MixerParticipant& participant, const bool anonymous) +{ + WEBRTC_TRACE(kTraceModuleCall, kTraceAudioMixerServer, _id, + "SetAnonymousMixabilityStatus(participant,anonymous:%s)", + anonymous ? "true" : "false"); + CriticalSectionScoped cs(*_cbCrit); + if(IsParticipantInList(participant, _additionalParticipantList)) + { + if(anonymous) + { + return 0; + } + if(!RemoveParticipantFromList(participant, _additionalParticipantList)) + { + WEBRTC_TRACE(kTraceError, kTraceAudioMixerServer, _id, + "unable to remove participant from anonymous list"); + assert(false); + return -1; + } + return AddParticipantToList(participant, _participantList) ? 0 : -1; + } + if(!anonymous) + { + return 0; + } + const bool mixable = RemoveParticipantFromList(participant, + _participantList); + if(!mixable) + { + WEBRTC_TRACE( + kTraceWarning, + kTraceAudioMixerServer, + _id, + "participant must be registered before turning it into anonymous"); + // Setting anonymous status is only possible if MixerParticipant is + // already registered. + return -1; + } + return AddParticipantToList(participant, _additionalParticipantList) ? + 0 : -1; +} + +WebRtc_Word32 AudioConferenceMixerImpl::AnonymousMixabilityStatus( + MixerParticipant& participant, bool& mixable) +{ + WEBRTC_TRACE(kTraceModuleCall, kTraceAudioMixerServer, _id, + "AnonymousMixabilityStatus(participant,mixable)"); + CriticalSectionScoped cs(*_cbCrit); + mixable = IsParticipantInList(participant, + _additionalParticipantList); + return 0; +} + WebRtc_Word32 AudioConferenceMixerImpl::SetMinimumMixingFrequency( Frequency freq) { @@ -593,7 +652,7 @@ void AudioConferenceMixerImpl::UpdateToMix( WebRtc_UWord32& maxAudioFrameCounter) { WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id, - "GetVIPAudio(mixList,rampOutList,mixParticipantList,%d)", + "UpdateToMix(mixList,rampOutList,mixParticipantList,%d)", maxAudioFrameCounter); const WebRtc_UWord32 mixListStartSize = mixList.GetSize(); ListWrapper activeList; // Elements are AudioFrames @@ -800,6 +859,49 @@ void AudioConferenceMixerImpl::UpdateToMix( maxAudioFrameCounter += mixListStartSize - mixList.GetSize(); } +void AudioConferenceMixerImpl::GetAdditionalAudio( + ListWrapper& additionalFramesList) +{ + WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id, + "GetAdditionalAudio(additionalFramesList)"); + ListItem* item = _additionalParticipantList.First(); + while(item) + { + // The GetAudioFrame() callback may remove the current item. Store the + // next item just in case that happens. + ListItem* nextItem = _additionalParticipantList.Next(item); + + MixerParticipant* participant = static_cast( + item->GetItem()); + AudioFrame* audioFrame = NULL; + if(_audioFramePool->PopMemory(audioFrame) == -1) + { + WEBRTC_TRACE(kTraceMemory, kTraceAudioMixerServer, _id, + "failed PopMemory() call"); + assert(false); + return; + } + audioFrame->_frequencyInHz = _outputFrequency; + if(participant->GetAudioFrame(_id, *audioFrame) != 0) + { + WEBRTC_TRACE(kTraceWarning, kTraceAudioMixerServer, _id, + "failed to GetAudioFrame() from participant"); + _audioFramePool->PushMemory(audioFrame); + item = nextItem; + continue; + } + if(audioFrame->_payloadDataLengthInSamples == 0) + { + // Empty frame. Don't use it. + _audioFramePool->PushMemory(audioFrame); + item = nextItem; + continue; + } + additionalFramesList.PushBack(static_cast(audioFrame)); + item = nextItem; + } +} + void AudioConferenceMixerImpl::UpdateMixedStatus( MapWrapper& mixedParticipantsMap) { @@ -807,7 +909,7 @@ void AudioConferenceMixerImpl::UpdateMixedStatus( "UpdateMixedStatus(mixedParticipantsMap)"); assert(mixedParticipantsMap.Size() <= kMaximumAmountOfMixedParticipants); - // Loop through all non-VIP participants. If they are in the mix map they + // Loop through all participants. If they are in the mix map they // were mixed. ListItem* participantItem = _participantList.First(); while(participantItem != NULL) diff --git a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h index 9e5c7b3da..6c961b93e 100644 --- a/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h +++ b/src/modules/audio_conference_mixer/source/audio_conference_mixer_impl.h @@ -78,6 +78,10 @@ public: virtual WebRtc_Word32 SetMinimumMixingFrequency(Frequency freq); virtual WebRtc_Word32 AmountOfMixables( WebRtc_UWord32& amountOfMixableParticipants); + virtual WebRtc_Word32 SetAnonymousMixabilityStatus( + MixerParticipant& participant, const bool mixable); + virtual WebRtc_Word32 AnonymousMixabilityStatus( + MixerParticipant& participant, bool& mixable); private: enum{DEFAULT_AUDIO_FRAME_POOLSIZE = 50}; @@ -101,6 +105,9 @@ private: // downsample any audio. WebRtc_Word32 GetLowestMixingFrequency(); + // Return the AudioFrames that should be mixed anonymously. + void GetAdditionalAudio(ListWrapper& additionalFramesList); + // Update the MixHistory of all MixerParticipants. mixedParticipantsList // should contain a map of MixerParticipants that have been mixed. void UpdateMixedStatus(MapWrapper& mixedParticipantsList); @@ -172,6 +179,7 @@ private: // List of all participants. Note all lists are disjunct ListWrapper _participantList; // May be mixed. + ListWrapper _additionalParticipantList; // Always mixed, anonomously. WebRtc_UWord32 _amountOfMixableParticipants; diff --git a/src/voice_engine/main/source/channel.cc b/src/voice_engine/main/source/channel.cc index b0002735f..155fa57c6 100644 --- a/src/voice_engine/main/source/channel.cc +++ b/src/voice_engine/main/source/channel.cc @@ -3501,6 +3501,16 @@ int Channel::StartPlayingFileLocally(const char* fileName, _outputFilePlayerPtr = NULL; return -1; } + if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0) + { + _engineStatisticsPtr->SetLastError( + VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError, + "StartPlayingFile() failed to add participant as file to mixer"); + _outputFilePlayerPtr->StopPlayingFile(); + FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr); + _outputFilePlayerPtr = NULL; + return -1; + } _outputFilePlayerPtr->RegisterModuleFileCallback(this); _outputFilePlaying = true; @@ -3573,6 +3583,16 @@ int Channel::StartPlayingFileLocally(InStream* stream, _outputFilePlayerPtr = NULL; return -1; } + if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0) + { + _engineStatisticsPtr->SetLastError( + VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError, + "StartPlayingFile() failed to add participant as file to mixer"); + _outputFilePlayerPtr->StopPlayingFile(); + FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr); + _outputFilePlayerPtr = NULL; + return -1; + } _outputFilePlayerPtr->RegisterModuleFileCallback(this); _outputFilePlaying = true; @@ -3602,6 +3622,14 @@ int Channel::StopPlayingFileLocally() "StopPlayingFile() could not stop playing"); return -1; } + if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0) + { + _engineStatisticsPtr->SetLastError( + VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError, + "StopPlayingFile() failed to stop participant from playing as file" + "in the mixer"); + return -1; + } _outputFilePlayerPtr->RegisterModuleFileCallback(NULL); FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr); _outputFilePlayerPtr = NULL; diff --git a/src/voice_engine/main/source/output_mixer.cc b/src/voice_engine/main/source/output_mixer.cc index f3ec5327e..0ea86b4c4 100644 --- a/src/voice_engine/main/source/output_mixer.cc +++ b/src/voice_engine/main/source/output_mixer.cc @@ -272,6 +272,13 @@ OutputMixer::SetMixabilityStatus(MixerParticipant& participant, return _mixerModule.SetMixabilityStatus(participant, mixable); } +WebRtc_Word32 +OutputMixer::SetAnonymousMixabilityStatus(MixerParticipant& participant, + const bool mixable) +{ + return _mixerModule.SetAnonymousMixabilityStatus(participant,mixable); +} + WebRtc_Word32 OutputMixer::MixActiveChannels() { diff --git a/src/voice_engine/main/source/output_mixer.h b/src/voice_engine/main/source/output_mixer.h index 7fc1c4e32..a5df18501 100644 --- a/src/voice_engine/main/source/output_mixer.h +++ b/src/voice_engine/main/source/output_mixer.h @@ -69,6 +69,9 @@ public: WebRtc_Word32 SetMixabilityStatus(MixerParticipant& participant, const bool mixable); + WebRtc_Word32 SetAnonymousMixabilityStatus(MixerParticipant& participant, + const bool mixable); + WebRtc_Word32 GetMixedAudio(const WebRtc_Word32 desiredFreqHz, const WebRtc_UWord8 channels, AudioFrame& audioFrame);