mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1213414 - Implement channelCount audio constraint. r=jib,padenot
MozReview-Commit-ID: K95iBYOE1nR --HG-- extra : rebase_source : 5c73eea4902933faec75e37d90e42a2f38c51b81
This commit is contained in:
parent
d39881db34
commit
41737dc1af
@ -675,10 +675,9 @@ AudioCallbackDriver::Init()
|
||||
#ifdef MOZ_WEBRTC
|
||||
if (mGraphImpl->mInputWanted) {
|
||||
StaticMutexAutoLock lock(AudioInputCubeb::Mutex());
|
||||
uint32_t maxInputChannels = 0;
|
||||
if (AudioInputCubeb::GetDeviceMaxChannels(mGraphImpl->mInputDeviceID, maxInputChannels) == 0) {
|
||||
input.channels = mInputChannels = maxInputChannels;
|
||||
}
|
||||
uint32_t userChannels = 0;
|
||||
AudioInputCubeb::GetUserChannelCount(mGraphImpl->mInputDeviceID, userChannels);
|
||||
input.channels = mInputChannels = userChannels;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1815,6 +1815,7 @@ MediaManager::MediaManager()
|
||||
#endif
|
||||
mPrefs.mPlayoutDelay = 0;
|
||||
mPrefs.mFullDuplex = false;
|
||||
mPrefs.mChannels = 0; // max channels default
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -1825,12 +1826,14 @@ MediaManager::MediaManager()
|
||||
}
|
||||
LOG(("%s: default prefs: %dx%d @%dfps (min %d), %dHz test tones, aec: %s,"
|
||||
"agc: %s, noise: %s, aec level: %d, agc level: %d, noise level: %d,"
|
||||
"playout delay: %d, %sfull_duplex, extended aec %s, delay_agnostic %s",
|
||||
"playout delay: %d, %sfull_duplex, extended aec %s, delay_agnostic %s "
|
||||
"channels %d",
|
||||
__FUNCTION__, mPrefs.mWidth, mPrefs.mHeight,
|
||||
mPrefs.mFPS, mPrefs.mMinFPS, mPrefs.mFreq, mPrefs.mAecOn ? "on" : "off",
|
||||
mPrefs.mAgcOn ? "on": "off", mPrefs.mNoiseOn ? "on": "off", mPrefs.mAec,
|
||||
mPrefs.mAgc, mPrefs.mNoise, mPrefs.mPlayoutDelay, mPrefs.mFullDuplex ? "" : "not ",
|
||||
mPrefs.mExtendedFilter ? "on" : "off", mPrefs.mDelayAgnostic ? "on" : "off"));
|
||||
mPrefs.mExtendedFilter ? "on" : "off", mPrefs.mDelayAgnostic ? "on" : "off",
|
||||
mPrefs.mChannels));
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaManager, nsIMediaManagerService, nsIObserver)
|
||||
@ -1904,6 +1907,7 @@ MediaManager::Get() {
|
||||
prefs->AddObserver("media.getusermedia.noise", sSingleton, false);
|
||||
prefs->AddObserver("media.getusermedia.playout_delay", sSingleton, false);
|
||||
prefs->AddObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", sSingleton, false);
|
||||
prefs->AddObserver("media.getusermedia.channels", sSingleton, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2937,6 +2941,7 @@ MediaManager::GetPrefs(nsIPrefBranch *aBranch, const char *aData)
|
||||
GetPref(aBranch, "media.getusermedia.playout_delay", aData, &mPrefs.mPlayoutDelay);
|
||||
GetPrefBool(aBranch, "media.getusermedia.aec_extended_filter", aData, &mPrefs.mExtendedFilter);
|
||||
GetPrefBool(aBranch, "media.getusermedia.aec_aec_delay_agnostic", aData, &mPrefs.mDelayAgnostic);
|
||||
GetPref(aBranch, "media.getusermedia.channels", aData, &mPrefs.mChannels);
|
||||
GetPrefBool(aBranch, "media.ondevicechange.fakeDeviceChangeEvent.enabled", aData, &mPrefs.mFakeDeviceChangeEventOn);
|
||||
#endif
|
||||
GetPrefBool(aBranch, "media.navigator.audio.full_duplex", aData, &mPrefs.mFullDuplex);
|
||||
@ -2975,6 +2980,7 @@ MediaManager::Shutdown()
|
||||
prefs->RemoveObserver("media.getusermedia.noise", this);
|
||||
prefs->RemoveObserver("media.getusermedia.playout_delay", this);
|
||||
prefs->RemoveObserver("media.ondevicechange.fakeDeviceChangeEvent.enabled", this);
|
||||
prefs->RemoveObserver("media.getusermedia.channels", this);
|
||||
#endif
|
||||
prefs->RemoveObserver("media.navigator.audio.full_duplex", this);
|
||||
}
|
||||
|
@ -3181,6 +3181,22 @@ SourceMediaStream::HasPendingAudioTrack()
|
||||
return audioTrackPresent;
|
||||
}
|
||||
|
||||
bool
|
||||
SourceMediaStream::OpenNewAudioCallbackDriver(AudioDataListener * aListener)
|
||||
{
|
||||
MOZ_ASSERT(GraphImpl()->mLifecycleState ==
|
||||
MediaStreamGraphImpl::LifecycleState::LIFECYCLE_RUNNING);
|
||||
AudioCallbackDriver* nextDriver = new AudioCallbackDriver(GraphImpl());
|
||||
nextDriver->SetInputListener(aListener);
|
||||
{
|
||||
MonitorAutoLock lock(GraphImpl()->GetMonitor());
|
||||
GraphImpl()->CurrentDriver()->SwitchAtNextIteration(nextDriver);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MediaInputPort::Init()
|
||||
{
|
||||
|
@ -808,6 +808,8 @@ public:
|
||||
return mStreamTracksStartTimeStamp;
|
||||
}
|
||||
|
||||
bool OpenNewAudioCallbackDriver(AudioDataListener *aListener);
|
||||
|
||||
// XXX need a Reset API
|
||||
|
||||
friend class MediaStreamGraphImpl;
|
||||
|
@ -74,7 +74,7 @@ var tests = [
|
||||
|
||||
var mustSupport = [
|
||||
'width', 'height', 'frameRate', 'facingMode', 'deviceId',
|
||||
'echoCancellation', 'noiseSuppression', 'autoGainControl',
|
||||
'echoCancellation', 'noiseSuppression', 'autoGainControl', 'channelCount',
|
||||
|
||||
// Yet to add:
|
||||
// 'aspectRatio', 'volume', 'sampleRate', 'sampleSize', 'latency', 'groupId'
|
||||
|
@ -105,6 +105,7 @@ public:
|
||||
, mExtendedFilter(false)
|
||||
, mDelayAgnostic(false)
|
||||
, mFakeDeviceChangeEventOn(false)
|
||||
, mChannels(0)
|
||||
{}
|
||||
|
||||
int32_t mWidth;
|
||||
@ -123,6 +124,7 @@ public:
|
||||
bool mExtendedFilter;
|
||||
bool mDelayAgnostic;
|
||||
bool mFakeDeviceChangeEventOn;
|
||||
int32_t mChannels;
|
||||
|
||||
// mWidth and/or mHeight may be zero (=adaptive default), so use functions.
|
||||
|
||||
|
@ -41,6 +41,7 @@ nsTArray<nsCString>* AudioInputCubeb::mDeviceNames;
|
||||
cubeb_device_collection AudioInputCubeb::mDevices = { nullptr, 0 };
|
||||
bool AudioInputCubeb::mAnyInUse = false;
|
||||
StaticMutex AudioInputCubeb::sMutex;
|
||||
uint32_t AudioInputCubeb::sUserChannelCount = 0;
|
||||
|
||||
// AudioDeviceID is an annoying opaque value that's really a string
|
||||
// pointer, and is freed when the cubeb_device_collection is destroyed
|
||||
|
@ -152,10 +152,12 @@ public:
|
||||
virtual int GetRecordingDeviceName(int aIndex, char (&aStrNameUTF8)[128],
|
||||
char aStrGuidUTF8[128]) = 0;
|
||||
virtual int GetRecordingDeviceStatus(bool& aIsAvailable) = 0;
|
||||
virtual int GetChannelCount(int aDeviceIndex, uint32_t& aChannels) = 0;
|
||||
virtual void GetChannelCount(uint32_t& aChannels) = 0;
|
||||
virtual int GetMaxAvailableChannels(uint32_t& aChannels) = 0;
|
||||
virtual void StartRecording(SourceMediaStream *aStream, AudioDataListener *aListener) = 0;
|
||||
virtual void StopRecording(SourceMediaStream *aStream) = 0;
|
||||
virtual int SetRecordingDevice(int aIndex) = 0;
|
||||
virtual void SetUserChannelCount(uint32_t aChannels) = 0;
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
@ -264,9 +266,19 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetChannelCount(int aDeviceIndex, uint32_t& aChannels)
|
||||
void GetChannelCount(uint32_t& aChannels)
|
||||
{
|
||||
return GetDeviceMaxChannels(aDeviceIndex, aChannels);
|
||||
GetUserChannelCount(mSelectedDevice, aChannels);
|
||||
}
|
||||
|
||||
static void GetUserChannelCount(int aDeviceIndex, uint32_t& aChannels)
|
||||
{
|
||||
aChannels = sUserChannelCount;
|
||||
}
|
||||
|
||||
int GetMaxAvailableChannels(uint32_t& aChannels)
|
||||
{
|
||||
return GetDeviceMaxChannels(mSelectedDevice, aChannels);
|
||||
}
|
||||
|
||||
static int GetDeviceMaxChannels(int aDeviceIndex, uint32_t& aChannels)
|
||||
@ -283,6 +295,18 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetUserChannelCount(uint32_t aChannels)
|
||||
{
|
||||
if (GetDeviceMaxChannels(mSelectedDevice, sUserChannelCount)) {
|
||||
sUserChannelCount = 1; // error capture mono
|
||||
return;
|
||||
}
|
||||
|
||||
if (aChannels && aChannels < sUserChannelCount) {
|
||||
sUserChannelCount = aChannels;
|
||||
}
|
||||
}
|
||||
|
||||
void StartRecording(SourceMediaStream *aStream, AudioDataListener *aListener)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
@ -344,6 +368,7 @@ private:
|
||||
static cubeb_device_collection mDevices;
|
||||
static bool mAnyInUse;
|
||||
static StaticMutex sMutex;
|
||||
static uint32_t sUserChannelCount;
|
||||
};
|
||||
|
||||
class AudioInputWebRTC final : public AudioInput
|
||||
@ -384,12 +409,20 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetChannelCount(int aDeviceIndex, uint32_t& aChannels)
|
||||
void GetChannelCount(uint32_t& aChannels)
|
||||
{
|
||||
aChannels = 1; // default to mono
|
||||
}
|
||||
|
||||
int GetMaxAvailableChannels(uint32_t& aChannels)
|
||||
{
|
||||
aChannels = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetUserChannelCount(uint32_t aChannels)
|
||||
{}
|
||||
|
||||
void StartRecording(SourceMediaStream *aStream, AudioDataListener *aListener) {}
|
||||
void StopRecording(SourceMediaStream *aStream) {}
|
||||
|
||||
|
@ -217,6 +217,7 @@ MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
|
||||
mSettings.mEchoCancellation.Construct(0);
|
||||
mSettings.mAutoGainControl.Construct(0);
|
||||
mSettings.mNoiseSuppression.Construct(0);
|
||||
mSettings.mChannelCount.Construct(0);
|
||||
// We'll init lazily as needed
|
||||
}
|
||||
|
||||
@ -288,12 +289,31 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
|
||||
prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn);
|
||||
prefs.mAgcOn = c.mAutoGainControl.Get(prefs.mAgcOn);
|
||||
prefs.mNoiseOn = c.mNoiseSuppression.Get(prefs.mNoiseOn);
|
||||
uint32_t maxChannels = 1;
|
||||
if (mAudioInput->GetMaxAvailableChannels(maxChannels) != 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Check channelCount violation
|
||||
if (static_cast<int32_t>(maxChannels) < c.mChannelCount.mMin ||
|
||||
static_cast<int32_t>(maxChannels) > c.mChannelCount.mMax) {
|
||||
*aOutBadConstraint = "channelCount";
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Clamp channelCount to a valid value
|
||||
if (prefs.mChannels <= 0) {
|
||||
prefs.mChannels = static_cast<int32_t>(maxChannels);
|
||||
}
|
||||
prefs.mChannels = c.mChannelCount.Get(std::min(prefs.mChannels,
|
||||
static_cast<int32_t>(maxChannels)));
|
||||
// Clamp channelCount to a valid value
|
||||
prefs.mChannels = std::max(1, std::min(prefs.mChannels, static_cast<int32_t>(maxChannels)));
|
||||
|
||||
LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d",
|
||||
prefs.mAecOn ? prefs.mAec : -1,
|
||||
prefs.mAgcOn ? prefs.mAgc : -1,
|
||||
prefs.mNoiseOn ? prefs.mNoise : -1,
|
||||
prefs.mPlayoutDelay));
|
||||
LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d, channels: %d",
|
||||
prefs.mAecOn ? prefs.mAec : -1,
|
||||
prefs.mAgcOn ? prefs.mAgc : -1,
|
||||
prefs.mNoiseOn ? prefs.mNoise : -1,
|
||||
prefs.mPlayoutDelay,
|
||||
prefs.mChannels));
|
||||
|
||||
mPlayoutDelay = prefs.mPlayoutDelay;
|
||||
|
||||
@ -310,21 +330,48 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
|
||||
// (Bug 1238038) fail allocation for a second device
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mAudioInput->SetRecordingDevice(mCapIndex)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mAudioInput->SetUserChannelCount(prefs.mChannels);
|
||||
if (!AllocChannel()) {
|
||||
FreeChannel();
|
||||
LOG(("Audio device is not initalized"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (mAudioInput->SetRecordingDevice(mCapIndex)) {
|
||||
FreeChannel();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
LOG(("Audio device %d allocated", mCapIndex));
|
||||
{
|
||||
// Update with the actual applied channelCount in order
|
||||
// to store it in settings.
|
||||
uint32_t channelCount = 0;
|
||||
mAudioInput->GetChannelCount(channelCount);
|
||||
MOZ_ASSERT(channelCount > 0);
|
||||
prefs.mChannels = channelCount;
|
||||
}
|
||||
break;
|
||||
|
||||
case kStarted:
|
||||
if (prefs == mLastPrefs) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (prefs.mChannels != mLastPrefs.mChannels) {
|
||||
MOZ_ASSERT(mSources.Length() > 0);
|
||||
auto& source = mSources.LastElement();
|
||||
mAudioInput->SetUserChannelCount(prefs.mChannels);
|
||||
// Get validated number of channel
|
||||
uint32_t channelCount = 0;
|
||||
mAudioInput->GetChannelCount(channelCount);
|
||||
MOZ_ASSERT(channelCount > 0 && mLastPrefs.mChannels > 0);
|
||||
// Check if new validated channels is the same as previous
|
||||
if (static_cast<uint32_t>(mLastPrefs.mChannels) != channelCount
|
||||
&& !source->OpenNewAudioCallbackDriver(mListener)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Update settings
|
||||
prefs.mChannels = channelCount;
|
||||
}
|
||||
|
||||
if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) {
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
if (mSources.IsEmpty()) {
|
||||
@ -384,6 +431,7 @@ MediaEngineWebRTCMicrophoneSource::SetLastPrefs(
|
||||
that->mSettings.mEchoCancellation.Value() = aPrefs.mAecOn;
|
||||
that->mSettings.mAutoGainControl.Value() = aPrefs.mAgcOn;
|
||||
that->mSettings.mNoiseSuppression.Value() = aPrefs.mNoiseOn;
|
||||
that->mSettings.mChannelCount.Value() = aPrefs.mChannels;
|
||||
return NS_OK;
|
||||
}));
|
||||
}
|
||||
@ -796,9 +844,9 @@ MediaEngineWebRTCMicrophoneSource::AllocChannel()
|
||||
webrtc::CodecInst codec;
|
||||
strcpy(codec.plname, ENCODING);
|
||||
codec.channels = CHANNELS;
|
||||
uint32_t channels = 0;
|
||||
if (mAudioInput->GetChannelCount(mCapIndex, channels) == 0) {
|
||||
codec.channels = channels;
|
||||
uint32_t maxChannels = 0;
|
||||
if (mAudioInput->GetMaxAvailableChannels(maxChannels) == 0) {
|
||||
codec.channels = maxChannels;
|
||||
}
|
||||
MOZ_ASSERT(mSampleFrequency == 16000 || mSampleFrequency == 32000);
|
||||
codec.rate = SAMPLE_RATE(mSampleFrequency);
|
||||
|
@ -378,6 +378,9 @@ FlattenedConstraints::FlattenedConstraints(const NormalizedConstraints& aOther)
|
||||
if (mAutoGainControl.Intersects(set.mAutoGainControl)) {
|
||||
mAutoGainControl.Intersect(set.mAutoGainControl);
|
||||
}
|
||||
if (mChannelCount.Intersects(set.mChannelCount)) {
|
||||
mChannelCount.Intersect(set.mChannelCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,7 @@ public:
|
||||
StringRange mDeviceId;
|
||||
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
||||
BooleanRange mEchoCancellation, mNoiseSuppression, mAutoGainControl;
|
||||
LongRange mChannelCount;
|
||||
private:
|
||||
typedef NormalizedConstraintSet T;
|
||||
public:
|
||||
@ -258,7 +259,9 @@ public:
|
||||
aOther.mNoiseSuppression,
|
||||
advanced, aList)
|
||||
, mAutoGainControl(&T::mAutoGainControl, "autoGainControl",
|
||||
aOther.mAutoGainControl, advanced, aList) {}
|
||||
aOther.mAutoGainControl, advanced, aList)
|
||||
, mChannelCount(&T::mChannelCount, "channelCount",
|
||||
aOther.mChannelCount, advanced, aList) {}
|
||||
};
|
||||
|
||||
template<> bool NormalizedConstraintSet::Range<bool>::Merge(const Range& aOther);
|
||||
|
@ -488,6 +488,7 @@ pref("media.peerconnection.video.h264_enabled", false);
|
||||
pref("media.peerconnection.video.vp9_enabled", true);
|
||||
pref("media.getusermedia.aec", 1);
|
||||
pref("media.getusermedia.browser.enabled", false);
|
||||
pref("media.getusermedia.channels", 0);
|
||||
// Desktop is typically VGA capture or more; and qm_select will not drop resolution
|
||||
// below 1/2 in each dimension (or so), so QVGA (320x200) is the lowest here usually.
|
||||
pref("media.peerconnection.video.min_bitrate", 0);
|
||||
|
Loading…
Reference in New Issue
Block a user