web-dev-qa-db-ja.com

Android AudioRecordは別のストリームをMICオーディオソースに強制します

更新3:私は別の開発者と提携しており、これを多額の資金で行える人を見つけたようです。彼らは私たちにテストapkを送信しましたが、うまくいくようです。ソースを購入します。詐欺にならないことを願っています。判明したら更新します

更新2:まだ作業中です。痛みを伴う日の後、私は今は何も変わっていないと思いますが、ネイティブ側でAudioFlinger( リンクを参照 )を使用してAudioFlinger :: setParametersを単に使用しています

私は今、audio_io_handle_t ioHandle、const String8&keyValuePairsでAudioFlinger :: setParametersを呼び出す簡単なJNIを書く方法を探しています。

私は何ができるか知っていますkeyValuePairsaudio_io_handle_tの手掛かりではありません

更新:現在、他のアプリがCAFでQCOMオーディオを使用している可能性があります。 同じリンク でaudio_extn_utils_send_audio_calibrationを参照してください

同じリンク のvoice_get_incall_rec_snd_device

C/++の知識がありません。これらのメソッドをネイティブ側から呼び出すことができるかどうかを確認するにはどうすればよいですか?他のアプリでもできるので、方法が必要です。


私はこれに40日以上、少なくとも1日5〜6時間苦労しています。 SOで許可されているかどうかはわかりませんが、正解に対しても寄付をさせていただきます。

VOICE_CALLオーディオソースを使用する通話録音アプリがあります。 ASOPはそれを実装/強制しませんが、ほとんどのメーカーはVOICE_CALLを実装しており、VOICE_CALLオーディオソースを使用するアプリは多くのデバイスで正常に機能しました。 Android 6。

Googleは、この動作をAndroid 6.で変更しました。VOICE_CALLオーディオソースを開くには、システムアプリケーションにのみ付与されるAndroid.permission.CAPTURE_AUDIO_OUTPUTが必要になりました。

これは基本的に通話録音を停止するか、停止する必要があります。まあ、それは私とこの制限を回避する方法を見つけた3を除く200以上の他の通話録音アプリのためにそれを行います。

私はこれらのアプリをAndroid 6で多くの異なる携帯電話で試してみましたが、それらが管理する方法で特定の特性を見つけました。

彼らはすべてAndroid AudioRecordクラスを使用し、MICオーディオソースを開きます。私も行います。ただし、アプリでは、MICからのみ音声を取得し、相手からは音声を取得しません。レコーディングを開始する直前または開始する前に、何らかのシステムコールを発行していることを教えてください。

MICを使用して記録している場合でも、VOICE_CALLを正常に記録するアプリの1つである次のログをご覧ください。 VOICE_CALLオーディオソースをMICにミキシング/ルーティング/ストリーム/マージする方法はアプリのようです。

- D/audio_hw_primary: in_set_parameters: enter: kvpairs=input_source=1;routing=-2147483644
- D/PermissionCache: checking Android.permission.MODIFY_AUDIO_SETTINGS for uid=10286 => granted (432 us)
- D/audio_hw_primary: in_set_parameters: enter: kvpairs=input_source=4;routing=-2147483584;format=1
- D/audio_hw_primary: select_devices: out_snd_device(0: ) in_snd_device(283: voice-dmic-ef)
- D/hardware_info: hw_info_append_hw_type : device_name = voice-dmic-ef
- D/voice: voice_get_incall_rec_snd_device: in_snd_device(283: voice-dmic-ef) incall_record_device(283: voice-dmic-ef)

最初の行でわかるように、MICオーディオソースinput_source = 1; routing = -2147483644で始まっています。

次に、2行目で何かを実行し、Android.permission.MODIFY_AUDIO_SETTINGSが付与されます。これは通常の許可であり、私のアプリにもあります。これが最も重要な部分のようであり、3つすべてがJNIを使​​用してVOICE_CALLオーディオソースのMICへのストリーミング/マージをトリガーし、標準のAudioRecorder APIで録音するために行うことを行っているようです。

次の行では、MIC(1)オーディオソースを開いているにもかかわらず、VOICE_CALL(input_source = 4)のミキシングを開始するオーディオハードウェアが表示されます。

私は彼らが使用すると仮定しました

AudioManager.setParameters("key=value")

などの多くのバリエーションを試しました

AudioManager.setParameters("input_source=4;routing=-2147483584;format=1")

運もなく。

