Android Question Select Audio In/Out devices for AudioStreamer

yo3ggx

Active Member
Licensed User
Longtime User
Hello,

Starting with Android 6.0, you can get the available audio input and output devices using AudioDeviceInfo.
I'm using the following inline JAVA code to get the list of audio devices. For each in/out audiodevice device I get the name, id and type.

B4X:
#If JAVA
    import android.media.AudioManager;
    import android.media.AudioDeviceInfo;
    import android.content.Context;
    
    public String[] getAudioInDevicesNames() {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
           AudioDeviceInfo[] adi = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
        String[] s = new String[adi.length];
        for (int i = 0; i < adi.length - 1; i++) {
            s[i] = (String)adi[i].getProductName() + "," + adi[i].getId()  + "," + adi[i].getType();
        }
        return s;
    }

    public String[] getAudioOutDevicesNames() {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
           AudioDeviceInfo[] adi = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        String[] s = new String[adi.length];
        for (int i = 0; i < adi.length - 1; i++) {
            s[i] = (String)adi[i].getProductName() + "," + adi[i].getId()  + "," + adi[i].getType();
        }
        return s;
    }
#End If

How can I set the audio in and audio out devices in AudioStreamer, using setPreferredDevice, available for both AudioRecord and AudioTrack?


Thank you.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
First step is to get the audio devices:
B4X:
Private Sub FindAudioDevices As Map
    Dim ctxt As JavaObject
    ctxt.InitializeContext
    Dim res As Map
    res.Initialize
    Dim devices() As Object = ctxt.RunMethodJO("getSystemService", Array("audio")).RunMethod("getDevices", Array(0x0001)) 'GET_DEVICES_INPUTS
    For Each device As Object In devices
        res.Put(device.As(JavaObject).RunMethod("getType", Null), device)
    Next
    Return res
End Sub

B4X:
Dim devices As Map = FindAudioDevices
Dim r As Reflector
r.Target = AudioStreamer
Dim AudioTrack As JavaObject = r.GetField("track") 'or audioRecord
AudioTrack.RunMethod("setPreferredDevice", Array(devices.Get(18))
Constants: https://developer.android.com/reference/android/media/AudioDeviceInfo
 
Upvote 0

yo3ggx

Active Member
Licensed User
Longtime User
In the mean time I've implement it like that.
B4X:
Sub SetAudioInDevice(audstr As AudioStreamer, idin As Int)

#If JAVA
    import android.media.AudioManager;
    import android.media.AudioDeviceInfo;
    import android.content.Context;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    
    public void setAudioDeviceIn(AudioRecord ar, int idIn) {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
           AudioDeviceInfo[] adi = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS);
        for (int i = 0; i < adi.length - 1; i++) {
            int id = adi[i].getId();
            if (id == idIn) {
                ar.setPreferredDevice(adi[i]);
                break;
            }
        }
    }
#End If
    Dim r As Reflector
    r.Target = audstr
    Dim ao As Object = r.GetField("audioRecord")           
    NativeMe.RunMethod("setAudioDeviceIn",Array As Object(ao,idin))
End Sub

Sub SetAudioOutDevice(audstr As AudioStreamer, idout As Int)

#If JAVA
    import android.media.AudioManager;
    import android.media.AudioDeviceInfo;
    import android.content.Context;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    
    public void setAudioDeviceOut(AudioTrack at, int idOut) {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
           AudioDeviceInfo[] adi = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);

        for (int i = 0; i < adi.length - 1; i++) {
            int id = adi[i].getId();
            if (id == idOut) {
                at.setPreferredDevice(adi[i]);
                break;
            }
        }
    }
    
#End If
    Dim r As Reflector
    r.Target = audstr
    Dim ao As Object = r.GetField("track")
    NativeMe.RunMethod("setAudioDeviceOut",Array As Object(ao,idout))
End Sub

... but I like more your approach.

Anyway, I observed something strange. When I set the audio in or out device using this approach, I cannot select the USB audio device anymore, even a new device is created when USB audio is connected. USB audio is automatically set as default when connected, but as soon as I switch the audio device using the code above, I can select only phone internal audio or Bluetooth audio (A2DP or SCO), but not USB audio.

So, if I want to use USB audio, I keep the STREAM_MUSIC and REC_DEFAULT in AudioStream initialization, without setting the device through the code above. If I want Bluetooth or internal (Earpiece or Speaker), then I set it through the code. I don't know if this is the best approach, but is working for me.
Some other observation is that if I change the device with the code above, volume cannot be changed anymore through the standard Android audio mixer (Media/Alarm/Notification), so I'm, using the following code to set volume:

B4X:
Sub Set_AudioVolume(audstr As AudioStreamer, vol As Int)
    ' volume 0-100
#If JAVA
    import android.media.AudioManager;
    import android.media.AudioDeviceInfo;
    import android.content.Context;
    import android.media.AudioRecord;
    import android.media.AudioTrack;
    
    public void setAudioVolume(AudioTrack at, int vol) {
        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
           AudioDeviceInfo[] adi = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
        at.setVolume(at.getMaxVolume() * vol / 100.0f);
    }
    
#End If
    Dim r As Reflector
    r.Target = audstr
    Dim ao As Object = r.GetField("track")   
    Try
        NativeMe.RunMethod("setAudioVolume",Array As Object(ao,vol))
    Catch
        Log("Cannot set volume")
    End Try
End Sub
 
Upvote 0

yo3ggx

Active Member
Licensed User
Longtime User
Hello,

Do you was able record device output audio? Could you share a piece of code?

tks
Can you detail a little bit what do you want to achieve? I just want to be able to select the audio device I'm recoding from or play to. When you have USB audio connected, this audio channel is the default one if not changed in developer mode. I want to use in my app both USB audio and a Bluetooth headset connected to the smartphone.
 
Upvote 0
Top