Android AudioRecord buộc một luồng khác tới nguồn âm thanh MIC


81

Cập nhật 3: Tôi đã hợp tác với một nhà phát triển khác và chúng tôi dường như đã tìm thấy ai đó có thể làm điều này với một khoản tiền lớn. Họ đã gửi cho chúng tôi một apk thử nghiệm và nó có vẻ hoạt động. Chúng tôi sẽ tiếp tục và mua nguồn. Tôi hy vọng chúng tôi sẽ không bị lừa đảo. Tôi sẽ cập nhật khi tôi phát hiện ra

Cập nhật 2: Vẫn đang làm việc trên nó. Sau những ngày đau khổ hơn, bây giờ tôi nghĩ rằng không có gì thú vị xảy ra nhưng họ chỉ đơn giản là sử dụng AudioFlinger ( Xem liên kết ) ở phía bản địa để gọi AudioFlinger :: setParameters

Tôi hiện đang tìm cách viết một JNI đơn giản để gọi AudioFlinger :: setParameters với audio_io_handle_t ioHandle, const String8 & keyValuePairs

Tôi biết keyValuePairs có thể là gì nhưng không phải manh mối về audio_io_handle_t

Cập nhật: Bây giờ tôi tin rằng các ứng dụng khác có thể đang sử dụng âm thanh QCOM với CAF. Xem audio_extn_utils_send_audio_calibration tại liên kết cho tương tự

và voice_get_incall_rec_snd_device tại liên kết cho cùng một

Tôi không có kiến ​​thức C / ++. Làm cách nào để biết liệu tôi có thể gọi các phương thức này từ phía bản địa hay không? Vì các ứng dụng khác có thể, nên phải có một cách.


Tôi đã vật lộn với điều này hơn 40 ngày trong ít nhất 5-6 giờ mỗi ngày. Tôi không chắc nó có được SO cho phép hay không nhưng tôi cũng rất vui khi đóng góp cho câu trả lời chính xác.

Tôi có ứng dụng ghi âm cuộc gọi sử dụng nguồn âm thanh VOICE_CALL. Mặc dù ASOP không triển khai / bắt buộc nó, hầu hết các nhà sản xuất đã triển khai VOICE_CALL và các ứng dụng sử dụng nguồn âm thanh VOICE_CALL hoạt động tốt trên nhiều thiết bị. Đó là cho đến Android 6.

Google đã thay đổi hành vi này với Android 6. Việc mở nguồn âm thanh VOICE_CALL hiện yêu cầu android.permission.CAPTURE_AUDIO_OUTPUT chỉ được cấp cho các ứng dụng hệ thống.

Điều này về cơ bản dừng ghi âm cuộc gọi, hoặc nó phải có. Chà, nó dành cho tôi và hơn 200 ứng dụng ghi âm cuộc gọi khác ngoài 3 ứng dụng đã tìm ra cách để vượt qua hạn chế này.

Tôi đã thử các ứng dụng đó trên nhiều điện thoại khác nhau với Android 6 và phát hiện ra một số đặc điểm nhất định trong cách chúng quản lý để ghi lại.

Tất cả đều sử dụng lớp AudioRecord của Android và nguồn âm thanh MIC mở. Tôi cũng làm như vậy; nhưng trên ứng dụng của tôi, tôi chỉ nhận được âm thanh từ MIC chứ không phải bên kia. Những gì tôi phát hiện ra đang cho tôi biết rằng họ đang thực hiện một số loại lệnh gọi hệ thống ngay sau hoặc trước khi bắt đầu ghi âm.

Hãy xem biểu mẫu nhật ký sau đây, một trong những ứng dụng ghi thành công VOICE_CALL, mặc dù nó sử dụng MIC để ghi. Có vẻ như ứng dụng là một số cách quản lý để trộn / định tuyến / phát / hợp nhất nguồn âm thanh VOICE_CALL vào 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)

Như bạn có thể thấy ở dòng đầu tiên, nó đang bắt đầu với nguồn âm thanh MIC input_source = 1; routing = -2147483644.

Sau đó, ở dòng thứ hai, nó thực hiện điều gì đó và được cấp android.permission.MODIFY_AUDIO_SETTINGS, đây là quyền bình thường và ứng dụng của tôi cũng có quyền đó. Đây dường như là phần quan trọng nhất và có vẻ như cả 3 đều đang sử dụng JNI để làm những gì họ làm để kích hoạt phát trực tuyến / hợp nhất nguồn âm thanh VOICE_CALL thành MIC và ghi lại bằng API AudioRecorder độc lập

