Skip to content

Commit 82c9ab5

Browse files
committed
fix audio route for Android & iOS
1 parent 7cfcaf8 commit 82c9ab5

File tree

16 files changed

+187
-20
lines changed

16 files changed

+187
-20
lines changed

example/androidApp/src/main/java/com/piasy/kmp/webrtc/android/CallActivity.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.content.Context;
44
import android.content.Intent;
5-
import android.content.res.AssetManager;
65
import android.os.Bundle;
76
import android.os.Handler;
87
import android.os.HandlerThread;
@@ -27,12 +26,12 @@
2726
import java.util.List;
2827

2928
import com.piasy.kmp.webrtc.AndroidPrivateConfig;
30-
import com.piasy.kmp.webrtc.IceCandidate;
29+
import com.piasy.kmp.webrtc.data.IceCandidate;
3130
import com.piasy.kmp.webrtc.PeerConnectionClient;
3231
import com.piasy.kmp.webrtc.PeerConnectionClientCallback;
3332
import com.piasy.kmp.webrtc.PeerConnectionClientFactory;
34-
import com.piasy.kmp.webrtc.RtcStatsReport;
35-
import com.piasy.kmp.webrtc.SessionDescription;
33+
import com.piasy.kmp.webrtc.data.RtcStatsReport;
34+
import com.piasy.kmp.webrtc.data.SessionDescription;
3635
import com.piasy.kmp.xlog.Logging;
3736

3837
import kotlin.Unit;
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.piasy.kmp.webrtc
2+
3+
import android.content.Context
4+
import android.media.AudioManager
5+
import com.piasy.avconf.audio.AppRTCAudioManager
6+
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.BLUETOOTH
7+
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.EARPIECE
8+
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.SPEAKER_PHONE
9+
import com.piasy.avconf.audio.AppRTCAudioManager.AudioDevice.WIRED_HEADSET
10+
11+
/**
12+
* Created by Piasy{github.com/Piasy} on 2019-11-27.
13+
*/
14+
class AndroidAudioDeviceManager(private val context: Context, speakerPhoneMode: SpeakerphoneMode) :
15+
AudioDeviceManager {
16+
private val audioManager = AppRTCAudioManager.create(context, speakerphoneMode(speakerPhoneMode))
17+
private var speakerOn = false
18+
19+
private fun speakerphoneMode(mode: SpeakerphoneMode) = when (mode) {
20+
SpeakerphoneMode.AUTO -> AppRTCAudioManager.SPEAKERPHONE_AUTO
21+
SpeakerphoneMode.OPEN -> AppRTCAudioManager.SPEAKERPHONE_TRUE
22+
SpeakerphoneMode.CLOSE -> AppRTCAudioManager.SPEAKERPHONE_FALSE
23+
}
24+
25+
override fun setSpeakerphoneOn(speakerOn: Boolean) {
26+
this.speakerOn = speakerOn
27+
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
28+
if (!audioManager.isWiredHeadsetOn) {
29+
audioManager.isSpeakerphoneOn = speakerOn
30+
}
31+
}
32+
33+
override fun start(callback: AudioDeviceManagerCallback) {
34+
audioManager.start { selectedAudioDevice, _ ->
35+
when (selectedAudioDevice) {
36+
SPEAKER_PHONE -> {
37+
setSpeakerphoneOn(speakerOn)
38+
callback.onAudioDeviceChanged(AudioDevice.SPEAKER_PHONE)
39+
}
40+
41+
WIRED_HEADSET -> callback.onAudioDeviceChanged(AudioDevice.WIRED_HEADSET)
42+
EARPIECE -> callback.onAudioDeviceChanged(AudioDevice.EARPIECE)
43+
BLUETOOTH -> callback.onAudioDeviceChanged(AudioDevice.BLUETOOTH)
44+
else -> callback.onAudioDeviceChanged(AudioDevice.NONE)
45+
}
46+
}
47+
audioManager.changeAudioRoute(true)
48+
if (audioManager.selectedAudioDevice == SPEAKER_PHONE) {
49+
setSpeakerphoneOn(true)
50+
}
51+
}
52+
53+
override fun stop() {
54+
audioManager.stop()
55+
}
56+
}

kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClient.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.piasy.kmp.webrtc
22

3+
import com.piasy.kmp.webrtc.data.IceCandidate
4+
import com.piasy.kmp.webrtc.data.IceServer
5+
import com.piasy.kmp.webrtc.data.RtcStats
6+
import com.piasy.kmp.webrtc.data.RtcStatsReport
7+
import com.piasy.kmp.webrtc.data.SessionDescription
38
import org.webrtc.PeerConnection
49
import org.webrtc.PeerConnection.TlsCertPolicy
510
import org.webrtc.PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK

kmp-webrtc/src/androidMain/kotlin/com/piasy/kmp/webrtc/AndroidPeerConnectionClientFactory.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@ data class AndroidPrivateConfig(
2727
) : PeerConnectionClientFactory.PrivateConfig()
2828

2929
class AndroidPeerConnectionClientFactory(
30-
private val config: Config,
30+
config: Config,
31+
errorHandler: (Int, String) -> Unit,
32+
appContext: Context,
3133
private val privateConfig: AndroidPrivateConfig,
32-
private val errorHandler: (Int, String) -> Unit,
33-
) : PeerConnectionClientFactory(), DefaultLifecycleObserver {
34+
) : PeerConnectionClientFactory(config, errorHandler, AndroidAudioDeviceManager(appContext, SpeakerphoneMode.AUTO)),
35+
DefaultLifecycleObserver {
3436
init {
3537
privateConfig.lifecycle.addObserver(this)
3638
}
@@ -124,6 +126,7 @@ class AndroidPeerConnectionClientFactory(
124126
}
125127

126128
override fun destroyPeerConnectionFactory() {
129+
super.destroyPeerConnectionFactory()
127130
com.piasy.avconf.PeerConnectionClient.destroyPeerConnectionFactory()
128131
}
129132

@@ -255,14 +258,15 @@ actual fun createPeerConnectionClientFactory(
255258
config: PeerConnectionClientFactory.Config,
256259
errorHandler: (Int, String) -> Unit,
257260
): PeerConnectionClientFactory {
261+
val appContext = AndroidPeerConnectionClientFactory.sAppContext!!
258262
val privateConfig = config.privateConfig as AndroidPrivateConfig
259263
com.piasy.avconf.PeerConnectionClient.createPeerConnectionFactory(
260-
AndroidPeerConnectionClientFactory.sAppContext!!,
264+
appContext,
261265
privateConfig.rootEglBase,
262266
privateConfig.options,
263267
privateConfig.recordSamplesReadyCallback,
264268
privateConfig.trackSamplesReadyCallback,
265269
privateConfig.enableH264HighProfile,
266270
)
267-
return AndroidPeerConnectionClientFactory(config, privateConfig, errorHandler)
271+
return AndroidPeerConnectionClientFactory(config, errorHandler, appContext, privateConfig)
268272
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.piasy.kmp.webrtc
2+
3+
import WebRTC.*
4+
import com.piasy.kmp.webrtc.AudioDevice.BLUETOOTH
5+
import com.piasy.kmp.webrtc.AudioDevice.EARPIECE
6+
import com.piasy.kmp.webrtc.AudioDevice.NONE
7+
import com.piasy.kmp.webrtc.AudioDevice.SPEAKER_PHONE
8+
import com.piasy.kmp.webrtc.AudioDevice.WIRED_HEADSET
9+
import platform.darwin.NSObject
10+
11+
/**
12+
* Created by Piasy{github.com/Piasy} on 2019-11-30.
13+
*/
14+
private class ObjCAudioDeviceManagerCallback(private val realCallback: AudioDeviceManagerCallback) :
15+
CFAudioDeviceManagerDelegateProtocol, NSObject() {
16+
override fun onAudioDeviceChanged(audioDevice: CFAudioDevice) {
17+
realCallback.onAudioDeviceChanged(
18+
when (audioDevice) {
19+
CFAudioDevice.CF_SPEAKER_PHONE -> SPEAKER_PHONE
20+
CFAudioDevice.CF_WIRED_HEADSET -> WIRED_HEADSET
21+
CFAudioDevice.CF_EARPIECE -> EARPIECE
22+
CFAudioDevice.CF_BLUETOOTH -> BLUETOOTH
23+
else -> NONE
24+
}
25+
)
26+
}
27+
}
28+
29+
class IOSAudioDeviceManager : AudioDeviceManager {
30+
private val realManager = CFAudioDeviceManager()
31+
32+
override fun setSpeakerphoneOn(speakerOn: Boolean) {
33+
realManager.setSpeakerphoneOn(speakerOn)
34+
}
35+
36+
override fun start(callback: AudioDeviceManagerCallback) {
37+
realManager.start(ObjCAudioDeviceManagerCallback(callback))
38+
}
39+
40+
override fun stop() {
41+
realManager.stop()
42+
}
43+
}

kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClient.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import WebRTC.*
44
import WebRTC.RTCSdpType.RTCSdpTypeAnswer
55
import WebRTC.RTCSdpType.RTCSdpTypeOffer
66
import WebRTC.RTCSdpType.RTCSdpTypePrAnswer
7+
import com.piasy.kmp.webrtc.data.IceCandidate
8+
import com.piasy.kmp.webrtc.data.IceServer
9+
import com.piasy.kmp.webrtc.data.RtcStats
10+
import com.piasy.kmp.webrtc.data.RtcStatsReport
11+
import com.piasy.kmp.webrtc.data.SessionDescription
712
import platform.darwin.NSObject
813
import kotlin.native.ref.WeakReference
914

kmp-webrtc/src/appleMain/kotlin/com/piasy/kmp/webrtc/ObjCPeerConnectionClientFactory.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.piasy.kmp.webrtc
22

33
import WebRTC.*
4+
import com.piasy.kmp.webrtc.utils.FieldTrial
45
import com.piasy.kmp.xlog.Logging
56
import com.piasy.kmp.xlog.initializeMarsXLog
67

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

1415
class ObjCPeerConnectionClientFactory(
15-
private val config: Config,
16-
private val errorHandler: (Int, String) -> Unit,
17-
) : PeerConnectionClientFactory() {
16+
config: Config,
17+
errorHandler: (Int, String) -> Unit,
18+
) : PeerConnectionClientFactory(config, errorHandler, IOSAudioDeviceManager()) {
1819
private var cameraCapturer: RTCCameraVideoCapturer? = null
1920
private var cameraCaptureController: CFCaptureController? = null
2021
private var screenCapturer: CFRPCapturer? = null
@@ -99,6 +100,7 @@ class ObjCPeerConnectionClientFactory(
99100
}
100101

101102
override fun destroyPeerConnectionFactory() {
103+
super.destroyPeerConnectionFactory()
102104
CFPeerConnectionClient.destroyPeerConnectionFactory()
103105
}
104106
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.piasy.kmp.webrtc
2+
3+
/**
4+
* Created by Piasy{github.com/Piasy} on 2019-11-27.
5+
*/
6+
interface AudioDeviceManager {
7+
fun setSpeakerphoneOn(speakerOn: Boolean)
8+
9+
fun start(callback: AudioDeviceManagerCallback)
10+
11+
fun stop()
12+
}
13+
14+
enum class AudioDevice {
15+
SPEAKER_PHONE,
16+
WIRED_HEADSET,
17+
EARPIECE,
18+
BLUETOOTH,
19+
NONE,
20+
}
21+
22+
enum class SpeakerphoneMode {
23+
AUTO,
24+
OPEN,
25+
CLOSE,
26+
}
27+
28+
interface AudioDeviceManagerCallback {
29+
fun onAudioDeviceChanged(device: AudioDevice)
30+
}

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClient.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.piasy.kmp.webrtc
22

3+
import com.piasy.kmp.webrtc.data.IceCandidate
4+
import com.piasy.kmp.webrtc.data.IceServer
5+
import com.piasy.kmp.webrtc.data.RtcStatsReport
6+
import com.piasy.kmp.webrtc.data.SessionDescription
7+
38
/**
49
* Created by Piasy{github.com/Piasy} on 2019-11-26.
510
*/

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/PeerConnectionClientFactory.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import com.piasy.kmp.xlog.Logging
55
/**
66
* Created by Piasy{github.com/Piasy} on 2025-02-16.
77
*/
8-
abstract class PeerConnectionClientFactory {
8+
abstract class PeerConnectionClientFactory(
9+
protected val config: Config,
10+
protected val errorHandler: (Int, String) -> Unit,
11+
private val audioDeviceManager: AudioDeviceManager,
12+
) {
913
data class Config(
1014
val videoCaptureImpl: Int,
1115
val videoCaptureWidth: Int,
@@ -29,6 +33,14 @@ abstract class PeerConnectionClientFactory {
2933

3034
open class PrivateConfig
3135

36+
init {
37+
audioDeviceManager.start(object : AudioDeviceManagerCallback {
38+
override fun onAudioDeviceChanged(device: AudioDevice) {
39+
// do nothing now
40+
}
41+
})
42+
}
43+
3244
abstract fun createPeerConnectionClient(
3345
peerUid: String,
3446
dir: Int,
@@ -46,13 +58,19 @@ abstract class PeerConnectionClientFactory {
4658
abstract fun stopVideoCapture()
4759
abstract fun switchCamera(onFinished: (Boolean) -> Unit)
4860

61+
fun toggleSpeaker(speakerOn: Boolean) {
62+
audioDeviceManager.setSpeakerphoneOn(speakerOn)
63+
}
64+
4965
abstract fun adaptVideoOutputFormat(
5066
width: Int,
5167
height: Int,
5268
fps: Int
5369
)
5470

55-
abstract fun destroyPeerConnectionFactory()
71+
open fun destroyPeerConnectionFactory() {
72+
audioDeviceManager.stop()
73+
}
5674

5775
protected fun logI(content: String) {
5876
Logging.info("$TAG@${hashCode()}", content)

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/IceCandidate.kt renamed to kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/data/IceCandidate.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.data
22

33
/**
44
* Created by Piasy{github.com/Piasy} on 2019-11-17.

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/IceServer.kt renamed to kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/data/IceServer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.data
22

33
/**
44
* Created by Piasy{github.com/Piasy} on 2019-11-17.

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/RtcStatsReport.kt renamed to kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/data/RtcStatsReport.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.data
22

33
import kotlinx.serialization.Serializable
44

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/SessionDescription.kt renamed to kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/data/SessionDescription.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.data
22

33
/**
44
* Created by Piasy{github.com/Piasy} on 2019-11-17.

kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/FieldTrial.kt renamed to kmp-webrtc/src/commonMain/kotlin/com/piasy/kmp/webrtc/utils/FieldTrial.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.utils
22

33
internal object FieldTrial {
44
fun fieldTrialsStringToMap(fieldTrials: String): Map<Any?, *> {

kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/FieldTrialTest.kt renamed to kmp-webrtc/src/commonTest/kotlin/com/piasy/kmp/webrtc/utils/FieldTrialTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.piasy.kmp.webrtc
1+
package com.piasy.kmp.webrtc.utils
22

33
import kotlin.test.Test
44
import kotlin.test.assertEquals

0 commit comments

Comments
 (0)