31

私はAndroidを使用しようとしましたが、AudioManager.setMicrophoneMute()あまり成功しませんでした。つまり、私が何をしても、マイクをミュートすることを拒否するだけです。

いくつかの手がかりを求めてウェブを検索したところ、同様の経験を報告しているいくつかの参考文献が見つかりました。

これは疑問を投げかけます:AudioManager.setMicrophoneMute()まったく機能しますか? Androidの将来のバージョンで実装されるのを待っている、単なるスタブメソッドですか? そうでない場合、どのように機能しますか?機能させるには何が必要ですか?その名前が示すように機能する条件は何ですか?

編集:このメソッドのドキュメントに次のように記載されていることに気付きました:

このメソッドは、オーディオ設定のプラットフォーム全体の管理を置き換えるアプリケーションまたはメインのテレフォニー アプリケーションでのみ使用する必要があります。

これは何を意味するのでしょうか?プラットフォーム全体の管理を置き換える必要があるのはなぜですか? 私は本当にそれをする必要がありますか?もしそうなら、どうすればいいですか?

編集:以下の答えは素晴らしいですが、私はまだ理解していません:

  1. そのフラグ (データベースの SET_MIC_MUTE) はどのように使用されていますか?
  2. このフラグが実際に電話機内のプリアンプ回路からマイク信号を切断するのはいつですか?
  3. もしそうしないなら、誰がするのですか?
  4. 何もしない場合、この「ミュート」はどのように機能すると予想されますか?

説明してください。ありがとう。

4

3 に答える 3

23

上記の 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;
    ...
    }
}

AudioFlinger でsetMicMuteの実際の実装を呼び出します。次のステップは、この関数を確認することです。

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;
}

ここで、2 つのことがわかります。1 つ目は、マイクをミュートできる権限チェックがあることです。settingsAllowed でチェックされる許可は android.permission.MODIFY_AUDIO_SETTINGS であるため、上記のコメントの 1 つで述べたように、マイクをミュートするための最初の要件は、アプリケーションがこの許可が必要であることを宣言していることです。次に注意すべきことは、mAudioHardware->setMicMute(state) を使用して setMicMute のハードウェア固有バージョンを呼び出していることです。

ハードウェアを接続する方法の詳細については、ファイル AudioHardwareInterface.cpp を調べてください。基本的には、プラットフォームの正しい AudioHardWare をプラグインする createAudioHardware への extern C 呼び出しを含む libhardware になります。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 の実装でわかるように、マイク ミュート コールは、通話中でない場合にのみ尊重されます。その理由は、電力調整、増幅などを処理するアナログ ベースバンドを介してオーディオがルーティングされるためです。通話中の音声は、多くの場合、アナログ ベースバンドとモデム CPU によって一緒に処理され、アプリケーション CPU を介してルーティングされません。その場合、マイクをミュートするために、RIL を介してモデム CPU を通過する必要がある場合があります。しかし、この動作はハードウェアに依存するため、一般的な解決策はありません。

4 つの追加の質問に短いバージョンを与えるには:

  1. フラグは、ハードウェア固有のミュート マイクに到達するまで、複数のコード レイヤーを介して渡されます。

  2. 少なくとも一部のデバイスでの通話中を除き、ハードウェア固有のコードが実行されると、マイクが切断されます。

  3. setMicrophoneMute がマイクをミュートしない場合、つまり通話中にテレフォニー API の 1 つを使用してミュートできる可能性がある場合は、電話アプリを検討することをお勧めします。

  4. 現在の実装に基づくと、通話中でない場合はミュートが機能しているように見えますが、ここでは調査していないプラットフォームにハードウェア固有の問題がある可能性があります。

編集:

さらに掘り下げて、モデム CPU にミュート コマンドを送信する方法は、SDK 開発者が利用できない com.android.internal.telephony パッケージの一部である内部電話インターフェイスを介することです。この関数は、オーディオ管理を置き換えるアプリケーションまたは元の電話アプリケーションでのみ使用する必要があるというコメントに基づいて、 AudioManager.setMicrophoneMute() は常にマイクをミュートするはずだったと思います。しかし、他のアプリケーションはおそらくこれを使用しているため、ミュートされた接続とマイクを追跡する電話アプリケーションの状態を台無しにしないように、ハードウェア実装にチェックを追加しました。

于 2011-08-18T09:55:39.070 に答える
12

AudioManagerのソースコードを見てみてください:

public void setMicrophoneMute(boolean on){
    IAudioService service = getService();
    try {
        service.setMicrophoneMute(on);
    } catch (RemoteException e) {
        Log.e(TAG, "Dead object in setMicrophoneMute", e);
    }
}

マイクをミュートするタスクは、IAudioServiceという名前のサービスに委任されます。

public void setMicrophoneMute(boolean on) {
    if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
        return;
    }
    synchronized (mSettingsLock) {
        if (on != mMicMute) {
            AudioSystem.muteMicrophone(on);
            mMicMute = on;
        } 
    }
}

次に、ネイティブコードで実装されているように見えるAudioSystemに委任します。

status_t AudioSystem::muteMicrophone(bool state) {
    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
    if (af == 0) return PERMISSION_DENIED;
    return af->setMicMute(state);
}

これは、IAudioFlinger.cppにあるように、それをIAudioFlingerに委任します

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();
}
于 2011-07-29T19:45:10.020 に答える