pedroSG94/RootEncoder

Select audio source

Closed this issue · 8 comments

Hi,

I am looking for ways to select the audio source, if possible independent of the video source. I searched the previous issues maybe these 2 qualify #1139 #782 , sorry if it's discussed someplace else that I missed.

What I tried:

I have a custom
class FlexibleMicrophoneSource( var audioSource: Int = MediaRecorder.AudioSource.CAMCORDER ): AudioSource(), GetMicrophoneData { private val microphone = MicrophoneManager(this) microphone.setPreferredDevice(preferredDevice)
I am checking the available devices from AudioManager and I chose the Bluetooth one. AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> { preferredDevice = device

I figured this might be the hardest to connect. But it could also be USB, or HDMI. So far I was able to use the phone mic when USB is connected, but when HDMI is connected it takes priority. (Yes, I have a device with USB and HDMI ports).

When I tried the code above to get the mic from the Bluetooth headphones (that I have paired with my phone and is used as default mic/sound) nothing happened and the sound source was the phone mic.

I also tried with MediaRecorder.AudioSource.MIC, DEFAULT, VOICE_COMMUNICATION

Hello,

If you want use bluetooth microphone or other audio source you can try use setPreferedDevice method in MicrophoneSource:

    val audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
    val devices = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)
    //check the list and select the device required
    val deviceSelected = ....
    (genericStream.audioSource as MicrophoneSource).setPreferredDevice(deviceSelected)
    //set null value to reset to default value
    (genericStream.audioSource as MicrophoneSource).setPreferredDevice(null)

Other possible solution is connect the device using bluetooth android API and the microphone should switch atumatically to that device:
https://stackoverflow.com/questions/33757491/android-recording-audio-from-bluetooth-headset-sometimes-records-from-the-mic
Maybe you need do it before start the audio source.

Thanks. This doesn't seem to work. I've tried in various ways, but basically this would be it: I left some comments there.

val audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
val devices = audioManager?.getDevices(AudioManager.GET_DEVICES_INPUTS)
audioManager?.mode = AudioManager.MODE_NORMAL
audioManager?.setBluetoothScoOn(true);
devices?.mapNotNull { device ->
    log.d("Type: ${device.getType()}")
    log.d("Product Name: ${device.getProductName()}")
    when (device.type) {
        AudioDeviceInfo.TYPE_BUILTIN_MIC -> "Built-in Microphone"
        AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> {
            log.d("micsource ${micSource.audioSource} ..,. ${micSource.preferredDevice?.type}")
            val source = rtmpStream.audioSource as MicrophoneSource
//                        source.audioSource = MediaRecorder.AudioSource.CAMCORDER
            source.setPreferredDevice(device)
//                        changeAudioSource(if (config.with_audio) phoneMicSource else NoAudioSource())
        }
        else -> null
    }
}

If I move that block of code into the AudioDeviceInfo.TYPE_BUILTIN_MIC case it works just fine - for the built in mic

Maybe this could work. I'm not sure:

    val audioManager = context?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
    audioManager?.let {
      it.mode = AudioManager.MODE_IN_COMMUNICATION
      it.isBluetoothScoOn = true
      it.startBluetoothSco()
      val source = MicrophoneSource(audioSource = MediaRecorder.AudioSource.VOICE_COMMUNICATION)
      source.setPreferredDevice(device)
      rtmpStream.changeAudioSource(source)
    }

This is really confuse because in internet I can find multiple ways to do it but anyone is working for now.
If you are using a special device try to use a normal phone to test for now.

Yeah I'll try, thanks. Exactly, nothing really works properly. Is it possible it's an app device owner thing? I am looking at recorder apps for instance. All the ones I have tried do not record from the Bluetooth, only the phone mic. All except the Google Recorder app that is. It's the only one that gives you the choice to record from the connected Bluetooth.

And I'm wondering if this is still happening and it's why the HDMI takes precedence: https://stackoverflow.com/questions/11077161/android-audiorecord-headphones-with-mic.

All in all, the point is that I have a list of the cameras connected to the phone, and I'd love to have a list of connected audio sources and be able to use whichever combination.

Hi Pedro,

So :)

This is what worked for me

          val audioManager: AudioManager = context.getSystemService<AudioManager>(
                AudioManager::class.java
            )
            var speakerDevice: AudioDeviceInfo? = null
            val devices: List<AudioDeviceInfo> = audioManager.availableCommunicationDevices
            for (device in devices) {
                if (device.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
                    speakerDevice = device
                    break
                }
            }
            if (speakerDevice != null) {
                val result = audioManager.setCommunicationDevice(speakerDevice)
                if (result) {
                    audioManager.let {
                        it.mode = AudioManager.MODE_IN_COMMUNICATION
                        val btSource =
                            MicrophoneSource(MediaRecorder.AudioSource.CAMCORDER)
                        btSource.noiseSuppressor=true
                        btSource.echoCanceler=true
                        btSource.isStereo=false
                        btSource.setPreferredDevice(speakerDevice)
                        changeAudioSource(btSource)
                    }
                }
            }

There are some interesting (read annoying) caveats to this.

  • commenting out //btSource.isStereo=false (the default) : it will go to the phone mic. So it needs to be mono.

  • the most annoying was this scenario though: comment \\btSource.isStereo=false and \\changeAudioSource(btSource) and it works from Bluetooth.
    So no need to set the audioSource? Are there more conclusions that you can take from this? Basically in this scenario setCommunicationDevice takes care of everything. This is how I understand it.

Also it.startBluetoothSco() is deprecated and in order for the replacement: setCommunicationDevice() to work they need to go

 //     it.isBluetoothScoOn = true
 //     it.startBluetoothSco()

Finally AudioManager.MODE_IN_COMMUNICATION is the default so unless it's kept for clarity reasons it can be removed too.

Hello,

I'm glad that all is working for you now. Thank you for share your conclusions, this could help to future users.

  • the most annoying was this scenario though: comment \\btSource.isStereo=false and \\changeAudioSource(btSource) and it works from Bluetooth.
    So no need to set the audioSource? Are there more conclusions that you can take from this? Basically in this scenario setCommunicationDevice takes care of everything. This is how I understand it.

About this, this could be because StreamBase use Camera2Source and MicrophoneSource by default so it make sense for me.

Thanks, yeah that makes sense then :)