Skip to content

Commit

Permalink
fix audio route for Android & iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Piasy committed Feb 20, 2025
1 parent 7cfcaf8 commit 82c9ab5
Show file tree
Hide file tree
Showing 16 changed files with 187 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
Expand All @@ -27,12 +26,12 @@
import java.util.List;

import com.piasy.kmp.webrtc.AndroidPrivateConfig;
import com.piasy.kmp.webrtc.IceCandidate;
import com.piasy.kmp.webrtc.data.IceCandidate;
import com.piasy.kmp.webrtc.PeerConnectionClient;
import com.piasy.kmp.webrtc.PeerConnectionClientCallback;
import com.piasy.kmp.webrtc.PeerConnectionClientFactory;
import com.piasy.kmp.webrtc.RtcStatsReport;
import com.piasy.kmp.webrtc.SessionDescription;
import com.piasy.kmp.webrtc.data.RtcStatsReport;
import com.piasy.kmp.webrtc.data.SessionDescription;
import com.piasy.kmp.xlog.Logging;

import kotlin.Unit;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.piasy.kmp.webrtc

import android.content.Context
import android.media.AudioManager
import com.piasy.avconf.audio.AppRTCAudioManager
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.BLUETOOTH
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.EARPIECE
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.SPEAKER_PHONE
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.WIRED_HEADSET

