mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
Bug 1890873 - Prime a voice processing stream on macOS before showing gUM prompt. r=padenot
If priming is done when the gUM prompt is accepted by the user, creating the voice processing stream is almost instantaneous since the primed stream can be reused. Differential Revision: https://phabricator.services.mozilla.com/D207213
This commit is contained in:
parent
a35c77dd10
commit
89f4b44d7d
@ -15,8 +15,10 @@
|
||||
#include "MediaTrackGraph.h"
|
||||
#include "MediaTrackListener.h"
|
||||
#include "VideoStreamTrack.h"
|
||||
#include "Tracing.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/EventTargetCapability.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/PeerIdentity.h"
|
||||
@ -1458,9 +1460,63 @@ class GetUserMediaStreamTask final : public GetUserMediaTask {
|
||||
|
||||
const MediaStreamConstraints& GetConstraints() { return mConstraints; }
|
||||
|
||||
void PrimeVoiceProcessing() {
|
||||
mPrimingStream = MakeAndAddRef<PrimingCubebVoiceInputStream>();
|
||||
mPrimingStream->Init();
|
||||
}
|
||||
|
||||
private:
|
||||
void PrepareDOMStream();
|
||||
|
||||
class PrimingCubebVoiceInputStream {
|
||||
class Listener final : public CubebInputStream::Listener {
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Listener, override);
|
||||
|
||||
private:
|
||||
~Listener() = default;
|
||||
|
||||
long DataCallback(const void*, long) override {
|
||||
MOZ_CRASH("Unexpected data callback");
|
||||
}
|
||||
void StateCallback(cubeb_state) override {}
|
||||
void DeviceChangedCallback() override {}
|
||||
};
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_EVENT_TARGET(
|
||||
PrimingCubebVoiceInputStream, mCubebThread.GetEventTarget())
|
||||
|
||||
public:
|
||||
void Init() {
|
||||
mCubebThread.GetEventTarget()->Dispatch(
|
||||
NS_NewRunnableFunction(__func__, [this, self = RefPtr(this)] {
|
||||
mCubebThread.AssertOnCurrentThread();
|
||||
LOG("Priming voice processing with stream %p", this);
|
||||
TRACE("PrimingCubebVoiceInputStream::Init");
|
||||
const cubeb_devid default_device = nullptr;
|
||||
const uint32_t mono = 1;
|
||||
const uint32_t rate = CubebUtils::PreferredSampleRate(false);
|
||||
const bool isVoice = true;
|
||||
mCubebStream =
|
||||
CubebInputStream::Create(default_device, mono, rate, isVoice,
|
||||
MakeRefPtr<Listener>().get());
|
||||
}));
|
||||
}
|
||||
|
||||
private:
|
||||
~PrimingCubebVoiceInputStream() {
|
||||
mCubebThread.AssertOnCurrentThread();
|
||||
LOG("Releasing primed voice processing stream %p", this);
|
||||
mCubebStream = nullptr;
|
||||
}
|
||||
|
||||
const EventTargetCapability<nsISerialEventTarget> mCubebThread =
|
||||
EventTargetCapability<nsISerialEventTarget>(
|
||||
TaskQueue::Create(CubebUtils::GetCubebOperationThread(),
|
||||
"PrimingCubebInputStream::mCubebThread")
|
||||
.get());
|
||||
UniquePtr<CubebInputStream> mCubebStream MOZ_GUARDED_BY(mCubebThread);
|
||||
};
|
||||
|
||||
// Constraints derived from those passed to getUserMedia() but adjusted for
|
||||
// preferences, defaults, and security
|
||||
const MediaStreamConstraints mConstraints;
|
||||
@ -1473,6 +1529,7 @@ class GetUserMediaStreamTask final : public GetUserMediaTask {
|
||||
// MediaDevices are set when selected and Allowed() by the UI.
|
||||
RefPtr<LocalMediaDevice> mAudioDevice;
|
||||
RefPtr<LocalMediaDevice> mVideoDevice;
|
||||
RefPtr<PrimingCubebVoiceInputStream> mPrimingStream;
|
||||
// Tracking id unique for a video frame source. Set when the corresponding
|
||||
// device has been allocated.
|
||||
Maybe<TrackingId> mVideoTrackingId;
|
||||
@ -3044,6 +3101,27 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
|
||||
std::move(audioListener), std::move(videoListener), prefs,
|
||||
principalInfo, aCallerType, focusSource);
|
||||
|
||||
// It is time to ask for user permission, prime voice processing
|
||||
// now. Use a local lambda to enable a guard pattern.
|
||||
[&] {
|
||||
if (!StaticPrefs::
|
||||
media_getusermedia_microphone_voice_stream_priming_enabled() ||
|
||||
!StaticPrefs::
|
||||
media_getusermedia_microphone_prefer_voice_stream_with_processing_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto fc = FlattenedConstraints(
|
||||
NormalizedConstraints(GetInvariant(c.mAudio)));
|
||||
!fc.mEchoCancellation.Get(prefs.mAecOn) &&
|
||||
!fc.mAutoGainControl.Get(prefs.mAgcOn && prefs.mAecOn) &&
|
||||
!fc.mNoiseSuppression.Get(prefs.mNoiseOn && prefs.mAecOn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
task->PrimeVoiceProcessing();
|
||||
}();
|
||||
|
||||
size_t taskCount =
|
||||
self->AddTaskAndGetCount(windowID, callID, std::move(task));
|
||||
|
||||
|
@ -10884,6 +10884,14 @@
|
||||
value: True
|
||||
mirror: always
|
||||
|
||||
# Tell the audio backend to create a voice stream for later re-use before asking
|
||||
# the user for microphone permissions, if approving those permissions would
|
||||
# result in a voice stream when created later on.
|
||||
- name: media.getusermedia.microphone.voice_stream_priming.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: @IS_XP_MACOSX@
|
||||
mirror: always
|
||||
|
||||
# This pref turns on legacy (non-spec) exposure of camera and microphone
|
||||
# information from enumerateDevices and devicechange ahead of successful
|
||||
# getUserMedia calls. Should only be turned on to resolve web compat issues,
|
||||
|
Loading…
Reference in New Issue
Block a user