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:
parent
731ecba47d
commit
066f9e5a2f
src
modules/audio_conference_mixer
voice_engine/main/source
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user