source

Android AudioRecord가 다른 스트림을 MIC 오디오 소스로 강제 전송

factcode 2022. 9. 11. 17:09
반응형

Android AudioRecord가 다른 스트림을 MIC 오디오 소스로 강제 전송

업데이트 3: 저는 다른 개발자와 파트너 관계를 맺고 있으며, 큰 금액으로 이 작업을 수행할 수 있는 사람을 찾은 것 같습니다.그들은 우리에게 테스트 apk를 보냈고 그것은 효과가 있는 것 같습니다.소스를 구입하겠습니다.나는 우리가 사기를 당하지 않기를 바란다.알게 되면 업데이트하겠습니다.

업데이트 2: 아직 진행 중입니다.좀 더 고통스러워진 날들이 지나고 나니, 지금은 별 볼일 없는 것 같지만, AudioFlinger(링크 참조)를 네이티브 측에서 사용하여 AudioFlinger를 호출하고 있습니다:setParameters

Audio Flinger를 호출하기 위해 간단한 JNI를 쓰는 방법을 찾고 있습니다: setParameters with audio_io_handle_t ioHandle, cst String8 & key ValuePairs

keyValuePairs는 알 수 있지만 audio_io_handle_t에 대한 단서는 알 수 없습니다.

업데이트: 다른 앱이 CAF에서 QCOM 오디오를 사용하고 있을 수 있습니다.링크의 audio_extn_utils_send_audio_calibration을 참조하십시오.

링크의 voice_get_incall_rec_snd_device는 동일하다.

저는 C/+에 대한 지식이 없습니다.이 메서드를 네이티브 측에서 호출할 수 있는지 어떻게 알 수 있습니까?다른 앱도 가능하니까 방법이 있을 거예요.


적어도 하루에 5~6시간씩 40일 넘게 이 문제로 고생하고 있어요.SO가 허락하는지는 모르겠지만 정답을 위해 기부를 하게 되어 기쁩니다.

VOICE_CALL 오디오 소스를 사용하는 통화 녹음 앱이 있습니다.ASOP에서는 실장/의무가 없지만, 대부분의 제조원은 VOICE_CALL을 실장하고 있어 VOICE_CALL 오디오소스를 사용하는 어플리케이션은 많은 디바이스에서 정상적으로 동작합니다.안드로이드6까지입니다.

구글은 안드로이드6에서 이 동작을 바꿨다.VOICE_CALL 오디오 소스를 열려면 안드로이드가 필요합니다.허가.CAPTURE_AUDIO_OUTPUT. 시스템응용 프로그램에만 부여됩니다.

이것에 의해, 기본적으로 콜 녹음이 정지됩니다.그렇지 않으면 정지합니다.이 제한에서 벗어날 수 있는 방법을 찾은 3명을 제외한 저와 200명 이상의 다른 통화 녹음 앱에도 해당됩니다.

Android 6를 탑재한 여러 폰에서 이 앱을 사용해 본 결과, 녹음이 가능한 특징을 알 수 있었습니다.

모두 Android Audio Record 클래스와 오픈 MIC 오디오 소스를 사용합니다.저도 그렇지만, 제 앱에서는, 상대방이 아닌 MIC로부터만 오디오를 들을 수 있습니다.내가 알아낸 것은 그들이 녹음을 시작한 직후 또는 시작하기 전에 일종의 시스템 호출을 발행하고 있다는 것이다.

VOICE_CALL이 MIC를 사용하여 녹음하는 경우에도 VOICE_CALL을 정상적으로 녹음하는 어플리케이션 중 하나에서 다음 로그를 확인하십시오.MIC에 VOICE_CALL 오디오 소스를 믹스/루팅/스트림/머지하는 방법이 앱인 것 같습니다.

- 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;mic=-2147483644로 시작합니다.

그리고 두 번째 줄에서 뭔가를 하고 안드로이드를 부여받습니다.허가.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, 오디오 라우팅이 헤드셋을 통해 오디오를 강제하고 있는 것을 발견했습니다.그것은 현재의 AudioRecord 세션에 어떻게 mix/route/stream/merge VOICE_CALL이 포함되어 있는지 생각했기 때문에 (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();
    }

}

분명히 녹음을 가능하게 하는 뭔가 놓치고 있는 것이 있습니다.

심지어 이 정보를 얻기 위해 돈을 주겠다고 제안했지만, 모두 거절했어요.좋아, 내가 말한 대로야.한 번 출판할 거야/찾으면!

그들이 뭘 하고 있을지 짐작 가는 거라도 있나요?

나와 내 파트너는 우리가 찾고 있던 것을 살 수 있었다.올바른 경로로 진행 중이었고, 네이티브 측에서 keyValuePairs를 설정했습니다.

유감스럽게도 소스를 작성한 회사의 라이센스 제한으로 인해 소스를 공개할 수 없습니다.

이치노나는 몇 가지 작은 프로젝트와 관련된 일을 했다.AudioRecordAPI. 다음 정보가 도움이 되었으면 합니다.

예를 들어 다음과 같이 셋업합니다.AudioRecord16kHz의 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;
        }
    }

Mashimallow 사용자는 거의 모든 멋진 사용자가 아니더라도 특정 권한에 접근할 수 있는 유일한 사용자이기 때문에 동일한 권한을 유지할 필요가 있다고 생각합니다.

수업을 실시해 보고, 어떻게 되었는지 알려 주세요.또한 더 많은 연구가 필요할 경우를 대비해서 참고 자료를 남깁니다.

행운을 빌어요.

AudioRecord API

AudioCaputre API

MediaRecorder API

언급URL : https://stackoverflow.com/questions/37080374/android-audiorecord-forcing-another-stream-to-mic-audio-source

반응형