summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJean-Michel Trivi <jmtrivi@google.com>2015-04-01 22:38:28 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-04-01 22:38:28 +0000
commitf77236dc8560ffbdedd69163bf75a9ad7890d898 (patch)
tree40ea5d98e4403b485a8d7cd2ab69ca61cd50a749 /services
parent53d6802799da3dbd9b040278e8fbbf9200a91a2c (diff)
parent036e1e9126dcd496203434aa69e52115d8e730cc (diff)
downloadframeworks_av-f77236dc8560ffbdedd69163bf75a9ad7890d898.zip
frameworks_av-f77236dc8560ffbdedd69163bf75a9ad7890d898.tar.gz
frameworks_av-f77236dc8560ffbdedd69163bf75a9ad7890d898.tar.bz2
Merge "Add AudioMix and AudioMixCollection to common policy element"
Diffstat (limited to 'services')
-rw-r--r--services/audiopolicy/common/managerdefinitions/Android.mk1
-rw-r--r--services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h81
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp193
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp122
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h12
5 files changed, 307 insertions, 102 deletions
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index bc6900b..e3e213e 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \
src/HwModule.cpp \
src/IOProfile.cpp \
src/AudioPort.cpp \
+ src/AudioPolicyMix.cpp \
src/AudioPatch.cpp \
src/AudioInputDescriptor.cpp \
src/AudioOutputDescriptor.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
new file mode 100644
index 0000000..988aed6
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/RefBase.h>
+#include <media/AudioPolicy.h>
+#include <utils/KeyedVector.h>
+#include <hardware/audio.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class AudioOutputDescriptor;
+
+/**
+ * custom mix entry in mPolicyMixes
+ */
+class AudioPolicyMix : public RefBase {
+public:
+ AudioPolicyMix() {}
+
+ const sp<AudioOutputDescriptor> &getOutput() const;
+
+ void setOutput(sp<AudioOutputDescriptor> &output);
+
+ void clearOutput();
+
+ android::AudioMix &getMix();
+
+ void setMix(AudioMix &mix);
+
+private:
+ AudioMix mMix; // Audio policy mix descriptor
+ sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
+};
+
+
+class AudioPolicyMixCollection : public DefaultKeyedVector<String8, sp<AudioPolicyMix> >
+{
+public:
+ status_t getAudioPolicyMix(String8 address, sp<AudioPolicyMix> &policyMix) const;
+
+ status_t registerMix(String8 address, AudioMix mix);
+
+ status_t unregisterMix(String8 address);
+
+ void closeOutput(sp<AudioOutputDescriptor> &desc);
+
+ /**
+ * Try to find an output descriptor for the given attributes.
+ *
+ * @param[in] attributes to consider for the research of output descriptor.
+ * @param[out] desc to return if an output could be found.
+ *
+ * @return NO_ERROR if an output was found for the given attribute (in this case, the
+ * descriptor output param is initialized), error code otherwise.
+ */
+ status_t getOutputForAttr(audio_attributes_t attributes, sp<AudioOutputDescriptor> &desc);
+
+ audio_devices_t getDeviceAndMixForInputSource(audio_source_t inputSource,
+ audio_devices_t availableDeviceTypes,
+ AudioMix **policyMix);
+
+ status_t getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix);
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
new file mode 100644
index 0000000..84a53eb
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioPolicyMix"
+//#define LOG_NDEBUG 0
+
+#include "AudioPolicyMix.h"
+#include "HwModule.h"
+#include "AudioPort.h"
+#include "IOProfile.h"
+#include "AudioGain.h"
+#include <AudioOutputDescriptor.h>
+
+namespace android {
+
+void AudioPolicyMix::setOutput(sp<AudioOutputDescriptor> &output)
+{
+ mOutput = output;
+}
+
+const sp<AudioOutputDescriptor> &AudioPolicyMix::getOutput() const
+{
+ return mOutput;
+}
+
+void AudioPolicyMix::clearOutput()
+{
+ mOutput.clear();
+}
+
+void AudioPolicyMix::setMix(AudioMix &mix)
+{
+ mMix = mix;
+}
+
+android::AudioMix &AudioPolicyMix::getMix()
+{
+ return mMix;
+}
+
+status_t AudioPolicyMixCollection::registerMix(String8 address, AudioMix mix)
+{
+ ssize_t index = indexOfKey(address);
+ if (index >= 0) {
+ ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
+ return BAD_VALUE;
+ }
+ sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
+ policyMix->setMix(mix);
+ add(address, policyMix);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::unregisterMix(String8 address)
+{
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+ return BAD_VALUE;
+ }
+
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyMixCollection::getAudioPolicyMix(String8 address,
+ sp<AudioPolicyMix> &policyMix) const
+{
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+ return BAD_VALUE;
+ }
+ policyMix = valueAt(index);
+ return NO_ERROR;
+}
+
+void AudioPolicyMixCollection::closeOutput(sp<AudioOutputDescriptor> &desc)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioPolicyMix> policyMix = valueAt(i);
+ if (policyMix->getOutput() == desc) {
+ policyMix->clearOutput();
+ }
+ }
+}
+
+status_t AudioPolicyMixCollection::getOutputForAttr(audio_attributes_t attributes,
+ sp<AudioOutputDescriptor> &desc)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioPolicyMix> policyMix = valueAt(i);
+ AudioMix mix = policyMix->getMix();
+
+ if (mix.mMixType == MIX_TYPE_PLAYERS) {
+ for (size_t j = 0; j < mix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
+ (RULE_EXCLUDE_ATTRIBUTE_USAGE == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
+ desc = policyMix->getOutput();
+ break;
+ }
+ if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = policyMix->getOutput();
+ break;
+ }
+ }
+ } else if (mix.mMixType == MIX_TYPE_RECORDERS) {
+ if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
+ strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
+ strncmp(attributes.tags + strlen("addr="),
+ mix.mRegistrationId.string(),
+ AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
+ desc = policyMix->getOutput();
+ }
+ }
+ if (desc != 0) {
+ desc->mPolicyMix = &mix;
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+audio_devices_t AudioPolicyMixCollection::getDeviceAndMixForInputSource(audio_source_t inputSource,
+ audio_devices_t availDevices,
+ AudioMix **policyMix)
+{
+ for (size_t i = 0; i < size(); i++) {
+ AudioMix mix = valueAt(i)->getMix();
+
+ if (mix.mMixType != MIX_TYPE_RECORDERS) {
+ continue;
+ }
+ for (size_t j = 0; j < mix.mCriteria.size(); j++) {
+ if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mSource == inputSource) ||
+ (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mix.mCriteria[j].mRule &&
+ mix.mCriteria[j].mAttr.mSource != inputSource)) {
+ if (availDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ if (policyMix != NULL) {
+ *policyMix = &mix;
+ }
+ return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+ }
+ }
+ }
+ return AUDIO_DEVICE_NONE;
+}
+
+status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, AudioMix *&policyMix)
+{
+ if (strncmp(attr.tags, "addr=", strlen("addr=")) != 0) {
+ return BAD_VALUE;
+ }
+ String8 address(attr.tags + strlen("addr="));
+
+ ssize_t index = indexOfKey(address);
+ if (index < 0) {
+ ALOGW("getInputForAttr() no policy for address %s", address.string());
+ return BAD_VALUE;
+ }
+ sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
+ AudioMix mix = audioPolicyMix->getMix();
+
+ if (mix.mMixType != MIX_TYPE_PLAYERS) {
+ ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
+ return BAD_VALUE;
+ }
+ policyMix = &mix;
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 033ae49..12d1ab3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -707,45 +707,16 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
}
stream_type_to_audio_attributes(*stream, &attributes);
}
-
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- sp<AudioOutputDescriptor> desc;
- if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_PLAYERS) {
- for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
- if ((RULE_MATCH_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage == attributes.usage) ||
- (RULE_EXCLUDE_ATTRIBUTE_USAGE == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mUsage != attributes.usage)) {
- desc = mPolicyMixes[i]->mOutput;
- break;
- }
- if (strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
- strncmp(attributes.tags + strlen("addr="),
- mPolicyMixes[i]->mMix.mRegistrationId.string(),
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- desc = mPolicyMixes[i]->mOutput;
- break;
- }
- }
- } else if (mPolicyMixes[i]->mMix.mMixType == MIX_TYPE_RECORDERS) {
- if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE &&
- strncmp(attributes.tags, "addr=", strlen("addr=")) == 0 &&
- strncmp(attributes.tags + strlen("addr="),
- mPolicyMixes[i]->mMix.mRegistrationId.string(),
- AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - strlen("addr=") - 1) == 0) {
- desc = mPolicyMixes[i]->mOutput;
- }
- }
- if (desc != 0) {
- if (!audio_is_linear_pcm(format)) {
- return BAD_VALUE;
- }
- desc->mPolicyMix = &mPolicyMixes[i]->mMix;
- *stream = streamTypefromAttributesInt(&attributes);
- *output = desc->mIoHandle;
- ALOGV("getOutputForAttr() returns output %d", *output);
- return NO_ERROR;
+ sp<AudioOutputDescriptor> desc;
+ if (mPolicyMixes.getOutputForAttr(attributes, desc) == NO_ERROR) {
+ ALOG_ASSERT(desc != 0, "Invalid desc returned by getOutputForAttr");
+ if (!audio_is_linear_pcm(format)) {
+ return BAD_VALUE;
}
+ *stream = streamTypefromAttributesInt(&attributes);
+ *output = desc->mIoHandle;
+ ALOGV("getOutputForAttr() returns output %d", *output);
+ return NO_ERROR;
}
if (attributes.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
ALOGW("getOutputForAttr() no policy mix found for usage AUDIO_USAGE_VIRTUAL_SOURCE");
@@ -1286,19 +1257,13 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
- device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- address = String8(attr->tags + strlen("addr="));
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index < 0) {
- ALOGW("getInputForAttr() no policy for address %s", address.string());
- return BAD_VALUE;
- }
- if (mPolicyMixes[index]->mMix.mMixType != MIX_TYPE_PLAYERS) {
- ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
- return BAD_VALUE;
+ status_t ret = mPolicyMixes.getInputMixForAttr(*attr, policyMix);
+ if (ret != NO_ERROR) {
+ return ret;
}
- policyMix = &mPolicyMixes[index]->mMix;
*inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ address = String8(attr->tags + strlen("addr="));
} else {
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
if (device == AUDIO_DEVICE_NONE) {
@@ -1929,9 +1894,8 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index >= 0) {
- ALOGE("registerPolicyMixes(): mix for address %s already registered", address.string());
+
+ if (mPolicyMixes.registerMix(address, mixes[i]) != NO_ERROR) {
continue;
}
audio_config_t outputConfig = mixes[i].mFormat;
@@ -1944,9 +1908,7 @@ status_t AudioPolicyManager::registerPolicyMixes(Vector<AudioMix> mixes)
AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
module->addInputProfile(address, &inputConfig,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
- sp<AudioPolicyMix> policyMix = new AudioPolicyMix();
- policyMix->mMix = mixes[i];
- mPolicyMixes.add(address, policyMix);
+
if (mixes[i].mMixType == MIX_TYPE_PLAYERS) {
setDeviceConnectionStateInt(AUDIO_DEVICE_IN_REMOTE_SUBMIX,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
@@ -1979,14 +1941,11 @@ status_t AudioPolicyManager::unregisterPolicyMixes(Vector<AudioMix> mixes)
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index < 0) {
- ALOGE("unregisterPolicyMixes(): mix for address %s not registered", address.string());
+
+ if (mPolicyMixes.unregisterMix(address) != NO_ERROR) {
continue;
}
- mPolicyMixes.removeItemsAt(index);
-
if (getDeviceConnectionState(AUDIO_DEVICE_IN_REMOTE_SUBMIX, address.string()) ==
AUDIO_POLICY_DEVICE_STATE_AVAILABLE)
{
@@ -3261,14 +3220,14 @@ status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor> de
if (output != AUDIO_IO_HANDLE_NONE) {
addOutput(output, desc);
if (device_distinguishes_on_address(device) && address != "0") {
- ssize_t index = mPolicyMixes.indexOfKey(address);
- if (index >= 0) {
- mPolicyMixes[index]->mOutput = desc;
- desc->mPolicyMix = &mPolicyMixes[index]->mMix;
- } else {
+ sp<AudioPolicyMix> policyMix;
+ if (mPolicyMixes.getAudioPolicyMix(address, policyMix) != NO_ERROR) {
ALOGE("checkOutputsForDevice() cannot find policy for address %s",
address.string());
}
+ policyMix->setOutput(desc);
+ desc->mPolicyMix = &(policyMix->getMix());
+
} else if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) {
// no duplicated output for direct outputs and
// outputs used by dynamic policy mixes
@@ -3579,12 +3538,7 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
ALOGW("closeOutput() unknown output %d", output);
return;
}
-
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- if (mPolicyMixes[i]->mOutput == outputDesc) {
- mPolicyMixes[i]->mOutput.clear();
- }
- }
+ mPolicyMixes.closeOutput(outputDesc);
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -4730,29 +4684,13 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
AudioMix **policyMix)
{
- audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() &
- ~AUDIO_DEVICE_BIT_IN;
+ audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
+ audio_devices_t selectedDeviceFromMix =
+ mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
- for (size_t i = 0; i < mPolicyMixes.size(); i++) {
- if (mPolicyMixes[i]->mMix.mMixType != MIX_TYPE_RECORDERS) {
- continue;
- }
- for (size_t j = 0; j < mPolicyMixes[i]->mMix.mCriteria.size(); j++) {
- if ((RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource == inputSource) ||
- (RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET == mPolicyMixes[i]->mMix.mCriteria[j].mRule &&
- mPolicyMixes[i]->mMix.mCriteria[j].mAttr.mSource != inputSource)) {
- if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
- if (policyMix != NULL) {
- *policyMix = &mPolicyMixes[i]->mMix;
- }
- return AUDIO_DEVICE_IN_REMOTE_SUBMIX;
- }
- break;
- }
- }
+ if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {
+ return selectedDeviceFromMix;
}
-
return getDeviceForInputSource(inputSource);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index ce9c69c..6b70f2e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -36,6 +36,7 @@
#include <HwModule.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
namespace android {
@@ -474,16 +475,7 @@ protected:
uint32_t mBeaconPlayingRefCount;// ref count for the playing beacon streams
bool mBeaconMuted; // has STREAM_TTS been muted
- // custom mix entry in mPolicyMixes
- class AudioPolicyMix : public RefBase {
- public:
- AudioPolicyMix() {}
-
- AudioMix mMix; // Audio policy mix descriptor
- sp<AudioOutputDescriptor> mOutput; // Corresponding output stream
- };
- DefaultKeyedVector<String8, sp<AudioPolicyMix> > mPolicyMixes; // list of registered mixes
-
+ AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
#ifdef AUDIO_POLICY_TEST
Mutex mLock;