Android AudioRecord başka bir akışı MIC ses kaynağına zorlar


82

Güncelleme 3: Başka bir geliştiriciyle ortaklık kurdum ve bunu büyük miktarda parayla yapabilecek birini bulduk. Bize bir test apk gönderdiler ve çalışıyor gibi görünüyor. Biz devam edip kaynağı satın alacağız. Umarım dolandırılmayız. Öğrendiğimde güncelleyeceğim

Güncelleme 2: Hala üzerinde çalışıyoruz. Daha sancılı günlerden sonra artık fantezi bir şey olmadığını düşünüyorum ama onlar sadece AudioFlinger :: setParameters'ı çağırmak için yerel tarafta AudioFlinger'ı ( bağlantıya bakın ) kullanıyorlar.

AudioFlinger :: setParameters'ı audio_io_handle_t ioHandle, const String8 & keyValuePairs ile çağırmak için nasıl basit bir JNI yazabileceğimi şimdi arıyorum.

KeyValuePairs'in ne olabileceğini biliyorum ama audio_io_handle_t hakkında bir ipucu değil

Güncelleme: Şimdi diğer uygulamaların CAF ile QCOM sesini kullanıyor olabileceğine inanıyorum. Aynı bağlantıda audio_extn_utils_send_audio_calibration'a bakın

ve voice_get_incall_rec_snd_device aynı bağlantıda

C / ++ bilgim yok. Bu yöntemleri yerel taraftan çağırıp çağıramayacağımı nasıl öğrenebilirim? Diğer uygulamalar yapabildiğinden, bir yolu olmalı.


40 günden fazla süredir bununla günde en az 5-6 saat uğraşıyorum. SO tarafından buna izin verilip verilmediğinden emin değilim, ancak doğru yanıt için bağış yapmaktan da mutluyum.

VOICE_CALL ses kaynağı kullanan bir çağrı kaydetme uygulamam var. ASOP bunu uygulamasa / zorunlu kılmasa da, çoğu üretici VOICE_CALL uygulamıştır ve VOICE_CALL ses kaynağı kullanan uygulamalar birçok cihazda iyi çalıştı. Bu Android 6'ya kadar.

Google bu davranışı Android 6 ile değiştirdi. VOICE_CALL ses kaynağının açılması artık android.permission.CAPTURE_AUDIO_OUTPUT gerektiriyor ve bu sadece sistem uygulamalarına veriliyor.

Bu, esasen arama kaydını durdurur, yoksa olmalıydı. Benimki ve bu sınırlamayı aşmanın bir yolunu bulan 3 dışında diğer 200'den fazla arama kayıt uygulaması için geçerli.

Bu uygulamaları Android 6 ile birçok farklı telefonda deniyor ve kaydetmeyi başardıkları şekilde belirli özellikleri buldum.

Hepsi Android AudioRecord sınıfını kullanır ve MIC ses kaynağını açar. Ben de yaptım; ancak uygulamamda, diğer taraftan değil, yalnızca MIC'den ses alıyorum. Öğrendiğim şey, kayda başlamadan hemen sonra veya hemen önce bir tür sistem çağrısı yaptıklarını söylüyor.

Kayıt için MIC kullanmasına rağmen VOICE_CALL'u başarıyla kaydeden uygulamalardan biri olan aşağıdaki günlük formuna bir göz atın. Görünüşe göre uygulama, VOICE_CALL ses kaynağını MIC'e karıştırmayı / yönlendirmeyi / aktarmayı / birleştirmeyi nasıl yönetiyor.

- 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)

İlk satırda görebileceğiniz gibi, MIC ses kaynağı input_source = 1 ile başlıyor; yönlendirme = -2147483644.

Ardından, ikinci satırda bir şey yapar ve normal izin olan android.permission.MODIFY_AUDIO_SETTINGS verilir ve uygulamam da buna sahiptir. Bu en önemli kısım gibi görünüyor ve görünüşe göre 3'ü de VOICE_CALL ses kaynağının MIC'ye akışını / birleştirilmesini tetiklemek ve standart AudioRecorder API ile kayıt yapmak için yaptıkları her şeyi yapmak için JNI kullanıyor.

