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

View File

@ -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.

View File

@ -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<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(
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)

View File

@ -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;

View File

@ -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;

View File

@ -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()
{

View File

@ -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);