そして、私は Android、NDK、オーディオルーティング、ヘッドセットにオーディオを強制する を見つけ、VOICE_CALLを現在のAudioRecordセッションにどのようにミックス/ルート/ストリーム/マージするかを考えました( Cの知識)は、リフレーションを使用して、以下のコード(同じ)で同じことを運なしで達成しようとしました。

private static void setForceUseOn() {

/*
setForceUse(int usage, int config);

----usage for setForceUse, must match AudioSystem::force_use
public static final int FOR_COMMUNICATION = 0;
public static final int FOR_MEDIA = 1;
public static final int FOR_RECORD = 2;
public static final int FOR_DOCK = 3;
public static final int FOR_SYSTEM = 4;
public static final int FOR_HDMI_SYSTEM_AUDIO = 5;

----device categories config for setForceUse, must match AudioSystem::forced_config
public static final int FORCE_NONE = 0;
public static final int FORCE_SPEAKER = 1;
public static final int FORCE_HEADPHONES = 2;
public static final int FORCE_BT_SCO = 3;
public static final int FORCE_BT_A2DP = 4;
public static final int FORCE_WIRED_ACCESSORY = 5;
public static final int FORCE_BT_CAR_DOCK = 6;
public static final int FORCE_BT_DESK_DOCK = 7;
public static final int FORCE_ANALOG_DOCK = 8;
public static final int FORCE_DIGITAL_DOCK = 9;
public static final int FORCE_NO_BT_A2DP = 10;
public static final int FORCE_SYSTEM_ENFORCED = 11;
public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
public static final int FORCE_DEFAULT = FORCE_NONE;


 */

    try {
        Class audioSystemClass = Class.forName("Android.media.AudioSystem");
        Method setForceUse = audioSystemClass.getMethod("setForceUse", int.class, int.class);
        setForceUse.invoke(null, 0, 0);      // setForceUse(FOR_RECORD, FORCE_NONE)


    } catch (Exception e) {
        e.printStackTrace();
    }

}

明らかに、録音を可能にするものが欠けています。

私もこの情報を得るために支払うことを申し出ました、すべて拒否しました。申し分ありません。一度公開するか、見つけたら公開します!

彼らが何をしているのかについて、何か考えはありますか?

81
nLL

私と私のパートナーは、探していたものを購入することができました。私たちは正しい道を歩んでいたので、ネイティブ側でkeyValuePairsを設定しました。

残念ながら、私たちのために書かれた会社からのライセンス制限のため、ソースを公開することはできません

10
nLL

あなたの発見は興味深いものです。私はAudioRecord AP​​Iを含むいくつかの小さなプロジェクトに取り組みました。うまくいけば、次のことが役立つでしょう:

AudioRecordインスタンスをセットアップして、16kHzで16ビットのモノラルで録音できるようにするとします。これを実現するには、次のようないくつかのヘルパーメソッドでクラスを作成します。

public class AudioRecordTool {
        private final int minBufferSize;
        private boolean doRecord = false;
        private final AudioRecord audioRecord;

        public AudioRecordTool() {
            minBufferSize = AudioTrack.getMinBufferSize(16000,
                    AudioFormat.CHANNEL_OUT_MONO,
                    AudioFormat.ENCODING_PCM_16BIT);
            audioRecord = new AudioRecord(
                    MediaRecorder.AudioSource.VOICE_COMMUNICATION,
                    16000,
                    AudioFormat.CHANNEL_IN_MONO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    minBufferSize * 2);
        }

        public void writeAudioToStream(OutputStream audioStream) {
            doRecord = true; //Will dictate if we are recording.
            audioRecord.startRecording();
            byte[] buffer = new byte[minBufferSize * 2];
            while (doRecord) {
                int bytesWritten = audioRecord.read(buffer, 0, buffer.length);
                try {
                    audioStream.write(buffer, 0, bytesWritten);
                } catch (IOException e) {
                    //You can log if you like, or simply ignore it
                   stopRecording();
                }
            }
            //cleanup
            audioRecord.stop();
            audioRecord.release();
        }

        public void stopRecording() {
            doRecord = false;
        }
    }

Marshmallowユーザーのみが特定のアクセスを許可する許可クールなもののほとんどではない場合。

クラスを実装してみて、どのようになったかをお知らせください。さらに調査が必要になった場合に備えて、追加の参照を残しています。

がんばろう。

AudioRecord API

AudioCaputre API

MediaRecorder API

0
Joel