Sonraki satırda, MIC (1) ses kaynağını açmış olsalar bile ses donanımının VOICE_CALL (input_source = 4) karıştırmaya başladığını görüyorsunuz.

Kullandıklarını varsaydım

AudioManager.setParameters("key=value")

ve birçok varyasyon denedi.

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

şanssız.

Ardından, Android, NDK, Ses yönlendirme, kulaklıktan ses zorlama buldum ve VOICE_CALL'u mevcut AudioRecord oturumuna nasıl karıştırır / yönlendirir / yayınlar / birleştirir ve (C bilgisine sahip olmadığım için) reflasyonu kullanmayı denedim aynı şeyi aşağıdaki kodla (tekrar) şanssız başarmak.

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

}

Açıkçası, kaydetmeyi mümkün kılan bir şey eksik.

Bu bilgiyi almak için ödeme yapmayı bile teklif ettim, hepsi reddetti. Yeterince adil dedim. Bir kez yayınlayacağım / bulursam!

Ne yaptıkları konusunda bir fikriniz var mı?


bunu başarılı bir şekilde yapan uygulamaları bağlayabilir misiniz?
roarster


Sonuncuyu iki kez gönderdin.
shmosel


1
bir göz atabilmek için derlemeyi çözmeyi denediniz mi? (sadece araştırma amaçlı;))
Buda Gavril

Yanıtlar:


9

Ben ve partnerim aradığımızı satın alabildik. Doğru yoldaydık, yerel tarafta keyValuePairs'i ayarladınız.

Maalesef bizim için yazmış olduğumuz şirketten gelen lisans kısıtlamaları nedeniyle kaynağı yayınlayamıyorum


3
Bir kişinin hatası, başka bir kişinin özelliğidir.
Elwin Arens

7
ya haklısın nLL ACR, çözümü paylaşamıyorsa neden bu stackoverflow topluluğunu kullanıyor? Bunun toplulukların ana nedenine tamamen aykırı olduğunu düşünüyorum. Söz veriyorum eğer çözümü alırsam, açık kaynağa inandığım için çözümü hemen göndereceğim.
japanjot singh

2
@japanjotsingh, birlikte çözüm bulalım
Peter

3
@nLL Kulağa kaba geliyor olabilirim ama kardeşim bu hepimiz için çok sinir bozucu :-(
japanjot singh

2
CallRecLib, Android 6'da telefon konuşmalarını kaydetmek için bir hack sağlayan bir kütüphanedir github.com/ViktorDegtyarev/CallRecLib
Viktor Degtyarev

0

Bulgularınız ilginç. AudioRecordAPI ile ilgili birkaç küçük proje üzerinde çalıştım . Umarım aşağıdakiler yardımcı olur:

AudioRecord16 kHz'de 16-bit mono kayıt yapabilmek için bir örnek kurmak istediğinizi varsayalım. Bunu, aşağıdaki gibi birkaç yardımcı yöntemle bir sınıf oluşturarak başarabilirsiniz:

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

Bize belirli izinlere erişim izni veren tek kişi Marshmallow kullanıcıları olduğundan , aynı izinleri yerinde tutmanız gerekeceğini tahmin ediyorum. , havalı olanların neredeyse tamamı olmasa da, kişilerdir.

Sınıfı uygulamayı deneyin ve nasıl gittiğini bize bildirin, ayrıca daha fazla araştırmaya ihtiyaç duymanız durumunda bazı ekstra referanslar bırakıyorum.

İyi şanslar.

AudioRecord API

AudioCaputre API

MediaRecorder API


1
Hayır, maalesef bunun sorumla ilgisi yok. Zaten AudioReocord sınıfını kullanıyorum ve onunla yoğun bir şekilde çalıştım.
nLL

bu problemi çözdün mü? Gerçekten çalışan bir çözüme ihtiyacım var :-(
Kimse 8
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.