mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 989921 - Allow the MediaStreamGraph mixer to send data back to multiple consumers. r=jesup
This commit is contained in:
parent
601228fc42
commit
6b08a02243
@ -9,13 +9,17 @@
|
||||
#include "AudioSampleFormat.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
|
||||
namespace mozilla {
|
||||
typedef void(*MixerFunc)(AudioDataValue* aMixedBuffer,
|
||||
|
||||
struct MixerCallbackReceiver {
|
||||
virtual void MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate);
|
||||
uint32_t aSampleRate) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class mixes multiple streams of audio together to output a single audio
|
||||
@ -32,21 +36,29 @@ typedef void(*MixerFunc)(AudioDataValue* aMixedBuffer,
|
||||
class AudioMixer
|
||||
{
|
||||
public:
|
||||
AudioMixer(MixerFunc aCallback)
|
||||
: mCallback(aCallback),
|
||||
mFrames(0),
|
||||
AudioMixer()
|
||||
: mFrames(0),
|
||||
mChannels(0),
|
||||
mSampleRate(0)
|
||||
{ }
|
||||
|
||||
~AudioMixer()
|
||||
{
|
||||
mCallbacks.clear();
|
||||
}
|
||||
|
||||
/* Get the data from the mixer. This is supposed to be called when all the
|
||||
* tracks have been mixed in. The caller should not hold onto the data. */
|
||||
void FinishMixing() {
|
||||
mCallback(mMixedAudio.Elements(),
|
||||
MOZ_ASSERT(mChannels && mFrames && mSampleRate, "Mix not called for this cycle?");
|
||||
for (MixerCallback* cb = mCallbacks.getFirst();
|
||||
cb != nullptr; cb = cb->getNext()) {
|
||||
cb->mReceiver->MixerCallback(mMixedAudio.Elements(),
|
||||
AudioSampleTypeToFormat<AudioDataValue>::Format,
|
||||
mChannels,
|
||||
mFrames,
|
||||
mSampleRate);
|
||||
}
|
||||
PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
|
||||
mSampleRate = mChannels = mFrames = 0;
|
||||
}
|
||||
@ -71,6 +83,21 @@ public:
|
||||
mMixedAudio[i] += aSamples[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AddCallback(MixerCallbackReceiver* aReceiver) {
|
||||
mCallbacks.insertBack(new MixerCallback(aReceiver));
|
||||
}
|
||||
|
||||
bool RemoveCallback(MixerCallbackReceiver* aReceiver) {
|
||||
for (MixerCallback* cb = mCallbacks.getFirst();
|
||||
cb != nullptr; cb = cb->getNext()) {
|
||||
if (cb->mReceiver == aReceiver) {
|
||||
cb->remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void EnsureCapacityAndSilence() {
|
||||
if (mFrames * mChannels > mMixedAudio.Length()) {
|
||||
@ -79,8 +106,17 @@ private:
|
||||
PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
|
||||
}
|
||||
|
||||
class MixerCallback : public LinkedListElement<MixerCallback>
|
||||
{
|
||||
public:
|
||||
MixerCallback(MixerCallbackReceiver* aReceiver)
|
||||
: mReceiver(aReceiver)
|
||||
{ }
|
||||
MixerCallbackReceiver* mReceiver;
|
||||
};
|
||||
|
||||
/* Function that is called when the mixing is done. */
|
||||
MixerFunc mCallback;
|
||||
LinkedList<MixerCallback> mCallbacks;
|
||||
/* Number of frames for this mixing block. */
|
||||
uint32_t mFrames;
|
||||
/* Number of channels for this mixing block. */
|
||||
|
@ -586,24 +586,6 @@ MediaStreamGraphImpl::UpdateStreamOrderForStream(mozilla::LinkedList<MediaStream
|
||||
*mStreams.AppendElement() = stream.forget();
|
||||
}
|
||||
|
||||
static void AudioMixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate)
|
||||
{
|
||||
// Need an api to register mixer callbacks, bug 989921
|
||||
#ifdef MOZ_WEBRTC
|
||||
if (aFrames > 0 && aChannels > 0) {
|
||||
// XXX need Observer base class and registration API
|
||||
if (gFarendObserver) {
|
||||
gFarendObserver->InsertFarEnd(aMixedBuffer, aFrames, false,
|
||||
aSampleRate, aChannels, aFormat);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::UpdateStreamOrder()
|
||||
{
|
||||
@ -631,8 +613,12 @@ MediaStreamGraphImpl::UpdateStreamOrder()
|
||||
}
|
||||
|
||||
if (!mMixer && shouldMix) {
|
||||
mMixer = new AudioMixer(AudioMixerCallback);
|
||||
mMixer = new AudioMixer();
|
||||
if (gFarendObserver) {
|
||||
mMixer->AddCallback(gFarendObserver);
|
||||
}
|
||||
} else if (mMixer && !shouldMix) {
|
||||
mMixer->RemoveCallback(gFarendObserver);
|
||||
mMixer = nullptr;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "MainThreadUtils.h"
|
||||
#include "nsAutoRef.h"
|
||||
#include "speex/speex_resampler.h"
|
||||
#include "AudioMixer.h"
|
||||
#include "mozilla/dom/AudioChannelBinding.h"
|
||||
|
||||
class nsIRunnable;
|
||||
|
@ -9,10 +9,12 @@
|
||||
using mozilla::AudioDataValue;
|
||||
using mozilla::AudioSampleFormat;
|
||||
|
||||
struct MixerConsumer : public mozilla::MixerCallbackReceiver
|
||||
{
|
||||
/* In this test, the different audio stream and channels are always created to
|
||||
* cancel each other. */
|
||||
void MixingDone(AudioDataValue* aData, AudioSampleFormat aFormat, uint32_t aChannels, uint32_t aFrames, uint32_t aSampleRate)
|
||||
{
|
||||
void MixerCallback(AudioDataValue* aData, AudioSampleFormat aFormat, uint32_t aChannels, uint32_t aFrames, uint32_t aSampleRate)
|
||||
{
|
||||
bool silent = true;
|
||||
for (uint32_t i = 0; i < aChannels * aFrames; i++) {
|
||||
if (aData[i] != 0.0) {
|
||||
@ -27,7 +29,8 @@ void MixingDone(AudioDataValue* aData, AudioSampleFormat aFormat, uint32_t aChan
|
||||
if (!silent) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Helper function to give us the maximum and minimum value that don't clip,
|
||||
* for a given sample format (integer or floating-point). */
|
||||
@ -68,6 +71,7 @@ void FillBuffer(AudioDataValue* aBuffer, uint32_t aLength, AudioDataValue aValue
|
||||
int main(int argc, char* argv[]) {
|
||||
const uint32_t CHANNEL_LENGTH = 256;
|
||||
const uint32_t AUDIO_RATE = 44100;
|
||||
MixerConsumer consumer;
|
||||
AudioDataValue a[CHANNEL_LENGTH * 2];
|
||||
AudioDataValue b[CHANNEL_LENGTH * 2];
|
||||
FillBuffer(a, CHANNEL_LENGTH, GetLowValue<AudioDataValue>());
|
||||
@ -77,7 +81,8 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
{
|
||||
int iterations = 2;
|
||||
mozilla::AudioMixer mixer(MixingDone);
|
||||
mozilla::AudioMixer mixer;
|
||||
mixer.AddCallback(&consumer);
|
||||
|
||||
fprintf(stderr, "Test AudioMixer constant buffer length.\n");
|
||||
|
||||
@ -89,7 +94,8 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
{
|
||||
mozilla::AudioMixer mixer(MixingDone);
|
||||
mozilla::AudioMixer mixer;
|
||||
mixer.AddCallback(&consumer);
|
||||
|
||||
fprintf(stderr, "Test AudioMixer variable buffer length.\n");
|
||||
|
||||
@ -120,7 +126,9 @@ int main(int argc, char* argv[]) {
|
||||
FillBuffer(b, CHANNEL_LENGTH, GetHighValue<AudioDataValue>());
|
||||
|
||||
{
|
||||
mozilla::AudioMixer mixer(MixingDone);
|
||||
mozilla::AudioMixer mixer;
|
||||
mixer.AddCallback(&consumer);
|
||||
|
||||
fprintf(stderr, "Test AudioMixer variable channel count.\n");
|
||||
|
||||
mixer.Mix(a, 1, CHANNEL_LENGTH, AUDIO_RATE);
|
||||
@ -135,7 +143,8 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
{
|
||||
mozilla::AudioMixer mixer(MixingDone);
|
||||
mozilla::AudioMixer mixer;
|
||||
mixer.AddCallback(&consumer);
|
||||
fprintf(stderr, "Test AudioMixer variable stream count.\n");
|
||||
|
||||
mixer.Mix(a, 2, CHANNEL_LENGTH, AUDIO_RATE);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define AUDIOOUTPUTOBSERVER_H_
|
||||
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "AudioMixer.h"
|
||||
|
||||
namespace webrtc {
|
||||
class SingleRwFifo;
|
||||
@ -20,12 +21,18 @@ typedef struct FarEndAudioChunk_ {
|
||||
} FarEndAudioChunk;
|
||||
|
||||
// XXX Really a singleton currently
|
||||
class AudioOutputObserver // : public MSGOutputObserver
|
||||
class AudioOutputObserver : public MixerCallbackReceiver
|
||||
{
|
||||
public:
|
||||
AudioOutputObserver();
|
||||
virtual ~AudioOutputObserver();
|
||||
|
||||
void MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate) MOZ_OVERRIDE;
|
||||
|
||||
void Clear();
|
||||
void InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aSamples, bool aOverran,
|
||||
int aFreq, int aChannels, AudioSampleFormat aFormat);
|
||||
|
@ -86,6 +86,17 @@ AudioOutputObserver::Size()
|
||||
return mPlayoutFifo->size();
|
||||
}
|
||||
|
||||
void
|
||||
AudioOutputObserver::MixerCallback(AudioDataValue* aMixedBuffer,
|
||||
AudioSampleFormat aFormat,
|
||||
uint32_t aChannels,
|
||||
uint32_t aFrames,
|
||||
uint32_t aSampleRate)
|
||||
{
|
||||
gFarendObserver->InsertFarEnd(aMixedBuffer, aFrames, false,
|
||||
aSampleRate, aChannels, aFormat);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
AudioOutputObserver::InsertFarEnd(const AudioDataValue *aBuffer, uint32_t aSamples, bool aOverran,
|
||||
|
Loading…
Reference in New Issue
Block a user