听众模式_in_communication降低了声音质量并引起crack啪作响/弹出声音

发布于 2025-02-09 20:48:46 字数 5166 浏览 0 评论 0原文

问题的描述:

当应用程序通过蓝牙耳机连接时,我正在启动audiomanager.startbluetoothsco()。您可以检查下面的代码。该连接效果很好,但是我对MediaPlayer播放的crack啪声有疑问。每当播放动作声音时,质量不好或crack啪作响的声音就会发生。 (例如r.raw.record_start,r.raw.success_action,r.raw.failure_action)

我用来测试的设备:

  • Aftershokx和Jabra Evolve 65
  • ,Samsung A50

Samsung A52,Samsung A50,Samsung A50 VE尝试了吗?

  1. 我尝试将audiomanager.mode = audiomanager.mode_in_communication更改为audiomanager.mode_in_call或audiomanager.mode_normal。
  • 更改为Mode_in_call不会更改audiomanager.mode。该值保持为0,是sode_normal。
  1. 更改为Mode_normal仅在Samsung A52上起作用。没有crack啪声听起来一切正常。这就是我要实现的目标,
  • 但是所有其他手机都切换到其他流或其他东西。这就是为什么我听不到任何媒体声音的原因。
  • 假设我使用像素3,并与jabra在sode_normal中相连的65。我再也听不到任何类型的媒体声音,包括YouTube,Spotify和System Sounds等其他应用程序,但它可以在Mode_in_communication和Crackling Sound中起作用。
  1. 我试图更改MediaPlayer的AudioAttributes,但质量仍然不好。

      val actionsound = if(triggerErrorearcon)r.raw.failure_action else if(longRecorDingbreak)r.raw.success_action else r.raw.record_start
    Val MD = MediaPlayer.Create(上下文,Actionsound)
    val streamType = if(audiodevicemanager.headsetconnected)audiomanager.stream_voice_call
    MD.SetaudioAttributes(
            AudioAttributes.builder()
                .setlegacystreamtype(streamType)
                .setContentType(AudioAttributes.Content_Type_music)
                。建造())
    md.play()
     

可能的解决方案?

  • 我不知道如何修复audiomanager.mode或AudoManager的其他某些属性。
  • 继续使用Mode_in_communication,但可以解决MediaPlayer属性的修复,以禁用蓝牙设备上的声音质量不佳。
  • 从这一点开始,我什么也没想到。希望您能帮助我解决这个问题,谢谢。

AudiodeviceManager.kt:

class AudioDeviceManager(val context: Context) {
    internal val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    internal val headsetConnectedSubject = BehaviorSubject.createDefault(false)
    internal val headsetConnected: Boolean get() = headsetConnectedSubject.value ?: false
    private val intentFilter = IntentFilter().apply { addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) }
    private val audioDeviceCallback = object: AudioDeviceCallback() {
        override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesAdded(addedDevices)
            updateBluetoothHeadsetState()
        }

        override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesRemoved(removedDevices)
            updateBluetoothHeadsetState()
        }
    }
    private val scoReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
                // SCO now connected
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
                audioManager.isSpeakerphoneOn = false
                audioManager.isBluetoothScoOn = true
            }
        }
    }

    fun start() {
        if (headsetConnected.not())
            audioManager.registerAudioDeviceCallback(audioDeviceCallback, null)
    }

    fun stop(unregisterAudioDeviceCallback: Boolean = false) {
        if (unregisterAudioDeviceCallback)
            unregisterDeviceCallback()
        audioManager.mode = AudioManager.MODE_NORMAL
        audioManager.isSpeakerphoneOn = true
        audioManager.isBluetoothScoOn = false
        audioManager.stopBluetoothSco()
    }

    private fun unregisterDeviceCallback() = audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)

    fun updateBluetoothHeadsetState() {
        val headset = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)?.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
        val headsetConnected = headset != null
        headsetConnectedSubject.onNext(headsetConnected)

        if (headsetConnected) {
            audioManager.startBluetoothSco()
            context.registerReceiver(scoReceiver, intentFilter)
        } else {
            audioManager.mode = AudioManager.MODE_NORMAL
            audioManager.isSpeakerphoneOn = true
            audioManager.isBluetoothScoOn = false
            audioManager.stopBluetoothSco()
        }
    }
}

在应用程序中播放动作声音:

 MediaPlayer.create(context, R.raw.record_start)
            .play()
            .subscribe()
            .addTo(disposable)

扩展功能:

fun MediaPlayer.play(): Completable {
    return Completable.create { emitter ->

        var isCancelled = false
        emitter.setCancellable {
            isCancelled = true
        }
        setOnCompletionListener {
            GlobalScope.launch {
                // release the sound a bit later. Listener is triggering so fast!
                delay(3000)
                it.release()
            }
            if (isCancelled) { return@setOnCompletionListener }
            emitter.onComplete()
        }
        start()
    }
}

Description of the problem:

