Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
xuning
/
livekitAndroidXuningTest
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
David Liu
2021-03-07 20:49:59 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
eb75cbff6103be6ad41d385518f0cbdbfab1b0d4
eb75cbff
1 parent
915be490
DI and more fleshing out audio
隐藏空白字符变更
内嵌
并排对比
正在显示
10 个修改的文件
包含
319 行增加
和
15 行删除
livekit-android-sdk/build.gradle
livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt
livekit-android-sdk/src/main/java/io/livekit/android/dagger/JsonFormatModule.kt
livekit-android-sdk/src/main/java/io/livekit/android/dagger/LiveKitComponent.kt
livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt
livekit-android-sdk/src/main/java/io/livekit/android/dagger/WebModule.kt
livekit-android-sdk/src/main/java/io/livekit/android/room/PublisherTransportObserver.kt
livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt
livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt
livekit-android-sdk/src/main/java/io/livekit/android/room/track/Track.kt
livekit-android-sdk/build.gradle
查看文件 @
eb75cbf
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android'
apply
plugin:
'kotlin-kapt'
apply
plugin:
'kotlinx-serialization'
apply
plugin:
'com.google.protobuf'
...
...
@@ -34,6 +35,9 @@ android {
sourceCompatibility
java_version
targetCompatibility
java_version
}
kotlinOptions
{
freeCompilerArgs
=
[
"-Xinline-classes"
]
}
}
protobuf
{
...
...
@@ -60,12 +64,12 @@ dependencies {
implementation
"com.google.protobuf:protobuf-java:${versions.protobuf}"
implementation
"com.google.protobuf:protobuf-java-util:${versions.protobuf}"
implementation
'com.google.dagger:dagger:2.32'
annotationProcessor
'com.google.dagger:dagger-compiler:2.32'
implementation
'com.google.dagger:dagger:2.33'
kapt
'com.google.dagger:dagger-compiler:2.33'
implementation
'com.github.ajalt:timberkt:1.5.1'
testImplementation
'junit:junit:4.12'
androidTestImplementation
'androidx.test.ext:junit:1.1.2'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.3.0'
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/LiveKit.kt
查看文件 @
eb75cbf
package io.livekit.android
import android.content.Context
import io.livekit.android.dagger.DaggerLiveKitComponent
class LiveKit {
suspend fun connect(
url: String,
token: String,
options: ConnectOptions?){
companion object {
suspend fun connect(
appContext: Context,
url: String,
token: String,
options: ConnectOptions
) {
val component = DaggerLiveKitComponent
.factory()
.create(appContext)
val room = component.roomFactory()
.create(options)
room.connect(url, token, false)
}
}
}
...
...
livekit-android-sdk/src/main/java/io/livekit/android/dagger/JsonFormatModule.kt
0 → 100644
查看文件 @
eb75cbf
package io.livekit.android.dagger
import com.google.protobuf.util.JsonFormat
import dagger.Module
import dagger.Provides
@Module
class JsonFormatModule {
companion object {
@Provides
fun jsonFormatParser(): JsonFormat.Parser {
return JsonFormat.parser()
}
@Provides
fun jsonFormatPrinter(): JsonFormat.Printer {
return JsonFormat.printer()
}
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/dagger/LiveKitComponent.kt
0 → 100644
查看文件 @
eb75cbf
package io.livekit.android.dagger
import android.content.Context
import dagger.BindsInstance
import dagger.Component
import io.livekit.android.room.Room
import javax.inject.Singleton
@Singleton
@Component(
modules = [
RTCModule::class,
WebModule::class,
JsonFormatModule::class,
]
)
interface LiveKitComponent {
fun roomFactory(): Room.Factory
@Component.Factory
interface Factory {
fun create(@BindsInstance appContext: Context): LiveKitComponent
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/dagger/RTCModule.kt
0 → 100644
查看文件 @
eb75cbf
package io.livekit.android.dagger
import android.content.Context
import com.github.ajalt.timberkt.Timber
import dagger.Module
import dagger.Provides
import org.webrtc.PeerConnectionFactory
import org.webrtc.audio.AudioDeviceModule
import org.webrtc.audio.JavaAudioDeviceModule
import javax.inject.Singleton
@Module
class RTCModule {
companion object {
@Provides
@Singleton
fun audioModule(appContext: Context): AudioDeviceModule {
// Set audio record error callbacks.
val audioRecordErrorCallback = object : JavaAudioDeviceModule.AudioRecordErrorCallback {
override fun onWebRtcAudioRecordInitError(errorMessage: String?) {
Timber.e { "onWebRtcAudioRecordInitError: $errorMessage" }
}
override fun onWebRtcAudioRecordStartError(
errorCode: JavaAudioDeviceModule.AudioRecordStartErrorCode?,
errorMessage: String?
) {
Timber.e { "onWebRtcAudioRecordStartError: $errorCode. $errorMessage" }
}
override fun onWebRtcAudioRecordError(errorMessage: String?) {
Timber.e { "onWebRtcAudioRecordError: $errorMessage" }
}
}
val audioTrackErrorCallback = object : JavaAudioDeviceModule.AudioTrackErrorCallback {
override fun onWebRtcAudioTrackInitError(errorMessage: String?) {
Timber.e { "onWebRtcAudioTrackInitError: $errorMessage" }
}
override fun onWebRtcAudioTrackStartError(
errorCode: JavaAudioDeviceModule.AudioTrackStartErrorCode?,
errorMessage: String?
) {
Timber.e { "onWebRtcAudioTrackStartError: $errorCode. $errorMessage" }
}
override fun onWebRtcAudioTrackError(errorMessage: String?) {
Timber.e { "onWebRtcAudioTrackError: $errorMessage" }
}
}
val audioRecordStateCallback: JavaAudioDeviceModule.AudioRecordStateCallback = object :
JavaAudioDeviceModule.AudioRecordStateCallback {
override fun onWebRtcAudioRecordStart() {
Timber.i { "Audio recording starts" }
}
override fun onWebRtcAudioRecordStop() {
Timber.i { "Audio recording stops" }
}
}
// Set audio track state callbacks.
val audioTrackStateCallback: JavaAudioDeviceModule.AudioTrackStateCallback = object :
JavaAudioDeviceModule.AudioTrackStateCallback {
override fun onWebRtcAudioTrackStart() {
Timber.i { "Audio playout starts" }
}
override fun onWebRtcAudioTrackStop() {
Timber.i { "Audio playout stops" }
}
}
return JavaAudioDeviceModule.builder(appContext)
.setUseHardwareAcousticEchoCanceler(true)
.setUseHardwareNoiseSuppressor(true)
.setAudioRecordErrorCallback(audioRecordErrorCallback)
.setAudioTrackErrorCallback(audioTrackErrorCallback)
.setAudioRecordStateCallback(audioRecordStateCallback)
.setAudioTrackStateCallback(audioTrackStateCallback)
.createAudioDeviceModule()
}
@Provides
@Singleton
fun peerConnectionFactory(
appContext: Context,
audioDeviceModule: AudioDeviceModule
): PeerConnectionFactory {
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions.builder(appContext)
.createInitializationOptions()
)
return PeerConnectionFactory.builder()
.setAudioDeviceModule(audioDeviceModule)
.createPeerConnectionFactory()
}
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/dagger/WebModule.kt
0 → 100644
查看文件 @
eb75cbf
package io.livekit.android.dagger
import dagger.Module
import dagger.Provides
import okhttp3.OkHttpClient
import okhttp3.WebSocket
import javax.inject.Singleton
@Module
class WebModule {
companion object {
@Provides
@Singleton
fun okHttpClient(): OkHttpClient {
return OkHttpClient()
}
@Provides
fun websocketFactory(okHttpClient: OkHttpClient): WebSocket.Factory {
return okHttpClient
}
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/room/PublisherTransportObserver.kt
查看文件 @
eb75cbf
...
...
@@ -7,8 +7,8 @@ class PublisherTransportObserver(
private val engine: RTCEngine
) : PeerConnection.Observer {
override fun onIceCandidate(candidate: IceCandidate?) {
val candidate = candidate ?: return
override fun onIceCandidate(iceCandidate: IceCandidate?) {
val candidate = iceCandidate ?: return
if (engine.rtcConnected) {
engine.client.sendCandidate(candidate, target = Rtc.SignalTarget.PUBLISHER)
} else {
...
...
@@ -21,10 +21,10 @@ class PublisherTransportObserver(
}
override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState?) {
val newState = newState ?: throw NullPointerException("unexpected null new state, what do?")
if (newState == PeerConnection.IceConnectionState.CONNECTED && !engine.iceConnected) {
val state = newState ?: throw NullPointerException("unexpected null new state, what do?")
if (state == PeerConnection.IceConnectionState.CONNECTED && !engine.iceConnected) {
engine.iceConnected = true
} else if (
newS
tate == PeerConnection.IceConnectionState.DISCONNECTED) {
} else if (
s
tate == PeerConnection.IceConnectionState.DISCONNECTED) {
engine.iceConnected = false
engine.listener?.onDisconnect("Peer connection disconnected")
}
...
...
livekit-android-sdk/src/main/java/io/livekit/android/room/RTCEngine.kt
查看文件 @
eb75cbf
package io.livekit.android.room
import android.content.Context
import io.livekit.android.room.track.Track
import livekit.Model
import livekit.Rtc
import org.webrtc.*
import javax.inject.Inject
import kotlin.coroutines.Continuation
class RTCEngine
@Inject
constructor(
private val appContext: Context,
val client: RTCClient,
pctFactory: PeerConnectionTransport.Factory,
) {
)
: RTCClient.Listener
{
var listener: Listener? = null
var rtcConnected: Boolean = false
...
...
@@ -24,12 +29,16 @@ constructor(
}
}
val pendingCandidates = mutableListOf<IceCandidate>()
private val pendingTrackResolvers: MutableMap<Track.Cid, Continuation<Model.TrackInfo>> =
mutableMapOf()
private val publisherObserver = PublisherTransportObserver(this)
private val subscriberObserver = SubscriberTransportObserver(this)
private val publisher: PeerConnectionTransport
private val subscriber: PeerConnectionTransport
private var privateDataChannel: DataChannel
init {
val rtcConfig = PeerConnection.RTCConfiguration(RTCClient.DEFAULT_ICE_SERVERS).apply {
sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN
...
...
@@ -38,7 +47,12 @@ constructor(
publisher = pctFactory.create(rtcConfig, publisherObserver)
subscriber = pctFactory.create(rtcConfig, subscriberObserver)
client.listener = this
privateDataChannel = publisher.peerConnection.createDataChannel(
PRIVATE_DATA_CHANNEL_LABEL,
DataChannel.Init()
)
}
suspend fun join(url: String, token: String, isSecure: Boolean) {
...
...
@@ -59,4 +73,40 @@ constructor(
fun onDisconnect(reason: String)
fun onFailToConnect(error: Error)
}
companion object {
private const val PRIVATE_DATA_CHANNEL_LABEL = "_private"
}
override fun onJoin(info: Rtc.JoinResponse) {
TODO("Not yet implemented")
}
override fun onAnswer(sessionDescription: SessionDescription) {
TODO("Not yet implemented")
}
override fun onOffer(sessionDescription: SessionDescription) {
TODO("Not yet implemented")
}
override fun onTrickle(candidate: IceCandidate, target: Rtc.SignalTarget) {
TODO("Not yet implemented")
}
override fun onLocalTrackPublished(trackPublished: Rtc.TrackPublishedResponse) {
TODO("Not yet implemented")
}
override fun onParticipantUpdate(updates: List<Model.ParticipantInfo>) {
TODO("Not yet implemented")
}
override fun onClose(reason: String, code: Int) {
TODO("Not yet implemented")
}
override fun onError(error: Error) {
TODO("Not yet implemented")
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/room/Room.kt
查看文件 @
eb75cbf
package io.livekit.android.room
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import io.livekit.android.ConnectOptions
class Room
@AssistedInject
constructor(
private val connectOptions: ConnectOptions,
@Assisted private val engine: RTCEngine,
@Assisted private val connectOptions: ConnectOptions,
private val engine: RTCEngine,
) {
suspend fun connect(url: String, token: String, isSecure: Boolean) {
engine.join(url, token, isSecure)
}
@AssistedFactory
interface Factory {
fun create(connectOptions: ConnectOptions): Room
}
}
\ No newline at end of file
...
...
livekit-android-sdk/src/main/java/io/livekit/android/room/track/Track.kt
0 → 100644
查看文件 @
eb75cbf
package io.livekit.android.room.track
import org.webrtc.DataChannel
import org.webrtc.MediaStreamTrack
class Track(name: String, state: State) {
var name = name
internal set
var state = state
internal set
inline class Sid(val sid: String)
inline class Cid(val cid: String)
enum class Priority {
STANDARD, HIGH, LOW;
}
enum class State {
ENDED, LIVE, NONE;
}
companion object {
fun stateFromRTCMediaTrackState(trackState: MediaStreamTrack.State): State {
return when (trackState) {
MediaStreamTrack.State.ENDED -> State.ENDED
MediaStreamTrack.State.LIVE -> State.LIVE
}
}
fun stateFromRTCDataChannelState(dataChannelState: DataChannel.State): State {
return when (dataChannelState) {
DataChannel.State.CONNECTING,
DataChannel.State.OPEN -> {
State.LIVE
}
DataChannel.State.CLOSING,
DataChannel.State.CLOSED -> {
State.ENDED
}
}
}
}
}
sealed class TrackException(message: String?, cause: Throwable?) : Exception(message, cause) {
class InvalidTrackTypeException(message: String?, cause: Throwable?) :
TrackException(message, cause)
class DuplicateTrackException(message: String?, cause: Throwable?) :
TrackException(message, cause)
class InvalidTrackStateException(message: String?, cause: Throwable?) :
TrackException(message, cause)
class MediaException(message: String?, cause: Throwable?) : TrackException(message, cause)
class PublishException(message: String?, cause: Throwable?) : TrackException(message, cause)
}
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论