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
This commit is contained in:
henrike@webrtc.org 2011-10-28 23:15:47 +00:00
parent 731ecba47d
commit 066f9e5a2f
6 changed files with 160 additions and 2 deletions

@ -73,6 +73,16 @@ public:
virtual WebRtc_Word32 AmountOfMixables( virtual WebRtc_Word32 AmountOfMixables(
WebRtc_UWord32& amountOfMixableParticipants) = 0; 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 // Set the minimum sampling frequency at which to mix. The mixing algorithm
// may still choose to mix at a higher samling frequency to avoid // may still choose to mix at a higher samling frequency to avoid
// downsampling of audio contributing to the mixed audio. // downsampling of audio contributing to the mixed audio.

@ -89,6 +89,7 @@ AudioConferenceMixerImpl::AudioConferenceMixerImpl(const WebRtc_Word32 id)
_outputFrequency(kDefaultFrequency), _outputFrequency(kDefaultFrequency),
_sampleSize((_outputFrequency*kProcessPeriodicityInMs)/1000), _sampleSize((_outputFrequency*kProcessPeriodicityInMs)/1000),
_participantList(), _participantList(),
_additionalParticipantList(),
_amountOfMixableParticipants(0), _amountOfMixableParticipants(0),
_timeStamp(0), _timeStamp(0),
_timeScheduler(kProcessPeriodicityInMs), _timeScheduler(kProcessPeriodicityInMs),
@ -200,6 +201,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process()
ListWrapper mixList; ListWrapper mixList;
ListWrapper rampOutList; ListWrapper rampOutList;
ListWrapper additionalFramesList;
MapWrapper mixedParticipantsMap; MapWrapper mixedParticipantsMap;
{ {
CriticalSectionScoped cs(*_cbCrit); CriticalSectionScoped cs(*_cbCrit);
@ -253,6 +255,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process()
UpdateToMix(mixList, rampOutList, mixedParticipantsMap, UpdateToMix(mixList, rampOutList, mixedParticipantsMap,
remainingParticipantsAllowedToMix); remainingParticipantsAllowedToMix);
GetAdditionalAudio(additionalFramesList);
UpdateMixedStatus(mixedParticipantsMap); UpdateMixedStatus(mixedParticipantsMap);
_scratchParticipantsToMixAmount = mixedParticipantsMap.Size(); _scratchParticipantsToMixAmount = mixedParticipantsMap.Size();
} }
@ -297,6 +300,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process()
_timeStamp += _sampleSize; _timeStamp += _sampleSize;
MixFromList(*mixedAudio,mixList); MixFromList(*mixedAudio,mixList);
MixAnonomouslyFromList(*mixedAudio, additionalFramesList);
MixAnonomouslyFromList(*mixedAudio, rampOutList); MixAnonomouslyFromList(*mixedAudio, rampOutList);
if(mixedAudio->_payloadDataLengthInSamples == 0) if(mixedAudio->_payloadDataLengthInSamples == 0)
@ -353,6 +357,7 @@ WebRtc_Word32 AudioConferenceMixerImpl::Process()
_audioFramePool->PushMemory(mixedAudio); _audioFramePool->PushMemory(mixedAudio);
ClearAudioFrameList(mixList); ClearAudioFrameList(mixList);
ClearAudioFrameList(rampOutList); ClearAudioFrameList(rampOutList);
ClearAudioFrameList(additionalFramesList);
{ {
CriticalSectionScoped cs(*_crit); CriticalSectionScoped cs(*_crit);
_processCalls--; _processCalls--;
@ -530,6 +535,60 @@ WebRtc_Word32 AudioConferenceMixerImpl::AmountOfMixables(
return 0; 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( WebRtc_Word32 AudioConferenceMixerImpl::SetMinimumMixingFrequency(
Frequency freq) Frequency freq)
{ {
@ -593,7 +652,7 @@ void AudioConferenceMixerImpl::UpdateToMix(
WebRtc_UWord32& maxAudioFrameCounter) WebRtc_UWord32& maxAudioFrameCounter)
{ {
WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id, WEBRTC_TRACE(kTraceStream, kTraceAudioMixerServer, _id,
"GetVIPAudio(mixList,rampOutList,mixParticipantList,%d)", "UpdateToMix(mixList,rampOutList,mixParticipantList,%d)",
maxAudioFrameCounter); maxAudioFrameCounter);
const WebRtc_UWord32 mixListStartSize = mixList.GetSize(); const WebRtc_UWord32 mixListStartSize = mixList.GetSize();
ListWrapper activeList; // Elements are AudioFrames ListWrapper activeList; // Elements are AudioFrames
@ -800,6 +859,49 @@ void AudioConferenceMixerImpl::UpdateToMix(
maxAudioFrameCounter += mixListStartSize - mixList.GetSize(); 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<MixerParticipant*>(
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<void*>(audioFrame));
item = nextItem;
}
}
void AudioConferenceMixerImpl::UpdateMixedStatus( void AudioConferenceMixerImpl::UpdateMixedStatus(
MapWrapper& mixedParticipantsMap) MapWrapper& mixedParticipantsMap)
{ {
@ -807,7 +909,7 @@ void AudioConferenceMixerImpl::UpdateMixedStatus(
"UpdateMixedStatus(mixedParticipantsMap)"); "UpdateMixedStatus(mixedParticipantsMap)");
assert(mixedParticipantsMap.Size() <= kMaximumAmountOfMixedParticipants); 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. // were mixed.
ListItem* participantItem = _participantList.First(); ListItem* participantItem = _participantList.First();
while(participantItem != NULL) while(participantItem != NULL)

@ -78,6 +78,10 @@ public:
virtual WebRtc_Word32 SetMinimumMixingFrequency(Frequency freq); virtual WebRtc_Word32 SetMinimumMixingFrequency(Frequency freq);
virtual WebRtc_Word32 AmountOfMixables( virtual WebRtc_Word32 AmountOfMixables(
WebRtc_UWord32& amountOfMixableParticipants); WebRtc_UWord32& amountOfMixableParticipants);
virtual WebRtc_Word32 SetAnonymousMixabilityStatus(
MixerParticipant& participant, const bool mixable);
virtual WebRtc_Word32 AnonymousMixabilityStatus(
MixerParticipant& participant, bool& mixable);
private: private:
enum{DEFAULT_AUDIO_FRAME_POOLSIZE = 50}; enum{DEFAULT_AUDIO_FRAME_POOLSIZE = 50};
@ -101,6 +105,9 @@ private:
// downsample any audio. // downsample any audio.
WebRtc_Word32 GetLowestMixingFrequency(); WebRtc_Word32 GetLowestMixingFrequency();
// Return the AudioFrames that should be mixed anonymously.
void GetAdditionalAudio(ListWrapper& additionalFramesList);
// Update the MixHistory of all MixerParticipants. mixedParticipantsList // Update the MixHistory of all MixerParticipants. mixedParticipantsList
// should contain a map of MixerParticipants that have been mixed. // should contain a map of MixerParticipants that have been mixed.
void UpdateMixedStatus(MapWrapper& mixedParticipantsList); void UpdateMixedStatus(MapWrapper& mixedParticipantsList);
@ -172,6 +179,7 @@ private:
// List of all participants. Note all lists are disjunct // List of all participants. Note all lists are disjunct
ListWrapper _participantList; // May be mixed. ListWrapper _participantList; // May be mixed.
ListWrapper _additionalParticipantList; // Always mixed, anonomously.
WebRtc_UWord32 _amountOfMixableParticipants; WebRtc_UWord32 _amountOfMixableParticipants;

@ -3501,6 +3501,16 @@ int Channel::StartPlayingFileLocally(const char* fileName,
_outputFilePlayerPtr = NULL; _outputFilePlayerPtr = NULL;
return -1; 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); _outputFilePlayerPtr->RegisterModuleFileCallback(this);
_outputFilePlaying = true; _outputFilePlaying = true;
@ -3573,6 +3583,16 @@ int Channel::StartPlayingFileLocally(InStream* stream,
_outputFilePlayerPtr = NULL; _outputFilePlayerPtr = NULL;
return -1; 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); _outputFilePlayerPtr->RegisterModuleFileCallback(this);
_outputFilePlaying = true; _outputFilePlaying = true;
@ -3602,6 +3622,14 @@ int Channel::StopPlayingFileLocally()
"StopPlayingFile() could not stop playing"); "StopPlayingFile() could not stop playing");
return -1; 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); _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr); FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
_outputFilePlayerPtr = NULL; _outputFilePlayerPtr = NULL;

@ -272,6 +272,13 @@ OutputMixer::SetMixabilityStatus(MixerParticipant& participant,
return _mixerModule.SetMixabilityStatus(participant, mixable); return _mixerModule.SetMixabilityStatus(participant, mixable);
} }
WebRtc_Word32
OutputMixer::SetAnonymousMixabilityStatus(MixerParticipant& participant,
const bool mixable)
{
return _mixerModule.SetAnonymousMixabilityStatus(participant,mixable);
}
WebRtc_Word32 WebRtc_Word32
OutputMixer::MixActiveChannels() OutputMixer::MixActiveChannels()
{ {

@ -69,6 +69,9 @@ public:
WebRtc_Word32 SetMixabilityStatus(MixerParticipant& participant, WebRtc_Word32 SetMixabilityStatus(MixerParticipant& participant,
const bool mixable); const bool mixable);
WebRtc_Word32 SetAnonymousMixabilityStatus(MixerParticipant& participant,
const bool mixable);
WebRtc_Word32 GetMixedAudio(const WebRtc_Word32 desiredFreqHz, WebRtc_Word32 GetMixedAudio(const WebRtc_Word32 desiredFreqHz,
const WebRtc_UWord8 channels, const WebRtc_UWord8 channels,
AudioFrame& audioFrame); AudioFrame& audioFrame);