/**
* Created by Piasy{github.com/Piasy} on 2019-11-27.
*/
class AndroidAudioDeviceManager(private val context: Context, speakerPhoneMode: SpeakerphoneMode) :
AudioDeviceManager {
private val audioManager = AppRTCAudioManager.create(context, speakerphoneMode(speakerPhoneMode))
private var speakerOn = false

private fun speakerphoneMode(mode: SpeakerphoneMode) = when (mode) {
SpeakerphoneMode.AUTO -> AppRTCAudioManager.SPEAKERPHONE_AUTO
SpeakerphoneMode.OPEN -> AppRTCAudioManager.SPEAKERPHONE_TRUE
SpeakerphoneMode.CLOSE -> AppRTCAudioManager.SPEAKERPHONE_FALSE
}

override fun setSpeakerphoneOn(speakerOn: Boolean) {
this.speakerOn = speakerOn
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
if (!audioManager.isWiredHeadsetOn) {
audioManager.isSpeakerphoneOn = speakerOn
}
}

override fun start(callback: AudioDeviceManagerCallback) {
audioManager.start { selectedAudioDevice, _ ->
when (selectedAudioDevice) {
SPEAKER_PHONE -> {
setSpeakerphoneOn(speakerOn)
callback.onAudioDeviceChanged(AudioDevice.SPEAKER_PHONE)
}

WIRED_HEADSET -> callback.onAudioDeviceChanged(AudioDevice.WIRED_HEADSET)
EARPIECE -> callback.onAudioDeviceChanged(AudioDevice.EARPIECE)
BLUETOOTH -> callback.onAudioDeviceChanged(AudioDevice.BLUETOOTH)
else -> callback.onAudioDeviceChanged(AudioDevice.NONE)
}
}
audioManager.changeAudioRoute(true)
if (audioManager.selectedAudioDevice == SPEAKER_PHONE) {
setSpeakerphoneOn(true)
}
}

override fun stop() {
audioManager.stop()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.piasy.kmp.webrtc

import com.piasy.kmp.webrtc.data.IceCandidate
import com.piasy.kmp.webrtc.data.IceServer
import com.piasy.kmp.webrtc.data.RtcStats
import com.piasy.kmp.webrtc.data.RtcStatsReport
import com.piasy.kmp.webrtc.data.SessionDescription
import org.webrtc.PeerConnection
import org.webrtc.PeerConnection.TlsCertPolicy
import org.webrtc.PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ data class AndroidPrivateConfig(
) : PeerConnectionClientFactory.PrivateConfig()

class AndroidPeerConnectionClientFactory(
private val config: Config,
config: Config,
errorHandler: (Int, String) -> Unit,
appContext: Context,
private val privateConfig: AndroidPrivateConfig,
private val errorHandler: (Int, String) -> Unit,
) : PeerConnectionClientFactory(), DefaultLifecycleObserver {
) : PeerConnectionClientFactory(config, errorHandler, AndroidAudioDeviceManager(appContext, SpeakerphoneMode.AUTO)),
DefaultLifecycleObserver {
init {
privateConfig.lifecycle.addObserver(this)
}
Expand Down Expand Up @@ -124,6 +126,7 @@ class AndroidPeerConnectionClientFactory(
}

override fun destroyPeerConnectionFactory() {
super.destroyPeerConnectionFactory()
com.piasy.avconf.PeerConnectionClient.destroyPeerConnectionFactory()
}

Expand Down Expand Up @@ -255,14 +258,15 @@ actual fun createPeerConnectionClientFactory(
config: PeerConnectionClientFactory.Config,
errorHandler: (Int, String) -> Unit,
): PeerConnectionClientFactory {
val appContext = AndroidPeerConnectionClientFactory.sAppContext!!
val privateConfig = config.privateConfig as AndroidPrivateConfig
com.piasy.avconf.PeerConnectionClient.createPeerConnectionFactory(
AndroidPeerConnectionClientFactory.sAppContext!!,
appContext,
privateConfig.rootEglBase,
privateConfig.options,
privateConfig.recordSamplesReadyCallback,
privateConfig.trackSamplesReadyCallback,
privateConfig.enableH264HighProfile,
)
return AndroidPeerConnectionClientFactory(config, privateConfig, errorHandler)
return AndroidPeerConnectionClientFactory(config, errorHandler, appContext, privateConfig)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.piasy.kmp.webrtc

import WebRTC.*
import com.piasy.kmp.webrtc.AudioDevice.BLUETOOTH
import com.piasy.kmp.webrtc.AudioDevice.EARPIECE
import com.piasy.kmp.webrtc.AudioDevice.NONE
import com.piasy.kmp.webrtc.AudioDevice.SPEAKER_PHONE
import com.piasy.kmp.webrtc.AudioDevice.WIRED_HEADSET
import platform.darwin.NSObject

/**
* Created by Piasy{github.com/Piasy} on 2019-11-30.
*/
private class ObjCAudioDeviceManagerCallback(private val realCallback: AudioDeviceManagerCallback) :
CFAudioDeviceManagerDelegateProtocol, NSObject() {
override fun onAudioDeviceChanged(audioDevice: CFAudioDevice) {
realCallback.onAudioDeviceChanged(
when (audioDevice) {
CFAudioDevice.CF_SPEAKER_PHONE -> SPEAKER_PHONE
CFAudioDevice.CF_WIRED_HEADSET -> WIRED_HEADSET
CFAudioDevice.CF_EARPIECE -> EARPIECE
CFAudioDevice.CF_BLUETOOTH -> BLUETOOTH
else -> NONE
}
)
}
}

class IOSAudioDeviceManager : AudioDeviceManager {
private val realManager = CFAudioDeviceManager()

override fun setSpeakerphoneOn(speakerOn: Boolean) {
realManager.setSpeakerphoneOn(speakerOn)
}

override fun start(callback: AudioDeviceManagerCallback) {
realManager.start(ObjCAudioDeviceManagerCallback(callback))
}

override fun stop() {
realManager.stop()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import WebRTC.*
import WebRTC.RTCSdpType.RTCSdpTypeAnswer
import WebRTC.RTCSdpType.RTCSdpTypeOffer
import WebRTC.RTCSdpType.RTCSdpTypePrAnswer
import com.piasy.kmp.webrtc.data.IceCandidate
import com.piasy.kmp.webrtc.data.IceServer
import com.piasy.kmp.webrtc.data.RtcStats
import com.piasy.kmp.webrtc.data.RtcStatsReport
import com.piasy.kmp.webrtc.data.SessionDescription
import platform.darwin.NSObject
import kotlin.native.ref.WeakReference

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.piasy.kmp.webrtc

import WebRTC.*
import com.piasy.kmp.webrtc.utils.FieldTrial
import com.piasy.kmp.xlog.Logging
import com.piasy.kmp.xlog.initializeMarsXLog

Expand All @@ -12,9 +13,9 @@ data class ObjCPrivateConfig(
) : PeerConnectionClientFactory.PrivateConfig()

class ObjCPeerConnectionClientFactory(
private val config: Config,
private val errorHandler: (Int, String) -> Unit,
) : PeerConnectionClientFactory() {
config: Config,
errorHandler: (Int, String) -> Unit,
) : PeerConnectionClientFactory(config, errorHandler, IOSAudioDeviceManager()) {
private var cameraCapturer: RTCCameraVideoCapturer? = null
private var cameraCaptureController: CFCaptureController? = null
private var screenCapturer: CFRPCapturer? = null
Expand Down Expand Up @@ -99,6 +100,7 @@ class ObjCPeerConnectionClientFactory(
}

override fun destroyPeerConnectionFactory() {
super.destroyPeerConnectionFactory()
CFPeerConnectionClient.destroyPeerConnectionFactory()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.piasy.kmp.webrtc

/**
* Created by Piasy{github.com/Piasy} on 2019-11-27.
*/
interface AudioDeviceManager {
fun setSpeakerphoneOn(speakerOn: Boolean)

fun start(callback: AudioDeviceManagerCallback)

fun stop()
}

enum class AudioDevice {
SPEAKER_PHONE,
WIRED_HEADSET,
EARPIECE,
BLUETOOTH,
NONE,
}

enum class SpeakerphoneMode {
AUTO,
OPEN,
CLOSE,
}

interface AudioDeviceManagerCallback {
fun onAudioDeviceChanged(device: AudioDevice)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.piasy.kmp.webrtc

import com.piasy.kmp.webrtc.data.IceCandidate
import com.piasy.kmp.webrtc.data.IceServer
import com.piasy.kmp.webrtc.data.RtcStatsReport
import com.piasy.kmp.webrtc.data.SessionDescription

/**
* Created by Piasy{github.com/Piasy} on 2019-11-26.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import com.piasy.kmp.xlog.Logging
/**
* Created by Piasy{github.com/Piasy} on 2025-02-16.
*/
abstract class PeerConnectionClientFactory {
abstract class PeerConnectionClientFactory(
protected val config: Config,
protected val errorHandler: (Int, String) -> Unit,
private val audioDeviceManager: AudioDeviceManager,
) {
data class Config(
val videoCaptureImpl: Int,
val videoCaptureWidth: Int,
Expand All @@ -29,6 +33,14 @@ abstract class PeerConnectionClientFactory {

open class PrivateConfig

init {
audioDeviceManager.start(object : AudioDeviceManagerCallback {
override fun onAudioDeviceChanged(device: AudioDevice) {
// do nothing now
}
})
}

abstract fun createPeerConnectionClient(
peerUid: String,
dir: Int,
Expand All @@ -46,13 +58,19 @@ abstract class PeerConnectionClientFactory {
abstract fun stopVideoCapture()
abstract fun switchCamera(onFinished: (Boolean) -> Unit)

fun toggleSpeaker(speakerOn: Boolean) {
audioDeviceManager.setSpeakerphoneOn(speakerOn)
}

abstract fun adaptVideoOutputFormat(
width: Int,
height: Int,
fps: Int
)

abstract fun destroyPeerConnectionFactory()
open fun destroyPeerConnectionFactory() {
audioDeviceManager.stop()
}

protected fun logI(content: String) {
Logging.info("$TAG@${hashCode()}", content)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.data

/**
* Created by Piasy{github.com/Piasy} on 2019-11-17.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.data

/**
* Created by Piasy{github.com/Piasy} on 2019-11-17.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.data

import kotlinx.serialization.Serializable

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.data

/**
* Created by Piasy{github.com/Piasy} on 2019-11-17.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.utils

internal object FieldTrial {
fun fieldTrialsStringToMap(fieldTrials: String): Map<Any?, *> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.piasy.kmp.webrtc
package com.piasy.kmp.webrtc.utils

import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down

0 comments on commit 82c9ab5

Please sign in to comment.