Чтобы уточнить ответ an00b:s выше и отредактированную версию вопроса, мы должны углубиться в исходный код. IAudioflinger — это интерфейс к службе AudioFlinger и вызов
virtual status_t setMicMute(bool state)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(state);
remote()->transact(SET_MIC_MUTE, data, &reply);
return reply.readInt32();
}
на самом деле является транзакцией Binder для отключения микрофона. Принимающая сторона вызова Binder выглядит следующим образом:
status_t BnAudioFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch(code) {
...
case SET_MIC_MUTE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int state = data.readInt32();
reply->writeInt32( setMicMute(state) );
return NO_ERROR;
} break;
...
}
}
и вызовы фактической реализации setMicMute в файле AudioFlinger. Следующий шаг — посмотреть на эту функцию:
status_t AudioFlinger::setMicMute(bool state) {
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MIC_MUTE;
status_t ret = mAudioHardware->setMicMute(state);
mHardwareStatus = AUDIO_HW_IDLE;
return ret;
}
Здесь мы можем отметить две вещи. Во-первых, есть проверка разрешений, позволяющая отключить микрофон. Разрешение, которое проверяется в settingsAllowed, — это android.permission.MODIFY_AUDIO_SETTINGS, поэтому, как упоминалось в одном из комментариев выше, первое требование для отключения микрофона заключается в том, что ваше приложение заявило, что ему требуется это разрешение. Следующее, что следует отметить, это то, что теперь мы вызываем аппаратную версию setMicMute, используя mAudioHardware->setMicMute(state).
Для получения дополнительной информации о том, как подключается оборудование, изучите файл AudioHardwareInterface.cpp. По сути, это заканчивается в libhardware с внешним вызовом C для createAudioHardware, который подключает правильный AudioHardWare для платформы. Существуют также переключатели для использования оборудования на основе A2DP, общий для эмулятора и заглушки звука. Предполагается, что вы работаете на реальном устройстве, реализация которого во многом зависит от аппаратного обеспечения. Чтобы почувствовать это, мы можем использовать доступное аудиооборудование от Crespo (Nexus S) в качестве примера.
status_t AudioHardware::setMicMute(bool state) {
LOGV("setMicMute(%d) mMicMute %d", state, mMicMute);
sp<AudioStreamInALSA> spIn;
{
AutoMutex lock(mLock);
if (mMicMute != state) {
mMicMute = state;
// in call mute is handled by RIL
if (mMode != AudioSystem::MODE_IN_CALL) {
spIn = getActiveInput_l();
}
}
}
if (spIn != 0) {
spIn->standby();
}
return NO_ERROR;
}
На этом примере мы можем завершить обсуждение реализации маршрутизации звука в смартфонах. Как вы можете видеть в реализации Crespo, вызов отключения звука микрофона будет учитываться только в том случае, если вы не участвуете в вызове. Причина этого в том, что звук направляется через аналоговую полосу модулирующих сигналов, которая отвечает за регулировку мощности, усиление и другие функции. Во время вызова голосовой звук часто обрабатывается процессором аналоговой полосы частот и модема вместе и не направляется через процессор приложения. В этом случае вам может понадобиться пройти через процессор модема через RIL, чтобы отключить микрофон. Но поскольку это поведение зависит от оборудования, общего решения нет.
Чтобы дать краткую версию ваших 4 дополнительных вопросов:
Флаг передается через несколько слоев кода, пока не окажется в аппаратно-зависимом микрофоне отключения звука.
Микрофон отключается, когда выполняется аппаратный код, за исключением случаев, когда во время вызова по крайней мере на некоторых устройствах.
Когда setMicrophoneMute не отключает звук микрофона, то есть во время разговора это можно сделать с помощью одного из API телефонии, я бы посоветовал изучить приложение для телефона.
Судя по текущей реализации, отключение звука работает, когда не происходит вызов, но могут быть проблемы с аппаратным обеспечением на платформах, которые мы здесь не изучали.
ИЗМЕНИТЬ:
Еще немного покопался, и способ отправить команду отключения звука на процессор модема — через внутренний интерфейс телефона, который является частью пакета com.android.internal.telephony, который недоступен разработчикам SDK. Основываясь на комментарии, который вы видели, что эта функция должна использоваться только приложениями, которые заменяют управление звуком или исходное приложение телефонии, я бы предположил, что AudioManager.setMicrophoneMute() должен был всегда отключать микрофон независимо. Но поскольку другие приложения, вероятно, используют это, они добавили проверку в аппаратную реализацию, чтобы не испортить состояние телефонного приложения, которое отслеживает отключенные соединения, а также микрофон. Эта функция, вероятно, не работает так, как предполагалось, из-за деталей аппаратной реализации и того факта, что отключение звука — гораздо более сложная операция, чем можно было бы подумать при рассмотрении состояний вызовов.
person
BMB
schedule
18.08.2011
checkAudioSettingsPermission
? - person YetAnotherUser   schedule 03.08.2011setMicrophoneMute()
наcheckAudioSettingsPermission
, но знаете ли вы, что делаетcheckAudioSettingsPermission
и что означает этот параметрString
? +1 - person ateiob   schedule 05.08.2011