Trên dòng tiếp theo, bạn thấy rằng phần cứng âm thanh bắt đầu trộn VOICE_CALL (input_source = 4) mặc dù chúng đã mở nguồn âm thanh MIC (1).

Tôi đã cho rằng họ đã sử dụng

AudioManager.setParameters("key=value")

và đã thử nhiều biến thể như

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

mà không có bất kỳ may mắn.

Sau đó, tôi đã tìm thấy Android, NDK, Định tuyến âm thanh, buộc âm thanh qua tai nghe và nghĩ rằng chúng có thể là một số cách trộn / định tuyến / luồng / hợp nhất VOICE_CALL vào phiên AudioRecord hiện tại và (vì không có kiến ​​thức C) đã cố gắng sử dụng tái tạo để đạt được điều tương tự với mã dưới đây (một lần nữa) mà không cần may mắn.

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

}

Rõ ràng là có điều gì đó tôi đang thiếu để có thể ghi âm.

Tôi thậm chí đã đề nghị trả tiền để có được thông tin này, tất cả đều bị từ chối. Tôi đã nói đủ công bằng. Tôi sẽ xuất bản nó một lần / nếu tôi tìm thấy nó!

Bạn có bất kỳ ý tưởng nào về những gì họ có thể đang làm không?


bạn có thể liên kết các ứng dụng làm điều đó thành công không?
roarster


Bạn đã đăng bài cuối cùng hai lần.
shmosel


1
bạn đã thử dịch ngược nó để có thể xem qua chưa? (chỉ dành cho mục đích nghiên cứu;))
Buda Gavril

Câu trả lời:


9

Tôi và đối tác của tôi đã có thể mua những gì chúng tôi đang tìm kiếm. Chúng tôi đã đi đúng hướng, bạn đặt keyValuePairs ở phía gốc.

Rất tiếc, tôi không thể xuất bản nguồn vì các hạn chế cấp phép từ công ty mà chúng tôi đã viết nó cho chúng tôi


3
Lỗi của một người là tính năng của người khác.
Elwin Arens

7
ya bạn nói đúng nLL là ACR, Nếu anh ấy không thể chia sẻ giải pháp tại sao anh ấy lại sử dụng cộng đồng stackoverflow này? Tôi nghĩ rằng điều này hoàn toàn chống lại động cơ chính của cộng đồng. Tôi hứa nếu tôi nhận được giải pháp, tôi sẽ đăng giải pháp ngay lập tức vì tôi tin vào mã nguồn mở.
japanjot singh

2
@japanjotsingh hãy cùng nhau tìm ra giải pháp
Peter

3
@nLL Tôi có thể nghe thô lỗ nhưng anh bạn, điều đó rất khó chịu cho tất cả chúng ta :-(
japanjot singh 29/09/17

2
CallRecLib là một thư viện cung cấp một hack để ghi lại cuộc hội thoại điện thoại trên Android 6 github.com/ViktorDegtyarev/CallRecLib
Viktor Degtyarev

0

Phát hiện của bạn rất thú vị. Tôi đã làm việc trên một vài dự án nhỏ liên quan đến AudioRecordAPI. Hy vọng rằng, những điều sau đây sẽ giúp:

Giả sử bạn muốn thiết lập một AudioRecordphiên bản để bạn có thể ghi âm đơn âm 16 bit ở tần số 16kHz. Bạn có thể đạt được điều này bằng cách tạo một lớp với một vài phương thức trợ giúp, như sau:

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

Tôi đoán bạn sẽ cần giữ nguyên các quyền đó, vì người dùng Marshmallow là những người duy nhất cấp cho chúng tôi quyền truy cập vào một số quyền nhất định nếu không phải là hầu hết tất cả các quyền thú vị.

Hãy thử triển khai lớp học và cho chúng tôi biết nó diễn ra như thế nào, tôi cũng để lại một số tài liệu tham khảo bổ sung trong trường hợp bạn cần nghiên cứu thêm.

Chúc may mắn.

API AudioRecord

API AudioCaputre

API MediaRecorder


1
Không, tiếc là điều này không liên quan gì đến câu hỏi của tôi. Tôi đã sử dụng lớp AudioReocord và đã làm việc với nó nhiều.
nLL

bạn đã giải quyết được vấn đề này chưa Tôi thực sự cần một giải pháp hiệu quả :-(
Nobody
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.