When the app is connected through Bluetooth headsets, I'm starting the audioManager.startBluetoothSco(). You can check the code below. The connection works well, but I have a problem with the crackling sounds that are played by MediaPlayer. Whenever an action sound is played, the quality is bad or a crackling sound happens. (eg. R.raw.record_start, R.raw.success_action, R.raw.failure_action)

Devices that I used to test:

  • OpenComm by AfterShokx and Jabra Evolve 65
  • Samsung A52, Samsung A50, Pixel 3, OnePlus 6 Pro

What I've tried so far?

  1. I tried to change audioManager.mode = AudioManager.MODE_IN_COMMUNICATION to AudioManager.MODE_IN_CALL or AudioManager.MODE_NORMAL.
  • Changing to MODE_IN_CALL doesn't change the audioManager.mode. The value stays as 0 which is MODE_NORMAL.
  1. Changing to MODE_NORMAL only works on Samsung A52. No crackling sounds everything works perfectly. This is what I want to achieve,
  • BUT all other phones switch to a different stream or something else; that's why I can't HEAR any media sounds.
  • Let's say I use Pixel 3 and connected with Jabra Evolve 65 in MODE_NORMAL. I can't hear any kind of media sounds anymore including other apps like Youtube, Spotify, and system sounds, but it works in MODE_IN_COMMUNICATION with a crackling sound.
  1. I tried to change MediaPlayer's AudioAttributes but still bad quality.

    val actionSound = if (triggerErrorEarcon) R.raw.failure_action else if (longRecordingBreak) R.raw.success_action else R.raw.record_start
    val md = MediaPlayer.create(context, actionSound)
    val streamType = if (audioDeviceManager.headsetConnected) AudioManager.STREAM_VOICE_CALL else AudioManager.STREAM_MUSIC
    md.setAudioAttributes(
            AudioAttributes.Builder()
                .setLegacyStreamType(streamType)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build())
    md.play()
    

Possible Solutions?

  • I don't know how but fixing audioManager.mode or some other properties of audioManager.
  • Keep using MODE_IN_COMMUNICATION but a fix on MediaPlayer properties to disable bad quality of sound on Bluetooth device.
  • I can't think of anything else from this point. I hope you could help me with this problem, thanks in advance.

AudioDeviceManager.kt:

class AudioDeviceManager(val context: Context) {
    internal val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    internal val headsetConnectedSubject = BehaviorSubject.createDefault(false)
    internal val headsetConnected: Boolean get() = headsetConnectedSubject.value ?: false
    private val intentFilter = IntentFilter().apply { addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED) }
    private val audioDeviceCallback = object: AudioDeviceCallback() {
        override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesAdded(addedDevices)
            updateBluetoothHeadsetState()
        }

        override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>?) {
            super.onAudioDevicesRemoved(removedDevices)
            updateBluetoothHeadsetState()
        }
    }
    private val scoReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1) == AudioManager.SCO_AUDIO_STATE_CONNECTED) {
                // SCO now connected
                audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
                audioManager.isSpeakerphoneOn = false
                audioManager.isBluetoothScoOn = true
            }
        }
    }

    fun start() {
        if (headsetConnected.not())
            audioManager.registerAudioDeviceCallback(audioDeviceCallback, null)
    }

    fun stop(unregisterAudioDeviceCallback: Boolean = false) {
        if (unregisterAudioDeviceCallback)
            unregisterDeviceCallback()
        audioManager.mode = AudioManager.MODE_NORMAL
        audioManager.isSpeakerphoneOn = true
        audioManager.isBluetoothScoOn = false
        audioManager.stopBluetoothSco()
    }

    private fun unregisterDeviceCallback() = audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)

    fun updateBluetoothHeadsetState() {
        val headset = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)?.firstOrNull { it.type == AudioDeviceInfo.TYPE_BLUETOOTH_SCO }
        val headsetConnected = headset != null
        headsetConnectedSubject.onNext(headsetConnected)

        if (headsetConnected) {
            audioManager.startBluetoothSco()
            context.registerReceiver(scoReceiver, intentFilter)
        } else {
            audioManager.mode = AudioManager.MODE_NORMAL
            audioManager.isSpeakerphoneOn = true
            audioManager.isBluetoothScoOn = false
            audioManager.stopBluetoothSco()
        }
    }
}

Playing an action sound in the app:

 MediaPlayer.create(context, R.raw.record_start)
            .play()
            .subscribe()
            .addTo(disposable)

Extension function:

fun MediaPlayer.play(): Completable {
    return Completable.create { emitter ->

        var isCancelled = false
        emitter.setCancellable {
            isCancelled = true
        }
        setOnCompletionListener {
            GlobalScope.launch {
                // release the sound a bit later. Listener is triggering so fast!
                delay(3000)
                it.release()
            }
            if (isCancelled) { return@setOnCompletionListener }
            emitter.onComplete()
        }
        start()
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文