davidliu
Committed by GitHub

Add spotless check to CI builds (#270)

* add spotless

* fix some format violations

* kotlin styling

* add spotless check to ci

* Update actions and fix spotless check

* ktlint fixes

* more spotless fixes

* more spotless fixes

* turn off annotation lint

* run spotless check first
正在显示 100 个修改的文件 包含 516 行增加316 行删除

要显示太多修改。

为保证性能只显示 100 of 100+ 个文件。

# https://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
max_line_length = 180
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{java,kt,kts,scala,rs,xml,kt.spec,kts.spec,gradle,md}]
indent_size = 4
[*.{kt,kts}]
ktlint_code_style = android_studio
# default IntelliJ IDEA style, same as alphabetical, but with "java", "javax", "kotlin" and alias imports in the end of the imports list
ij_kotlin_imports_layout = *, java.**, javax.**, kotlin.**, ^
ktlint_standard = enabled
ktlint_standard_annotation = disabled
ktlint_standard_no-wildcard-imports = disabled
ktlint_standard_trailing-comma-on-call-site = disabled
ij_kotlin_allow_trailing_comma_on_call_site = true
ktlint_standard_trailing-comma-on-declaration-site = disabled
ij_kotlin_allow_trailing_comma = true
ktlint_standard_wrapping = disabled
[*.md]
trim_trailing_whitespace = false
max_line_length = unset
[*.yml]
ij_yaml_spaces_within_brackets = false
... ...
... ... @@ -24,18 +24,18 @@ jobs:
working-directory: ./client-sdk-android
steps:
- name: checkout client-sdk-android
uses: actions/checkout@v2.3.4
uses: actions/checkout@v4.0.0
with:
path: ./client-sdk-android
submodules: recursive
- name: set up JDK 12
uses: actions/setup-java@v2
uses: actions/setup-java@v3.12.0
with:
java-version: '12'
distribution: 'adopt'
- uses: actions/cache@v2
- uses: actions/cache@v3.3.2
with:
path: |
~/.gradle/caches
... ... @@ -45,10 +45,19 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Gradle clean
run: ./gradlew clean
- name: Spotless check
if: github.event_name == 'pull_request'
run: |
git fetch origin main --depth 1
./gradlew spotlessCheck
- name: Build with Gradle
run: ./gradlew clean assembleRelease livekit-android-sdk:testRelease
run: ./gradlew assembleRelease livekit-android-sdk:testRelease
# TODO: Figure out appropriate place to run this. Takes ~3 mins, so pretty slow.
# TODO: Figure out appropriate place to run this. Takes ~3 mins, so pretty slow.
# # generates coverage-report.md and publishes as checkrun
# - name: JaCoCo Code Coverage Report
# id: jacoco_reporter
... ...
/*
* Copyright $YEAR LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
... ...
... ... @@ -15,6 +15,7 @@ buildscript {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.19'
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.30.0"
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.5'
classpath "com.diffplug.spotless:spotless-plugin-gradle:6.21.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
... ... @@ -27,6 +28,41 @@ subprojects {
mavenCentral()
maven { url 'https://jitpack.io' }
}
apply plugin: "com.diffplug.spotless"
spotless {
// optional: limit format enforcement to just the files changed by this feature branch
ratchetFrom 'origin/main'
format 'misc', {
// define the files to apply `misc` to
target '*.gradle', '*.md', '.gitignore'
// define the steps to apply to those files
trimTrailingWhitespace()
indentWithSpaces()
endWithNewline()
}
java {
// apply a specific flavor of google-java-format
googleJavaFormat('1.17.0').aosp().reflowLongStrings()
// fix formatting of type annotations
formatAnnotations()
// make sure every file has the following copyright header.
// optionally, Spotless can set copyright years by digging
// through git history (see "license" section below)
licenseHeaderFile rootProject.file("LicenseHeaderFile.txt")
removeUnusedImports()
}
kotlin {
target("src/*/java/**/*.kt")
ktlint("0.50.0")
.setEditorConfigPath("$rootDir/.editorconfig")
licenseHeaderFile(rootProject.file("LicenseHeaderFile.txt"))
.named('license')
endWithNewline()
}
}
}
task clean(type: Delete) {
... ...
... ... @@ -16,14 +16,12 @@
package io.livekit.android
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
... ...
... ... @@ -19,7 +19,6 @@ package io.livekit.android
import io.livekit.android.room.ProtocolVersion
import org.webrtc.PeerConnection
data class ConnectOptions(
/** Auto subscribe to room tracks upon connect, defaults to true */
val autoSubscribe: Boolean = true,
... ...
... ... @@ -122,6 +122,5 @@ class LiveKit {
room.connect(url, token, connectOptions)
return room
}
}
}
... ...
... ... @@ -50,7 +50,6 @@ data class LiveKitOverrides(
val audioOptions: AudioOptions? = null,
)
class AudioOptions(
/**
* Override the default output [AudioType].
... ... @@ -87,7 +86,7 @@ class AudioOptions(
sealed class AudioType(
val audioMode: Int,
val audioAttributes: AudioAttributes,
val audioStreamType: Int
val audioStreamType: Int,
) {
/**
* An audio type for general media playback usage (i.e. listener-only use cases).
... ... @@ -101,7 +100,7 @@ sealed class AudioType(
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.build(),
AudioManager.STREAM_MUSIC
AudioManager.STREAM_MUSIC,
)
/**
... ... @@ -115,7 +114,7 @@ sealed class AudioType(
.setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
.setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
.build(),
AudioManager.STREAM_VOICE_CALL
AudioManager.STREAM_VOICE_CALL,
)
/**
... ...
... ... @@ -106,7 +106,7 @@ constructor(context: Context) : AudioHandler {
AudioAttributes.Builder()
.setUsage(audioAttributeUsageType)
.setContentType(audioAttributeContentType)
.build()
.build(),
)
.build()
}
... ...
... ... @@ -150,14 +150,14 @@ constructor(private val context: Context) : AudioHandler {
context = context,
loggingEnabled = loggingEnabled,
audioFocusChangeListener = onAudioFocusChangeListener ?: defaultOnAudioFocusChangeListener,
preferredDeviceList = preferredDeviceList ?: defaultPreferredDeviceList
preferredDeviceList = preferredDeviceList ?: defaultPreferredDeviceList,
)
} else {
LegacyAudioSwitch(
context = context,
loggingEnabled = loggingEnabled,
audioFocusChangeListener = onAudioFocusChangeListener ?: defaultOnAudioFocusChangeListener,
preferredDeviceList = preferredDeviceList ?: defaultPreferredDeviceList
preferredDeviceList = preferredDeviceList ?: defaultPreferredDeviceList,
)
}
switch.manageAudioFocus = manageAudioFocus
... ... @@ -214,7 +214,7 @@ constructor(private val context: Context) : AudioHandler {
AudioDevice.BluetoothHeadset::class.java,
AudioDevice.WiredHeadset::class.java,
AudioDevice.Earpiece::class.java,
AudioDevice.Speakerphone::class.java
AudioDevice.Speakerphone::class.java,
)
}
}
... ...
... ... @@ -37,7 +37,6 @@ fun VideoRenderer(
modifier: Modifier = Modifier,
mirror: Boolean = false,
) {
val videoSinkVisibility = remember(room, videoTrack) { ComposeVisibility() }
var boundVideoTrack by remember { mutableStateOf<VideoTrack?>(null) }
var view: TextureViewRenderer? by remember { mutableStateOf(null) }
... ...
... ... @@ -42,7 +42,7 @@ object AudioHandlerModule {
@Provides
fun audioOutputAttributes(
audioType: AudioType
audioType: AudioType,
): AudioAttributes {
return audioType.audioAttributes
}
... ...
... ... @@ -29,7 +29,7 @@ object InjectionNames {
/**
* @see [kotlinx.coroutines.Dispatchers.IO]
*/
internal const val DISPATCHER_IO = "dispatcher_io";
internal const val DISPATCHER_IO = "dispatcher_io"
/**
* @see [kotlinx.coroutines.Dispatchers.Main]
... ...
... ... @@ -32,5 +32,4 @@ object JsonFormatModule {
Json {
ignoreUnknownKeys = true
}
}
... ...
... ... @@ -35,7 +35,7 @@ import javax.inject.Singleton
OverridesModule::class,
AudioHandlerModule::class,
MemoryModule::class,
]
],
)
internal interface LiveKitComponent {
... ... @@ -49,7 +49,7 @@ internal interface LiveKitComponent {
interface Factory {
fun create(
@BindsInstance appContext: Context,
overridesModule: OverridesModule
overridesModule: OverridesModule,
): LiveKitComponent
}
}
... ... @@ -60,7 +60,6 @@ internal fun LiveKitComponent.Factory.create(
): LiveKitComponent {
return create(
appContext = context,
overridesModule = OverridesModule(overrides)
overridesModule = OverridesModule(overrides),
)
}
... ...
... ... @@ -63,5 +63,4 @@ class OverridesModule(private val overrides: LiveKitOverrides) {
@Provides
@Named(InjectionNames.OVERRIDE_AUDIO_OUTPUT_TYPE)
fun audioOutputType() = overrides.audioOptions?.audioOutputType
}
... ...
... ... @@ -53,7 +53,8 @@ object RTCModule {
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions
.builder(appContext)
.setInjectableLogger({ s, severity, s2 ->
.setInjectableLogger(
{ s, severity, s2 ->
if (!LiveKit.enableWebRTCLogging) {
return@setInjectableLogger
}
... ... @@ -69,8 +70,10 @@ object RTCModule {
LKLog.log(loggingLevel) {
Timber.log(loggingLevel.toAndroidLogPriority(), "$s2: $s")
}
}, Logging.Severity.LS_VERBOSE)
.createInitializationOptions()
},
Logging.Severity.LS_VERBOSE,
)
.createInitializationOptions(),
)
return LibWebrtcInitialization
}
... ... @@ -86,7 +89,7 @@ object RTCModule {
@Nullable
moduleCustomizer: ((builder: JavaAudioDeviceModule.Builder) -> Unit)?,
audioOutputAttributes: AudioAttributes,
appContext: Context
appContext: Context,
): AudioDeviceModule {
if (audioDeviceModuleOverride != null) {
return audioDeviceModuleOverride
... ... @@ -100,7 +103,7 @@ object RTCModule {
override fun onWebRtcAudioRecordStartError(
errorCode: JavaAudioDeviceModule.AudioRecordStartErrorCode?,
errorMessage: String?
errorMessage: String?,
) {
LKLog.e { "onWebRtcAudioRecordStartError: $errorCode. $errorMessage" }
}
... ... @@ -117,7 +120,7 @@ object RTCModule {
override fun onWebRtcAudioTrackStartError(
errorCode: JavaAudioDeviceModule.AudioTrackStartErrorCode?,
errorMessage: String?
errorMessage: String?,
) {
LKLog.e { "onWebRtcAudioTrackStartError: $errorCode. $errorMessage" }
}
... ... @@ -125,7 +128,6 @@ object RTCModule {
override fun onWebRtcAudioTrackError(errorMessage: String?) {
LKLog.e { "onWebRtcAudioTrackError: $errorMessage" }
}
}
val audioRecordStateCallback: JavaAudioDeviceModule.AudioRecordStateCallback = object :
JavaAudioDeviceModule.AudioRecordStateCallback {
... ... @@ -168,7 +170,9 @@ object RTCModule {
@Provides
@Singleton
fun eglBase(@Singleton memoryManager: CloseableManager): EglBase {
fun eglBase(
@Singleton memoryManager: CloseableManager,
): EglBase {
val eglBase = EglBase.create()
memoryManager.registerResource(eglBase) { eglBase.release() }
... ... @@ -188,7 +192,7 @@ object RTCModule {
eglContext: EglBase.Context,
@Named(InjectionNames.OVERRIDE_VIDEO_ENCODER_FACTORY)
@Nullable
videoEncoderFactoryOverride: VideoEncoderFactory?
videoEncoderFactoryOverride: VideoEncoderFactory?,
): VideoEncoderFactory {
return videoEncoderFactoryOverride ?: if (videoHwAccel) {
SimulcastVideoEncoderFactoryWrapper(
... ... @@ -211,7 +215,7 @@ object RTCModule {
eglContext: EglBase.Context,
@Named(InjectionNames.OVERRIDE_VIDEO_DECODER_FACTORY)
@Nullable
videoDecoderFactoryOverride: VideoDecoderFactory?
videoDecoderFactoryOverride: VideoDecoderFactory?,
): VideoDecoderFactory {
return videoDecoderFactoryOverride ?: if (videoHwAccel) {
WrappedVideoDecoderFactory(eglContext)
... ...
... ... @@ -39,7 +39,7 @@ object WebModule {
fun okHttpClient(
@Named(InjectionNames.OVERRIDE_OKHTTP)
@Nullable
okHttpClientOverride: OkHttpClient?
okHttpClientOverride: OkHttpClient?,
): OkHttpClient {
OkHttpClient.Builder()
.pingInterval(20, TimeUnit.SECONDS)
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.e2ee
import io.livekit.android.events.RoomEvent
... ... @@ -70,10 +86,12 @@ constructor(keyProvider: KeyProvider) {
LKLog.i { "Receiver::onFrameCryptionStateChanged: $trackId, state: $state" }
emitEvent(
RoomEvent.TrackE2EEStateEvent(
room!!, publication.track!!, publication,
room!!,
publication.track!!,
publication,
participant,
state = e2eeStateFromFrameCryptoState(state)
)
state = e2eeStateFromFrameCryptoState(state),
),
)
}
}
... ... @@ -94,10 +112,12 @@ constructor(keyProvider: KeyProvider) {
LKLog.i { "Sender::onFrameCryptionStateChanged: $trackId, state: $state" }
emitEvent(
RoomEvent.TrackE2EEStateEvent(
room!!, publication.track!!, publication,
room!!,
publication.track!!,
publication,
participant,
state = e2eeStateFromFrameCryptoState(state)
)
state = e2eeStateFromFrameCryptoState(state),
),
)
}
}
... ... @@ -111,18 +131,22 @@ constructor(keyProvider: KeyProvider) {
FrameCryptionState.ENCRYPTIONFAILED -> E2EEState.ENCRYPTION_FAILED
FrameCryptionState.DECRYPTIONFAILED -> E2EEState.DECRYPTION_FAILED
FrameCryptionState.INTERNALERROR -> E2EEState.INTERNAL_ERROR
else -> { E2EEState.INTERNAL_ERROR}
else -> { E2EEState.INTERNAL_ERROR }
}
}
private fun addRtpSender(sender: RtpSender, participantId: String, trackId: String , kind: String): FrameCryptor {
private fun addRtpSender(sender: RtpSender, participantId: String, trackId: String, kind: String): FrameCryptor {
var pid = "$kind-sender-$participantId-$trackId"
var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpSender(
sender, pid, algorithm, keyProvider.rtcKeyProvider)
sender,
pid,
algorithm,
keyProvider.rtcKeyProvider,
)
frameCryptors[trackId] = frameCryptor
frameCryptor.setEnabled(enabled)
if(keyProvider.enableSharedKey) {
if (keyProvider.enableSharedKey) {
keyProvider.rtcKeyProvider?.setKey(pid, 0, keyProvider?.sharedKey)
frameCryptor.setKeyIndex(0)
}
... ... @@ -133,12 +157,16 @@ constructor(keyProvider: KeyProvider) {
private fun addRtpReceiver(receiver: RtpReceiver, participantId: String, trackId: String, kind: String): FrameCryptor {
var pid = "$kind-receiver-$participantId-$trackId"
var frameCryptor = FrameCryptorFactory.createFrameCryptorForRtpReceiver(
receiver, pid, algorithm, keyProvider.rtcKeyProvider)
receiver,
pid,
algorithm,
keyProvider.rtcKeyProvider,
)
frameCryptors[trackId] = frameCryptor
frameCryptor.setEnabled(enabled)
if(keyProvider.enableSharedKey) {
if (keyProvider.enableSharedKey) {
keyProvider.rtcKeyProvider?.setKey(pid, 0, keyProvider?.sharedKey)
frameCryptor.setKeyIndex(0)
}
... ... @@ -156,7 +184,7 @@ constructor(keyProvider: KeyProvider) {
var frameCryptor = item.value
var participantId = item.key
frameCryptor.setEnabled(enabled)
if(keyProvider.enableSharedKey) {
if (keyProvider.enableSharedKey) {
keyProvider.rtcKeyProvider?.setKey(participantId, 0, keyProvider?.sharedKey)
frameCryptor.setKeyIndex(0)
}
... ... @@ -169,7 +197,7 @@ constructor(keyProvider: KeyProvider) {
fun ratchetKey() {
for (participantId in frameCryptors.keys) {
var newKey = keyProvider.rtcKeyProvider?.ratchetKey(participantId, 0)
LKLog.d{ "ratchetKey: newKey: $newKey" }
LKLog.d { "ratchetKey: newKey: $newKey" }
}
}
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.e2ee
import livekit.LivekitModels.Encryption
... ... @@ -15,7 +31,8 @@ constructor(
defaultRatchetWindowSize,
true,
defaultFaultTolerance,
), encryptionType: Encryption.Type = Encryption.Type.GCM
),
encryptionType: Encryption.Type = Encryption.Type.GCM,
) {
var keyProvider: KeyProvider
var encryptionType: Encryption.Type = Encryption.Type.NONE
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.e2ee
enum class E2EEState {
... ... @@ -7,5 +23,5 @@ enum class E2EEState {
MISSING_KEY, // missing key
ENCRYPTION_FAILED, // encryption failed
DECRYPTION_FAILED, // decryption failed
INTERNAL_ERROR // internal error
INTERNAL_ERROR, // internal error
}
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.e2ee
import io.livekit.android.util.LKLog
... ... @@ -5,13 +21,13 @@ import org.webrtc.FrameCryptorFactory
import org.webrtc.FrameCryptorKeyProvider
class KeyInfo
constructor(var participantId: String, var keyIndex: Int, var key: String ) {
constructor(var participantId: String, var keyIndex: Int, var key: String) {
override fun toString(): String {
return "KeyInfo(participantId='$participantId', keyIndex=$keyIndex)"
}
}
public interface KeyProvider {
public interface KeyProvider {
fun setKey(key: String, participantId: String?, keyIndex: Int? = 0)
fun ratchetKey(participantId: String, index: Int): ByteArray
... ... @@ -28,7 +44,7 @@ constructor(
private var uncryptedMagicBytes: String,
private var ratchetWindowSize: Int,
override var enableSharedKey: Boolean = true,
private var failureTolerance:Int,
private var failureTolerance: Int,
) :
KeyProvider {
override var sharedKey: ByteArray? = null
... ... @@ -46,8 +62,8 @@ constructor(
return
}
if(participantId == null) {
LKLog.d{ "Please provide valid participantId for non-SharedKey mode." }
if (participantId == null) {
LKLog.d { "Please provide valid participantId for non-SharedKey mode." }
return
}
... ... @@ -72,7 +88,7 @@ constructor(
ratchetSalt.toByteArray(),
ratchetWindowSize,
uncryptedMagicBytes.toByteArray(),
failureTolerance
failureTolerance,
)
}
}
... ...
... ... @@ -58,7 +58,6 @@ sealed class ParticipantEvent(open val participant: Participant) : Event() {
*/
class TrackUnmuted(participant: Participant, val publication: TrackPublication) : ParticipantEvent(participant)
// local participants
/**
* When a new track is published by the local participant.
... ... @@ -113,7 +112,7 @@ sealed class ParticipantEvent(open val participant: Participant) : Event() {
class TrackUnsubscribed(
override val participant: RemoteParticipant,
val track: Track,
val publication: RemoteTrackPublication
val publication: RemoteTrackPublication,
) : ParticipantEvent(participant)
/**
... ... @@ -122,7 +121,7 @@ sealed class ParticipantEvent(open val participant: Participant) : Event() {
class DataReceived(
override val participant: RemoteParticipant,
val data: ByteArray,
val topic: String?
val topic: String?,
) : ParticipantEvent(participant)
/**
... ... @@ -131,17 +130,16 @@ sealed class ParticipantEvent(open val participant: Participant) : Event() {
class TrackStreamStateChanged(
override val participant: Participant,
val trackPublication: TrackPublication,
val streamState: Track.StreamState
val streamState: Track.StreamState,
) : ParticipantEvent(participant)
/**
* A remote track's subscription permissions have changed.
*/
class TrackSubscriptionPermissionChanged(
override val participant: RemoteParticipant,
val trackPublication: RemoteTrackPublication,
val subscriptionAllowed: Boolean
val subscriptionAllowed: Boolean,
) : ParticipantEvent(participant)
/**
... ...
... ... @@ -62,7 +62,7 @@ sealed class RoomEvent(val room: Room) : Event() {
class RoomMetadataChanged(
room: Room,
val newMetadata: String?,
val prevMetadata: String?
val prevMetadata: String?,
) : RoomEvent(room)
// Participant callbacks
... ... @@ -74,13 +74,13 @@ sealed class RoomEvent(val room: Room) : Event() {
class ParticipantMetadataChanged(
room: Room,
val participant: Participant,
val prevMetadata: String?
val prevMetadata: String?,
) : RoomEvent(room)
class ParticipantNameChanged(
room: Room,
val participant: Participant,
val name: String?
val name: String?,
) : RoomEvent(room)
/**
... ... @@ -119,7 +119,7 @@ sealed class RoomEvent(val room: Room) : Event() {
room: Room,
val track: Track,
val publication: TrackPublication,
val participant: RemoteParticipant
val participant: RemoteParticipant,
) : RoomEvent(room)
/**
... ... @@ -129,7 +129,7 @@ sealed class RoomEvent(val room: Room) : Event() {
room: Room,
val sid: String,
val exception: Exception,
val participant: RemoteParticipant
val participant: RemoteParticipant,
) : RoomEvent(room)
/**
... ... @@ -140,7 +140,7 @@ sealed class RoomEvent(val room: Room) : Event() {
room: Room,
val track: Track,
val publications: TrackPublication,
val participant: RemoteParticipant
val participant: RemoteParticipant,
) : RoomEvent(room)
/**
... ... @@ -149,7 +149,7 @@ sealed class RoomEvent(val room: Room) : Event() {
class TrackStreamStateChanged(
room: Room,
val trackPublication: TrackPublication,
val streamState: Track.StreamState
val streamState: Track.StreamState,
) : RoomEvent(room)
/**
... ... @@ -159,7 +159,7 @@ sealed class RoomEvent(val room: Room) : Event() {
room: Room,
val participant: RemoteParticipant,
val trackPublication: RemoteTrackPublication,
val subscriptionAllowed: Boolean
val subscriptionAllowed: Boolean,
) : RoomEvent(room)
/**
... ... @@ -207,7 +207,7 @@ sealed class RoomEvent(val room: Room) : Event() {
val track: Track,
val publication: TrackPublication,
val participant: Participant,
var state: E2EEState
var state: E2EEState,
) : RoomEvent(room)
}
... ... @@ -219,7 +219,7 @@ enum class DisconnectReason {
PARTICIPANT_REMOVED,
ROOM_DELETED,
STATE_MISMATCH,
JOIN_FAILURE;
JOIN_FAILURE,
}
fun LivekitModels.DisconnectReason?.convert(): DisconnectReason {
... ... @@ -233,6 +233,7 @@ fun LivekitModels.DisconnectReason?.convert(): DisconnectReason {
LivekitModels.DisconnectReason.JOIN_FAILURE -> DisconnectReason.JOIN_FAILURE
LivekitModels.DisconnectReason.UNKNOWN_REASON,
LivekitModels.DisconnectReason.UNRECOGNIZED,
null -> DisconnectReason.UNKNOWN_REASON
null,
-> DisconnectReason.UNKNOWN_REASON
}
}
... ...
... ... @@ -23,12 +23,16 @@ import org.webrtc.*
import org.webrtc.RendererCommon.*
import java.util.concurrent.CountDownLatch
/**
* Display the video stream on a TextureView.
*/
open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureView.SurfaceTextureListener, VideoSink,
RendererEvents, ViewVisibility.Notifier {
open class TextureViewRenderer :
TextureView,
SurfaceHolder.Callback,
TextureView.SurfaceTextureListener,
VideoSink,
RendererEvents,
ViewVisibility.Notifier {
// Cached resource name.
private val resourceName: String
private val videoLayoutMeasure = VideoLayoutMeasure()
... ... @@ -68,6 +72,7 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
* `drawer`. It is allowed to call init() to reinitialize the renderer after a previous
* init()/release() cycle.
*/
/**
* Initialize this class, sharing resources with `sharedContext`. It is allowed to call init() to
* reinitialize the renderer after a previous init()/release() cycle.
... ... @@ -75,14 +80,15 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
@JvmOverloads
fun init(
sharedContext: EglBase.Context?,
rendererEvents: RendererEvents?, configAttributes: IntArray? = EglBase.CONFIG_PLAIN,
drawer: GlDrawer? = GlRectDrawer()
rendererEvents: RendererEvents?,
configAttributes: IntArray? = EglBase.CONFIG_PLAIN,
drawer: GlDrawer? = GlRectDrawer(),
) {
ThreadUtils.checkIsOnMainThread()
this.rendererEvents = rendererEvents
rotatedFrameWidth = 0
rotatedFrameHeight = 0
eglRenderer.init(sharedContext, this /* rendererEvents */, configAttributes, drawer)
eglRenderer.init(sharedContext, this, configAttributes, drawer)
}
/**
... ... @@ -105,7 +111,9 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
* @param drawer Custom drawer to use for this frame listener.
*/
fun addFrameListener(
listener: EglRenderer.FrameListener?, scale: Float, drawerParam: GlDrawer?
listener: EglRenderer.FrameListener?,
scale: Float,
drawerParam: GlDrawer?,
) {
eglRenderer.addFrameListener(listener, scale, drawerParam)
}
... ... @@ -155,12 +163,12 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
fun setScalingType(
scalingTypeMatchOrientation: ScalingType?,
scalingTypeMismatchOrientation: ScalingType?
scalingTypeMismatchOrientation: ScalingType?,
) {
ThreadUtils.checkIsOnMainThread()
videoLayoutMeasure.setScalingType(
scalingTypeMatchOrientation,
scalingTypeMismatchOrientation
scalingTypeMismatchOrientation,
)
requestLayout()
}
... ... @@ -221,14 +229,14 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
val width = Math.min(width, drawnFrameWidth)
val height = Math.min(height, drawnFrameHeight)
logD(
"updateSurfaceSize. Layout size: " + getWidth() + "x" + getHeight() + ", frame size: "
+ rotatedFrameWidth + "x" + rotatedFrameHeight + ", requested surface size: " + width
+ "x" + height + ", old surface size: " + surfaceWidth + "x" + surfaceHeight
"updateSurfaceSize. Layout size: " + getWidth() + "x" + getHeight() + ", frame size: " +
rotatedFrameWidth + "x" + rotatedFrameHeight + ", requested surface size: " + width +
"x" + height + ", old surface size: " + surfaceWidth + "x" + surfaceHeight,
)
if (width != surfaceWidth || height != surfaceHeight) {
surfaceWidth = width
surfaceHeight = height
adjustAspectRatio(surfaceWidth, surfaceHeight);
adjustAspectRatio(surfaceWidth, surfaceHeight)
}
} else {
surfaceHeight = 0
... ... @@ -257,8 +265,8 @@ open class TextureViewRenderer : TextureView, SurfaceHolder.Callback, TextureVie
val xoff = (viewWidth - newWidth) / 2
val yoff = (viewHeight - newHeight) / 2
logD(
"video=" + videoWidth + "x" + videoHeight + " view=" + viewWidth + "x" + viewHeight
+ " newView=" + newWidth + "x" + newHeight + " off=" + xoff + "," + yoff
"video=" + videoWidth + "x" + videoHeight + " view=" + viewWidth + "x" + viewHeight +
" newView=" + newWidth + "x" + newHeight + " off=" + xoff + "," + yoff,
)
val txform = Matrix()
getTransform(txform)
... ...
... ... @@ -20,5 +20,5 @@ enum class ConnectionState {
CONNECTING,
CONNECTED,
DISCONNECTED,
RECONNECTING;
RECONNECTING,
}
... ...
... ... @@ -27,7 +27,7 @@ object DeviceManager {
enum class Kind {
// Only camera input currently, audio input/output only has one option atm.
CAMERA;
CAMERA,
}
private val defaultDevices = mutableMapOf<Kind, String>()
... ... @@ -44,7 +44,8 @@ object DeviceManager {
hasSetupListeners = true
val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
cameraManager.registerAvailabilityCallback(object : CameraManager.AvailabilityCallback() {
cameraManager.registerAvailabilityCallback(
object : CameraManager.AvailabilityCallback() {
override fun onCameraAvailable(cameraId: String) {
notifyListeners(Kind.CAMERA)
}
... ... @@ -56,7 +57,9 @@ object DeviceManager {
override fun onCameraAccessPrioritiesChanged() {
notifyListeners(Kind.CAMERA)
}
}, Handler(Looper.getMainLooper()))
},
Handler(Looper.getMainLooper()),
)
}
fun getDefaultDevice(kind: Kind): String? {
... ... @@ -89,7 +92,7 @@ object DeviceManager {
fun registerOnDeviceAvailabilityChange(
kind: Kind,
listener: OnDeviceAvailabilityChangeListener
listener: OnDeviceAvailabilityChangeListener,
) {
if (listeners[kind] == null) {
listeners[kind] = mutableListOf()
... ... @@ -99,7 +102,7 @@ object DeviceManager {
fun unregisterOnDeviceAvailabilityChange(
kind: Kind,
listener: OnDeviceAvailabilityChangeListener
listener: OnDeviceAvailabilityChangeListener,
) {
listeners[kind]?.remove(listener)
}
... ...
... ... @@ -45,12 +45,12 @@ constructor(
@Assisted private val listener: Listener?,
@Named(InjectionNames.DISPATCHER_IO)
private val ioDispatcher: CoroutineDispatcher,
connectionFactory: PeerConnectionFactory
connectionFactory: PeerConnectionFactory,
) {
private val coroutineScope = CoroutineScope(ioDispatcher + SupervisorJob())
internal val peerConnection: PeerConnection = connectionFactory.createPeerConnection(
config,
pcObserver
pcObserver,
) ?: throw IllegalStateException("peer connection creation failed?")
private val pendingCandidates = mutableListOf<IceCandidate>()
private var restartingIce: Boolean = false
... ... @@ -76,7 +76,6 @@ constructor(
}
suspend fun setRemoteDescription(sd: SessionDescription): Either<Unit, String?> {
val result = peerConnection.setRemoteDescription(sd)
if (result is Either.Left) {
mutex.withLock {
... ... @@ -145,7 +144,6 @@ constructor(
listener?.onOffer(sdpOffer)
}
fun prepareForIceRestart() {
restartingIce = true
}
... ... @@ -163,7 +161,7 @@ constructor(
fun create(
config: PeerConnection.RTCConfiguration,
pcObserver: PeerConnection.Observer,
listener: Listener?
listener: Listener?,
): PeerConnectionTransport
}
}
... ...
... ... @@ -85,5 +85,4 @@ class PublisherTransportObserver(
override fun onAddTrack(p0: RtpReceiver?, p1: Array<out MediaStream>?) {
}
}
... ...
... ... @@ -21,7 +21,6 @@ import com.google.protobuf.ByteString
import io.livekit.android.ConnectOptions
import io.livekit.android.RoomOptions
import io.livekit.android.dagger.InjectionNames
import io.livekit.android.e2ee.E2EEOptions
import io.livekit.android.events.DisconnectReason
import io.livekit.android.events.convert
import io.livekit.android.room.participant.ParticipantTrackPermission
... ... @@ -39,7 +38,6 @@ import io.livekit.android.webrtc.toProtoSessionDescription
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import livekit.LivekitModels
import livekit.LivekitModels.Encryption
import livekit.LivekitRtc
import livekit.LivekitRtc.JoinResponse
import livekit.LivekitRtc.ReconnectResponse
... ... @@ -150,7 +148,7 @@ internal constructor(
url: String,
token: String,
options: ConnectOptions,
roomOptions: RoomOptions
roomOptions: RoomOptions,
): JoinResponse {
coroutineScope.close()
coroutineScope = CloseableCoroutineScope(SupervisorJob() + ioDispatcher)
... ... @@ -165,7 +163,7 @@ internal constructor(
url: String,
token: String,
options: ConnectOptions,
roomOptions: RoomOptions
roomOptions: RoomOptions,
): JoinResponse {
val joinResponse = client.join(url, token, options, roomOptions)
listener?.onJoinResponse(joinResponse)
... ... @@ -248,7 +246,7 @@ internal constructor(
reliableInit.ordered = true
reliableDataChannel = publisher.peerConnection.createDataChannel(
RELIABLE_DATA_CHANNEL_LABEL,
reliableInit
reliableInit,
)
reliableDataChannel!!.registerObserver(this)
val lossyInit = DataChannel.Init()
... ... @@ -256,7 +254,7 @@ internal constructor(
lossyInit.maxRetransmits = 0
lossyDataChannel = publisher.peerConnection.createDataChannel(
LOSSY_DATA_CHANNEL_LABEL,
lossyInit
lossyInit,
)
lossyDataChannel!!.registerObserver(this)
}
... ... @@ -268,7 +266,7 @@ internal constructor(
cid: String,
name: String,
kind: LivekitModels.TrackType,
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder()
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(),
): LivekitModels.TrackInfo {
if (pendingTrackResolvers[cid] != null) {
throw TrackException.DuplicateTrackException("Track with same ID $cid has already been published!")
... ... @@ -282,7 +280,7 @@ internal constructor(
fun updateSubscriptionPermissions(
allParticipants: Boolean,
participantTrackPermissions: List<ParticipantTrackPermission>
participantTrackPermissions: List<ParticipantTrackPermission>,
) {
client.sendUpdateSubscriptionPermissions(allParticipants, participantTrackPermissions)
}
... ... @@ -348,7 +346,6 @@ internal constructor(
val forceFullReconnect = fullReconnectOnNext
fullReconnectOnNext = false
val job = coroutineScope.launch {
connectionState = ConnectionState.RECONNECTING
listener?.onEngineReconnecting()
... ... @@ -498,7 +495,6 @@ internal constructor(
this.negotiatePublisher()
}
val targetChannel = dataChannelForKind(kind) ?: throw IllegalArgumentException("Unknown data packet kind!")
if (targetChannel.state() == DataChannel.State.OPEN) {
return
... ... @@ -529,21 +525,21 @@ internal constructor(
add(
MediaConstraints.KeyValuePair(
MediaConstraintKeys.OFFER_TO_RECV_AUDIO,
MediaConstraintKeys.FALSE
)
MediaConstraintKeys.FALSE,
),
)
add(
MediaConstraints.KeyValuePair(
MediaConstraintKeys.OFFER_TO_RECV_VIDEO,
MediaConstraintKeys.FALSE
)
MediaConstraintKeys.FALSE,
),
)
if (connectionState == ConnectionState.RECONNECTING) {
add(
MediaConstraints.KeyValuePair(
MediaConstraintKeys.ICE_RESTART,
MediaConstraintKeys.TRUE
)
MediaConstraintKeys.TRUE,
),
)
}
}
... ... @@ -552,9 +548,8 @@ internal constructor(
private fun makeRTCConfig(
serverResponse: Either<JoinResponse, ReconnectResponse>,
connectOptions: ConnectOptions
connectOptions: ConnectOptions,
): RTCConfiguration {
// Convert protobuf ice servers
val serverIceServers = run {
val servers = mutableListOf<PeerConnection.IceServer>()
... ... @@ -664,7 +659,7 @@ internal constructor(
}
}
//---------------------------------- SignalClient.Listener --------------------------------------//
// ---------------------------------- SignalClient.Listener --------------------------------------//
override fun onAnswer(sessionDescription: SessionDescription) {
LKLog.v { "received server answer: ${sessionDescription.type}, ${publisher.peerConnection.signalingState()}" }
... ... @@ -686,8 +681,10 @@ internal constructor(
LKLog.v { "received server offer: ${sessionDescription.type}, ${subscriber.peerConnection.signalingState()}" }
coroutineScope.launch {
run<Unit> {
when (val outcome =
subscriber.setRemoteDescription(sessionDescription)) {
when (
val outcome =
subscriber.setRemoteDescription(sessionDescription)
) {
is Either.Right -> {
LKLog.e { "error setting remote description for answer: ${outcome.value} " }
return@launch
... ... @@ -821,7 +818,7 @@ internal constructor(
listener?.onLocalTrackUnpublished(trackUnpublished)
}
//--------------------------------- DataChannel.Observer ------------------------------------//
// --------------------------------- DataChannel.Observer ------------------------------------//
override fun onBufferedAmountChange(previousAmount: Long) {
}
... ... @@ -844,7 +841,8 @@ internal constructor(
}
LivekitModels.DataPacket.ValueCase.VALUE_NOT_SET,
null -> {
null,
-> {
LKLog.v { "invalid value for data packet" }
}
}
... ... @@ -852,7 +850,7 @@ internal constructor(
fun sendSyncState(
subscription: LivekitRtc.UpdateSubscription,
publishedTracks: List<LivekitRtc.TrackPublishedResponse>
publishedTracks: List<LivekitRtc.TrackPublishedResponse>,
) {
val answer = subscriber.peerConnection.localDescription?.toProtoSessionDescription()
... ... @@ -894,7 +892,7 @@ internal constructor(
enum class ReconnectType {
DEFAULT,
FORCE_SOFT_RECONNECT,
FORCE_FULL_RECONNECT;
FORCE_FULL_RECONNECT,
}
internal fun LivekitRtc.ICEServer.toWebrtc() = PeerConnection.IceServer.builder(urlsList)
... ...
... ... @@ -80,7 +80,7 @@ constructor(
CONNECTING,
CONNECTED,
DISCONNECTED,
RECONNECTING;
RECONNECTING,
}
/**
... ... @@ -90,7 +90,7 @@ constructor(
SPEAKER_UPDATE,
NODE_FAILURE,
MIGRATION,
SERVER_LEAVE;
SERVER_LEAVE,
}
@JvmInline
... ... @@ -224,7 +224,7 @@ constructor(
room = this@Room,
publication = it.publication,
participant = it.participant,
)
),
)
is ParticipantEvent.ParticipantPermissionsChanged -> emitWhenConnected(
... ... @@ -233,7 +233,7 @@ constructor(
participant = it.participant,
newPermissions = it.newPermissions,
oldPermissions = it.oldPermissions,
)
),
)
is ParticipantEvent.MetadataChanged -> {
... ... @@ -242,8 +242,8 @@ constructor(
RoomEvent.ParticipantMetadataChanged(
this@Room,
it.participant,
it.prevMetadata
)
it.prevMetadata,
),
)
}
... ... @@ -252,13 +252,13 @@ constructor(
RoomEvent.ParticipantNameChanged(
this@Room,
it.participant,
it.name
)
it.name,
),
)
}
else -> {
/* do nothing */
// do nothing
}
}
}
... ... @@ -267,9 +267,9 @@ constructor(
state = State.CONNECTING
connectOptions = options
if(roomOptions.e2eeOptions != null) {
if (roomOptions.e2eeOptions != null) {
e2eeManager = E2EEManager(roomOptions!!.e2eeOptions!!.keyProvider)
e2eeManager!!.setup(this, {event ->
e2eeManager!!.setup(this, { event ->
coroutineScope.launch {
emitWhenConnected(event)
}
... ... @@ -316,7 +316,6 @@ constructor(
* @suppress
*/
override fun onJoinResponse(response: LivekitRtc.JoinResponse) {
LKLog.i { "Connected to server, server version: ${response.serverVersion}, client version: ${Version.CLIENT_VERSION}" }
sid = Sid(response.room.sid)
... ... @@ -365,7 +364,7 @@ constructor(
@Synchronized
private fun getOrCreateRemoteParticipant(
sid: String,
info: LivekitModels.ParticipantInfo? = null
info: LivekitModels.ParticipantInfo? = null,
): RemoteParticipant {
var participant = remoteParticipants[sid]
if (participant != null) {
... ... @@ -389,7 +388,7 @@ constructor(
room = this@Room,
publication = it.publication,
participant = it.participant,
)
),
)
}
}
... ... @@ -398,8 +397,8 @@ constructor(
RoomEvent.TrackStreamStateChanged(
this@Room,
it.trackPublication,
it.streamState
)
it.streamState,
),
)
is ParticipantEvent.TrackSubscriptionPermissionChanged -> eventBus.postEvent(
... ... @@ -407,8 +406,8 @@ constructor(
this@Room,
it.participant,
it.trackPublication,
it.subscriptionAllowed
)
it.subscriptionAllowed,
),
)
is ParticipantEvent.MetadataChanged -> {
... ... @@ -417,8 +416,8 @@ constructor(
RoomEvent.ParticipantMetadataChanged(
this@Room,
it.participant,
it.prevMetadata
)
it.prevMetadata,
),
)
}
... ... @@ -428,7 +427,7 @@ constructor(
this@Room,
it.participant,
it.name,
)
),
)
}
... ... @@ -438,11 +437,11 @@ constructor(
participant = it.participant,
newPermissions = it.newPermissions,
oldPermissions = it.oldPermissions,
)
),
)
else -> {
/* do nothing */
// do nothing
}
}
}
... ... @@ -632,7 +631,7 @@ constructor(
fun create(context: Context): Room
}
//------------------------------------- NetworkCallback -------------------------------------//
// ------------------------------------- NetworkCallback -------------------------------------//
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
/**
* @suppress
... ... @@ -656,7 +655,7 @@ constructor(
}
}
//----------------------------------- RTCEngine.Listener ------------------------------------//
// ----------------------------------- RTCEngine.Listener ------------------------------------//
/**
* @suppress
... ... @@ -703,7 +702,7 @@ constructor(
trackSid!!,
autoManageVideo = adaptiveStream,
statsGetter = statsGetter,
receiver = receiver
receiver = receiver,
)
}
... ... @@ -895,7 +894,7 @@ constructor(
localParticipant.handleLocalTrackUnpublished(trackUnpublished)
}
//------------------------------- ParticipantListener --------------------------------//
// ------------------------------- ParticipantListener --------------------------------//
/**
* This is called for both Local and Remote participants
* @suppress
... ... @@ -928,11 +927,12 @@ constructor(
*/
override fun onTrackPublished(publication: LocalTrackPublication, participant: LocalParticipant) {
listener?.onTrackPublished(publication, participant, this)
if(e2eeManager != null) {
if (e2eeManager != null) {
e2eeManager!!.addPublishedTrack(publication.track!!, publication, participant, this)
}
eventBus.postEvent(RoomEvent.TrackPublished(this, publication, participant), coroutineScope)
}
/**
* @suppress
*/
... ... @@ -946,7 +946,7 @@ constructor(
*/
override fun onTrackSubscribed(track: Track, publication: RemoteTrackPublication, participant: RemoteParticipant) {
listener?.onTrackSubscribed(track, publication, participant, this)
if(e2eeManager != null) {
if (e2eeManager != null) {
e2eeManager!!.addSubscribedTrack(track, publication, participant, this)
}
eventBus.postEvent(RoomEvent.TrackSubscribed(this, track, publication, participant), coroutineScope)
... ... @@ -958,7 +958,7 @@ constructor(
override fun onTrackSubscriptionFailed(
sid: String,
exception: Exception,
participant: RemoteParticipant
participant: RemoteParticipant,
) {
listener?.onTrackSubscriptionFailed(sid, exception, participant, this)
eventBus.postEvent(RoomEvent.TrackSubscriptionFailed(this, sid, exception, participant), coroutineScope)
... ... @@ -970,7 +970,7 @@ constructor(
override fun onTrackUnsubscribed(
track: Track,
publication: RemoteTrackPublication,
participant: RemoteParticipant
participant: RemoteParticipant,
) {
listener?.onTrackUnsubscribed(track, publication, participant, this)
eventBus.postEvent(RoomEvent.TrackUnsubscribed(this, track, publication, participant), coroutineScope)
... ... @@ -982,7 +982,7 @@ constructor(
fun initVideoRenderer(viewRenderer: SurfaceViewRenderer) {
viewRenderer.init(eglBase.eglBaseContext, null)
viewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
viewRenderer.setEnableHardwareScaler(false /* enabled */)
viewRenderer.setEnableHardwareScaler(false)
}
/**
... ... @@ -991,7 +991,7 @@ constructor(
fun initVideoRenderer(viewRenderer: TextureViewRenderer) {
viewRenderer.init(eglBase.eglBaseContext, null)
viewRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
viewRenderer.setEnableHardwareScaler(false /* enabled */)
viewRenderer.setEnableHardwareScaler(false)
}
private suspend fun emitWhenConnected(event: RoomEvent) {
... ...
... ... @@ -80,7 +80,9 @@ constructor(
private var joinContinuation: CancellableContinuation<
Either<
JoinResponse,
Either<ReconnectResponse, Unit>>>? = null
Either<ReconnectResponse, Unit>,
>,
>? = null
private lateinit var coroutineScope: CloseableCoroutineScope
private val requestFlowJobLock = Object()
... ... @@ -121,7 +123,7 @@ constructor(
reconnect = true
this.participantSid = participantSid
},
lastRoomOptions ?: RoomOptions()
lastRoomOptions ?: RoomOptions(),
)
return (reconnectResponse as Either.Right).value
}
... ... @@ -130,7 +132,7 @@ constructor(
url: String,
token: String,
options: ConnectOptions,
roomOptions: RoomOptions
roomOptions: RoomOptions,
): Either<JoinResponse, Either<ReconnectResponse, Unit>> {
// Clean up any pre-existing connection.
close(reason = "Starting new connection")
... ... @@ -160,9 +162,8 @@ constructor(
token: String,
clientInfo: LivekitModels.ClientInfo,
options: ConnectOptions,
roomOptions: RoomOptions
roomOptions: RoomOptions,
): String {
val queryParams = mutableListOf<Pair<String, String>>()
queryParams.add(CONNECT_QUERY_TOKEN to token)
queryParams.add(CONNECT_QUERY_PROTOCOL to options.protocolVersion.value.toString())
... ... @@ -234,7 +235,7 @@ constructor(
startRequestQueue()
}
//--------------------------------- WebSocket Listener --------------------------------------//
// --------------------------------- WebSocket Listener --------------------------------------//
override fun onMessage(webSocket: WebSocket, text: String) {
LKLog.w { "received JSON message, unsupported in this version." }
}
... ... @@ -291,7 +292,7 @@ constructor(
// Handle websocket closure here.
handleWebSocketClose(
reason = reason ?: response?.toString() ?: t.localizedMessage ?: "websocket failure",
code = response?.code ?: CLOSE_REASON_WEBSOCKET_FAILURE
code = response?.code ?: CLOSE_REASON_WEBSOCKET_FAILURE,
)
}
}
... ... @@ -306,7 +307,7 @@ constructor(
pongJob?.cancel()
}
//------------------------------- End WebSocket Listener ------------------------------------//
// ------------------------------- End WebSocket Listener ------------------------------------//
private fun fromProtoSessionDescription(sd: LivekitRtc.SessionDescription): SessionDescription {
val rtcSdpType = when (sd.type) {
... ... @@ -340,7 +341,7 @@ constructor(
val iceCandidateJSON = IceCandidateJSON(
candidate = candidate.sdp,
sdpMid = candidate.sdpMid,
sdpMLineIndex = candidate.sdpMLineIndex
sdpMLineIndex = candidate.sdpMLineIndex,
)
val trickleRequest = LivekitRtc.TrickleRequest.newBuilder()
... ... @@ -375,7 +376,7 @@ constructor(
cid: String,
name: String,
type: LivekitModels.TrackType,
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder()
builder: LivekitRtc.AddTrackRequest.Builder = LivekitRtc.AddTrackRequest.newBuilder(),
) {
var encryptionType = lastRoomOptions?.e2eeOptions?.encryptionType ?: LivekitModels.Encryption.Type.NONE
val addTrackRequest = builder
... ... @@ -442,7 +443,7 @@ constructor(
fun sendUpdateSubscriptionPermissions(
allParticipants: Boolean,
participantTrackPermissions: List<ParticipantTrackPermission>
participantTrackPermissions: List<ParticipantTrackPermission>,
) {
val update = LivekitRtc.SubscriptionPermission.newBuilder()
.setAllParticipants(allParticipants)
... ... @@ -580,7 +581,7 @@ constructor(
val iceCandidate = IceCandidate(
iceCandidateJson.sdpMid,
iceCandidateJson.sdpMLineIndex,
iceCandidateJson.candidate
iceCandidateJson.candidate,
)
listener?.onTrickle(iceCandidate, response.trickle.target)
}
... ... @@ -658,7 +659,8 @@ constructor(
}
LivekitRtc.SignalResponse.MessageCase.MESSAGE_NOT_SET,
null -> {
null,
-> {
LKLog.v { "empty messageCase!" }
}
}
... ... @@ -721,7 +723,7 @@ constructor(
joinContinuation?.cancel()
joinContinuation = null
// TODO: support calling this from connect without wiping any queued requests.
//requestFlow.resetReplayCache()
// requestFlow.resetReplayCache()
responseFlow.resetReplayCache()
lastUrl = null
lastOptions = null
... ...
... ... @@ -96,5 +96,4 @@ class SubscriberTransportObserver(
override fun onRenegotiationNeeded() {
}
}
... ...
... ... @@ -144,7 +144,7 @@ internal constructor(
name,
LocalVideoTrackOptions(isScreencast = true),
eglBase,
screencastVideoTrackFactory
screencastVideoTrackFactory,
)
}
... ... @@ -171,7 +171,7 @@ internal constructor(
*/
suspend fun setScreenShareEnabled(
enabled: Boolean,
mediaProjectionPermissionResultData: Intent? = null
mediaProjectionPermissionResultData: Intent? = null,
) {
setTrackEnabled(Track.Source.SCREEN_SHARE, enabled, mediaProjectionPermissionResultData)
}
... ... @@ -179,7 +179,7 @@ internal constructor(
private suspend fun setTrackEnabled(
source: Track.Source,
enabled: Boolean,
mediaProjectionPermissionResultData: Intent? = null
mediaProjectionPermissionResultData: Intent? = null,
) {
val pub = getTrackPublication(source)
... ... @@ -238,16 +238,16 @@ internal constructor(
track: LocalAudioTrack,
options: AudioTrackPublishOptions = AudioTrackPublishOptions(
null,
audioTrackPublishDefaults
audioTrackPublishDefaults,
),
publishListener: PublishListener? = null
publishListener: PublishListener? = null,
) {
val encodings = listOf(
RtpParameters.Encoding(null, true, null).apply {
if (options.audioBitrate != null && options.audioBitrate > 0) {
maxBitrateBps = options.audioBitrate
}
}
},
)
publishTrackImpl(
track = track,
... ... @@ -264,9 +264,8 @@ internal constructor(
suspend fun publishVideoTrack(
track: LocalVideoTrack,
options: VideoTrackPublishOptions = VideoTrackPublishOptions(null, videoTrackPublishDefaults),
publishListener: PublishListener? = null
publishListener: PublishListener? = null,
) {
val encodings = computeVideoEncodings(track.dimensions, options)
val videoLayers =
EncodingUtils.videoLayersFromEncodings(track.dimensions.width, track.dimensions.height, encodings)
... ... @@ -285,11 +284,10 @@ internal constructor(
addAllLayers(videoLayers)
},
encodings = encodings,
publishListener = publishListener
publishListener = publishListener,
)
}
/**
* @return true if the track publish was successful.
*/
... ... @@ -298,7 +296,7 @@ internal constructor(
options: TrackPublishOptions,
requestConfig: LivekitRtc.AddTrackRequest.Builder.() -> Unit,
encodings: List<RtpParameters.Encoding> = emptyList(),
publishListener: PublishListener? = null
publishListener: PublishListener? = null,
): Boolean {
if (localTrackPublications.any { it.track == track }) {
publishListener?.onPublishFailure(TrackException.PublishException("Track has already been published"))
... ... @@ -313,12 +311,12 @@ internal constructor(
cid = cid,
name = track.name,
kind = track.kind.toProto(),
builder = builder
builder = builder,
)
val transInit = RtpTransceiver.RtpTransceiverInit(
RtpTransceiver.RtpTransceiverDirection.SEND_ONLY,
listOf(this.sid),
encodings
encodings,
)
val transceiver = engine.publisher.peerConnection.addTransceiver(track.rtcTrack, transInit)
... ... @@ -393,7 +391,7 @@ internal constructor(
private fun computeVideoEncodings(
dimensions: Track.Dimensions,
options: VideoTrackPublishOptions
options: VideoTrackPublishOptions,
): List<RtpParameters.Encoding> {
val (width, height) = dimensions
var encoding = options.videoEncoding
... ... @@ -410,7 +408,6 @@ internal constructor(
val encodings = mutableListOf<RtpParameters.Encoding>()
if (simulcast) {
val presets = EncodingUtils.presetsForResolution(width, height)
val midPreset = presets[1]
val lowPreset = presets[0]
... ... @@ -456,7 +453,6 @@ internal constructor(
return encodings
}
/**
* Control who can subscribe to LocalParticipant's published tracks.
*
... ... @@ -476,7 +472,7 @@ internal constructor(
*/
fun setTrackSubscriptionPermissions(
allParticipantsAllowed: Boolean,
participantTrackPermissions: List<ParticipantTrackPermission> = emptyList()
participantTrackPermissions: List<ParticipantTrackPermission> = emptyList(),
) {
engine.updateSubscriptionPermissions(allParticipantsAllowed, participantTrackPermissions)
}
... ... @@ -732,7 +728,7 @@ data class VideoTrackPublishOptions(
) : BaseVideoTrackPublishOptions(), TrackPublishOptions {
constructor(
name: String? = null,
base: BaseVideoTrackPublishOptions
base: BaseVideoTrackPublishOptions,
) : this(
name,
base.videoEncoding,
... ... @@ -748,21 +744,21 @@ abstract class BaseAudioTrackPublishOptions {
data class AudioTrackPublishDefaults(
override val audioBitrate: Int? = 20_000,
override val dtx: Boolean = true
override val dtx: Boolean = true,
) : BaseAudioTrackPublishOptions()
data class AudioTrackPublishOptions(
override val name: String? = null,
override val audioBitrate: Int? = null,
override val dtx: Boolean = true
override val dtx: Boolean = true,
) : BaseAudioTrackPublishOptions(), TrackPublishOptions {
constructor(
name: String? = null,
base: BaseAudioTrackPublishOptions
base: BaseAudioTrackPublishOptions,
) : this(
name,
base.audioBitrate,
base.dtx
base.dtx,
)
}
... ... @@ -785,7 +781,7 @@ data class ParticipantTrackPermission(
/**
* The list of track ids that the target participant can subscribe to.
*/
val allowedTrackSids: List<String> = emptyList()
val allowedTrackSids: List<String> = emptyList(),
) {
init {
if (participantIdentity == null && participantSid == null) {
... ... @@ -806,11 +802,11 @@ data class ParticipantTrackPermission(
sealed class PublishRecord() {
data class AudioTrackPublishRecord(
val track: LocalAudioTrack,
val options: AudioTrackPublishOptions
val options: AudioTrackPublishOptions,
)
data class VideoTrackPublishRecord(
val track: LocalVideoTrack,
val options: VideoTrackPublishOptions
val options: VideoTrackPublishOptions,
)
}
... ...
... ... @@ -127,9 +127,9 @@ open class Participant(
ParticipantEvent.ParticipantPermissionsChanged(
this,
newPermissions,
oldPermissions
oldPermissions,
),
scope
scope,
)
}
}
... ... @@ -191,7 +191,7 @@ open class Participant(
// Re-emit when track changes
trackPublication::track.flow
.map { trackPublication to trackPublication.track }
}
},
) { trackPubs ->
trackPubs.toList()
}
... ... @@ -208,7 +208,7 @@ open class Participant(
stateFlow = ::tracks.flow
.map { it.filterValues { publication -> publication.kind == Track.Kind.AUDIO } }
.trackUpdateFlow()
.stateIn(delegateScope, SharingStarted.Eagerly, emptyList())
.stateIn(delegateScope, SharingStarted.Eagerly, emptyList()),
)
/**
... ... @@ -220,7 +220,7 @@ open class Participant(
stateFlow = ::tracks.flow
.map { it.filterValues { publication -> publication.kind == Track.Kind.VIDEO } }
.trackUpdateFlow()
.stateIn(delegateScope, SharingStarted.Eagerly, emptyList())
.stateIn(delegateScope, SharingStarted.Eagerly, emptyList()),
)
/**
... ... @@ -340,7 +340,7 @@ open class Participant(
val trackPublication = tracks[trackEvent.track.sid] ?: return
eventBus.postEvent(
ParticipantEvent.TrackStreamStateChanged(this, trackPublication, trackEvent.streamState),
scope
scope,
)
}
... ... @@ -392,7 +392,6 @@ interface ParticipantListener {
*/
fun onTrackUnmuted(publication: TrackPublication, participant: Participant) {}
// local participants
/**
* When a new track is published by the local participant.
... ... @@ -428,7 +427,7 @@ interface ParticipantListener {
fun onTrackSubscriptionFailed(
sid: String,
exception: Exception,
participant: RemoteParticipant
participant: RemoteParticipant,
) {
}
... ... @@ -439,7 +438,7 @@ interface ParticipantListener {
fun onTrackUnsubscribed(
track: Track,
publication: RemoteTrackPublication,
participant: RemoteParticipant
participant: RemoteParticipant,
) {
}
... ... @@ -453,7 +452,8 @@ enum class ConnectionQuality {
EXCELLENT,
GOOD,
POOR,
UNKNOWN;
UNKNOWN,
;
companion object {
fun fromProto(proto: LivekitModels.ConnectionQuality): ConnectionQuality {
... ...
... ... @@ -31,7 +31,6 @@ import livekit.LivekitRtc
import org.webrtc.AudioTrack
import org.webrtc.MediaStreamTrack
import org.webrtc.RtpReceiver
import org.webrtc.RtpTransceiver
import org.webrtc.VideoTrack
class RemoteParticipant(
... ... @@ -135,7 +134,7 @@ class RemoteParticipant(
} else {
coroutineScope.launch {
delay(150)
addSubscribedMediaTrack(mediaTrack, sid, statsGetter,receiver = receiver, autoManageVideo, triesLeft - 1)
addSubscribedMediaTrack(mediaTrack, sid, statsGetter, receiver = receiver, autoManageVideo, triesLeft - 1)
}
}
return
... ...
... ... @@ -19,5 +19,4 @@ package io.livekit.android.room.track
import org.webrtc.AudioTrack
abstract class AudioTrack(name: String, override val rtcTrack: AudioTrack) :
Track(name, Kind.AUDIO, rtcTrack) {
}
Track(name, Kind.AUDIO, rtcTrack)
... ...
... ... @@ -55,7 +55,7 @@ constructor(
context,
eglBase,
defaultsManager,
videoTrackFactory
videoTrackFactory,
) {
private val serviceConnection = ScreenCaptureConnection(context)
... ... @@ -128,7 +128,7 @@ constructor(
name: String,
options: LocalVideoTrackOptions,
rootEglBase: EglBase,
screencastVideoTrackFactory: Factory
screencastVideoTrackFactory: Factory,
): LocalScreencastVideoTrack {
val source = peerConnectionFactory.createVideoSource(options.isScreencast)
val callback = MediaProjectionCallback()
... ... @@ -136,7 +136,7 @@ constructor(
capturer.initialize(
SurfaceTextureHelper.create("ScreenVideoCaptureThread", rootEglBase.eglBaseContext),
context,
source.capturerObserver
source.capturerObserver,
)
val track = peerConnectionFactory.createVideoTrack(UUID.randomUUID().toString(), source)
... ... @@ -146,14 +146,13 @@ constructor(
options = options,
name = name,
rtcTrack = track,
mediaProjectionCallback = callback
mediaProjectionCallback = callback,
)
}
private fun createScreenCapturer(
resultData: Intent,
callback: MediaProjectionCallback
callback: MediaProjectionCallback,
): ScreenCapturerAndroid {
return ScreenCapturerAndroid(resultData, callback)
}
... ...
... ... @@ -21,7 +21,6 @@ import android.content.Context
import android.content.pm.PackageManager
import android.hardware.camera2.CameraManager
import androidx.core.content.ContextCompat
import com.github.ajalt.timberkt.Timber
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
... ... @@ -36,7 +35,6 @@ import org.webrtc.*
import org.webrtc.CameraVideoCapturer.CameraEventsHandler
import java.util.*
/**
* A representation of a local video track (generally input coming from camera or screen).
*
... ... @@ -116,7 +114,6 @@ constructor(
* this will switch to the next camera, if one is available.
*/
fun switchCamera(deviceId: String? = null, position: CameraPosition? = null) {
val cameraCapturer = capturer as? CameraVideoCapturer ?: run {
LKLog.w { "Attempting to switch camera on a non-camera video track!" }
return
... ... @@ -183,7 +180,6 @@ constructor(
override fun onCameraSwitchError(errorDescription: String?) {
LKLog.w { "switching camera failed: $errorDescription" }
}
}
if (targetDeviceId == null) {
LKLog.w { "No target camera found!" }
... ... @@ -197,7 +193,6 @@ constructor(
* Restart a track with new options.
*/
fun restartTrack(options: LocalVideoTrackOptions = defaultsManager.videoTrackCaptureDefaults.copy()) {
val oldCapturer = capturer
val oldSource = source
val oldRtcTrack = rtcTrack
... ... @@ -293,7 +288,6 @@ constructor(
trackFactory: Factory,
videoProcessor: VideoProcessor? = null,
): LocalVideoTrack {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) !=
PackageManager.PERMISSION_GRANTED
) {
... ... @@ -450,5 +444,4 @@ constructor(
return null
}
}
}
... ...
... ... @@ -26,7 +26,7 @@ data class LocalVideoTrackOptions(
*/
val deviceId: String? = null,
val position: CameraPosition? = CameraPosition.FRONT,
val captureParams: VideoCaptureParameter = VideoPreset169.QHD.capture
val captureParams: VideoCaptureParameter = VideoPreset169.QHD.capture,
)
data class VideoCaptureParameter(
... ... @@ -56,7 +56,6 @@ data class VideoEncoding(
networkPriority = 1 // low, from priority.h in webrtc
bitratePriority = 1.0
}
}
}
}
... ... @@ -68,7 +67,7 @@ enum class VideoCodec(val codecName: String) {
enum class CameraPosition {
FRONT,
BACK
BACK,
}
interface VideoPreset {
... ... @@ -125,26 +124,30 @@ enum class VideoPreset169(
VideoCaptureParameter(320, 180, 15),
VideoEncoding(125_000, 15),
),
@Deprecated("VGA is deprecated, use H360 instead")
VGA(
VideoCaptureParameter(640, 360, 30),
VideoEncoding(400_000, 30),
),
@Deprecated("QHD is deprecated, use H540 instead")
QHD(
VideoCaptureParameter(960, 540, 30),
VideoEncoding(800_000, 30),
),
@Deprecated("HD is deprecated, use H720 instead")
HD(
VideoCaptureParameter(1280, 720, 30),
VideoEncoding(2_500_000, 30),
),
@Deprecated("FHD is deprecated, use H1080 instead")
FHD(
VideoCaptureParameter(1920, 1080, 30),
VideoEncoding(4_000_000, 30),
)
),
}
/**
... ... @@ -196,24 +199,28 @@ enum class VideoPreset43(
VideoCaptureParameter(240, 180, 15),
VideoEncoding(100_000, 15),
),
@Deprecated("VGA is deprecated, use H360 instead")
VGA(
VideoCaptureParameter(480, 360, 30),
VideoEncoding(320_000, 30),
),
@Deprecated("QHD is deprecated, use H540 instead")
QHD(
VideoCaptureParameter(720, 540, 30),
VideoEncoding(640_000, 30),
),
@Deprecated("HD is deprecated, use H720 instead")
HD(
VideoCaptureParameter(960, 720, 30),
VideoEncoding(2_000_000, 30),
),
@Deprecated("FHD is deprecated, use H1080 instead")
FHD(
VideoCaptureParameter(1440, 1080, 30),
VideoEncoding(3_200_000, 30),
)
),
}
... ...
... ... @@ -153,10 +153,10 @@ class RemoteTrackPublication(
* Will override previous calls to [setVideoDimensions].
*/
fun setVideoQuality(quality: LivekitModels.VideoQuality) {
if (isAutoManaged
|| !subscribed
|| quality == videoQuality
|| track !is VideoTrack
if (isAutoManaged ||
!subscribed ||
quality == videoQuality ||
track !is VideoTrack
) {
return
}
... ... @@ -171,10 +171,10 @@ class RemoteTrackPublication(
* Will override previous calls to [setVideoQuality].
*/
fun setVideoDimensions(dimensions: Track.Dimensions) {
if (isAutoManaged
|| !subscribed
|| videoDimensions == dimensions
|| track !is VideoTrack
if (isAutoManaged ||
!subscribed ||
videoDimensions == dimensions ||
track !is VideoTrack
) {
return
}
... ... @@ -188,10 +188,10 @@ class RemoteTrackPublication(
* Update the fps that the server will use for determining the video quality to send down.
*/
fun setVideoFps(fps: Int?) {
if (isAutoManaged
|| !subscribed
|| this.fps == fps
|| track !is VideoTrack
if (isAutoManaged ||
!subscribed ||
this.fps == fps ||
track !is VideoTrack
) {
return
}
... ... @@ -232,7 +232,7 @@ class RemoteTrackPublication(
disabled,
videoDimensions,
videoQuality,
fps
fps,
)
}
... ... @@ -250,6 +250,6 @@ class RemoteTrackPublication(
/**
* Not subscribed.
*/
UNSUBSCRIBED
UNSUBSCRIBED,
}
}
... ...
... ... @@ -25,7 +25,6 @@ import io.livekit.android.room.track.video.ViewVisibility
import io.livekit.android.util.LKLog
import kotlinx.coroutines.*
import org.webrtc.RtpReceiver
import org.webrtc.RtpTransceiver
import org.webrtc.VideoSink
import javax.inject.Named
import kotlin.math.max
... ...
... ... @@ -30,7 +30,7 @@ import org.webrtc.RTCStatsReport
abstract class Track(
name: String,
kind: Kind,
open val rtcTrack: MediaStreamTrack
open val rtcTrack: MediaStreamTrack,
) {
protected val eventBus = BroadcastEventBus<TrackEvent>()
val events = eventBus.readOnly()
... ... @@ -67,7 +67,8 @@ abstract class Track(
VIDEO("video"),
// unknown
UNRECOGNIZED("unrecognized");
UNRECOGNIZED("unrecognized"),
;
fun toProto(): LivekitModels.TrackType {
return when (this) {
... ... @@ -78,7 +79,7 @@ abstract class Track(
}
override fun toString(): String {
return value;
return value
}
companion object {
... ... @@ -96,8 +97,8 @@ abstract class Track(
CAMERA,
MICROPHONE,
SCREEN_SHARE,
UNKNOWN;
UNKNOWN,
;
fun toProto(): LivekitModels.TrackSource {
return when (this) {
... ... @@ -123,7 +124,8 @@ abstract class Track(
enum class StreamState {
ACTIVE,
PAUSED,
UNKNOWN;
UNKNOWN,
;
fun toProto(): LivekitRtc.StreamState {
return when (this) {
... ... @@ -159,7 +161,6 @@ abstract class Track(
}
}
sealed class TrackException(message: String? = null, cause: Throwable? = null) :
Exception(message, cause) {
class InvalidTrackTypeException(message: String? = null, cause: Throwable? = null) :
... ...
... ... @@ -21,7 +21,7 @@ import org.webrtc.VideoTrack
abstract class VideoTrack(name: String, override val rtcTrack: VideoTrack) :
Track(name, Kind.VIDEO, rtcTrack) {
protected val sinks: MutableList<VideoSink> = ArrayList();
protected val sinks: MutableList<VideoSink> = ArrayList()
var enabled: Boolean
get() = rtcTrack.enabled()
... ...
... ... @@ -67,7 +67,7 @@ open class ScreenCaptureService : Service() {
val channel = NotificationChannel(
DEFAULT_CHANNEL_ID,
"Screen Capture",
NotificationManager.IMPORTANCE_LOW
NotificationManager.IMPORTANCE_LOW,
)
val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
service.createNotificationChannel(channel)
... ... @@ -82,7 +82,6 @@ open class ScreenCaptureService : Service() {
return false
}
inner class ScreenCaptureBinder : Binder() {
val service: ScreenCaptureService
get() = this@ScreenCaptureService
... ...
... ... @@ -77,5 +77,4 @@ internal class CameraEventsDispatchHandler : CameraEventsHandler {
handler.onCameraClosed()
}
}
}
... ...
... ... @@ -31,7 +31,7 @@ internal interface VideoCapturerWithSize : VideoCapturer {
*/
internal abstract class CameraCapturerWithSize(
val cameraEventsDispatchHandler: CameraEventsDispatchHandler
val cameraEventsDispatchHandler: CameraEventsDispatchHandler,
) : VideoCapturerWithSize
/**
... ...
... ... @@ -40,7 +40,7 @@ internal object EncodingUtils {
VideoPreset169.H720,
VideoPreset169.H1080,
VideoPreset169.H1440,
VideoPreset169.H2160
VideoPreset169.H2160,
)
// Note: maintain order from smallest to biggest.
... ... @@ -82,7 +82,7 @@ internal object EncodingUtils {
fun videoLayersFromEncodings(
trackWidth: Int,
trackHeight: Int,
encodings: List<RtpParameters.Encoding>
encodings: List<RtpParameters.Encoding>,
): List<LivekitModels.VideoLayer> {
return if (encodings.isEmpty()) {
listOf(
... ... @@ -92,7 +92,7 @@ internal object EncodingUtils {
quality = LivekitModels.VideoQuality.HIGH
bitrate = 0
ssrc = 0
}.build()
}.build(),
)
} else {
encodings.map { encoding ->
... ...
... ... @@ -16,8 +16,6 @@
package io.livekit.android.room.util
import io.livekit.android.room.participant.Participant
import io.livekit.android.room.track.Track
import org.webrtc.DataChannel
fun DataChannel.unpackedTrackLabel(): Triple<String, String, String> {
... ...
... ... @@ -30,7 +30,6 @@ internal class NetworkMonitor(private val context: Context) {
coroutineContext = SupervisorJob() + Dispatchers.IO
scope = CoroutineScope(coroutineContext)
scope.launch {
val uid = context.packageManager.getApplicationInfo(context.packageName, 0).uid
var prevTxBytes = TrafficStats.getUidTxBytes(uid)
... ...
... ... @@ -21,7 +21,7 @@ import kotlinx.coroutines.*
fun <T, R> debounce(
waitMs: Long = 300L,
coroutineScope: CoroutineScope,
destinationFunction: suspend (T) -> R
destinationFunction: suspend (T) -> R,
): (T) -> Unit {
var debounceJob: Deferred<R>? = null
return { param: T ->
... ...
... ... @@ -34,7 +34,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
/**
* A little circuitous but the way this works is:
* 1. [delegateRequested] set to true indicates that [delegate] should be filled.
... ... @@ -74,7 +73,7 @@ annotation class FlowObservable
internal class MutableStateFlowDelegate<T>
internal constructor(
private val flow: MutableStateFlow<T>,
private val onSetValue: ((newValue: T, oldValue: T) -> Unit)? = null
private val onSetValue: ((newValue: T, oldValue: T) -> Unit)? = null,
) : MutableStateFlow<T> by flow {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
... ... @@ -94,7 +93,7 @@ internal constructor(
@FlowObservable
internal class StateFlowDelegate<T>
internal constructor(
private val flow: StateFlow<T>
private val flow: StateFlow<T>,
) : StateFlow<T> by flow {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
... ... @@ -107,13 +106,13 @@ internal constructor(
internal fun <T> flowDelegate(
initialValue: T,
onSetValue: ((newValue: T, oldValue: T) -> Unit)? = null
onSetValue: ((newValue: T, oldValue: T) -> Unit)? = null,
): MutableStateFlowDelegate<T> {
return MutableStateFlowDelegate(MutableStateFlow(initialValue), onSetValue)
}
internal fun <T> flowDelegate(
stateFlow: StateFlow<T>
stateFlow: StateFlow<T>,
): StateFlowDelegate<T> {
return StateFlowDelegate(stateFlow)
}
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.util
import io.livekit.android.util.LoggingLevel.*
... ... @@ -25,7 +41,6 @@ internal class LKLog {
companion object {
var loggingLevel = OFF
/** Log a verbose exception and a message that will be evaluated lazily when the message is printed */
@JvmStatic
inline fun v(t: Throwable? = null, message: () -> String) =
... ...
... ... @@ -25,7 +25,8 @@ enum class LoggingLevel {
WARN,
ERROR,
WTF,
OFF;
OFF,
;
fun toAndroidLogPriority(): Int {
return when (this) {
... ... @@ -39,4 +40,3 @@ enum class LoggingLevel {
}
}
}
... ...
... ... @@ -98,8 +98,8 @@ fun RTCStatsReport.getFilteredStats(trackIdentifier: String): RTCStatsReport {
codecIds,
localCandidateId,
remoteCandidateId,
statsMap
)
statsMap,
),
)
val filteredStatsMap: MutableMap<String, RTCStats> = HashMap()
for (stats in filteredStats) {
... ... @@ -120,7 +120,6 @@ private fun getTrackStats(trackIdentifier: String, statsMap: Map<String, RTCStat
return null
}
private fun getStreamStats(trackId: String, statsMap: Map<String, RTCStats>): RTCStats? {
for (stats in statsMap.values) {
if (stats.type == "stream") {
... ... @@ -141,7 +140,7 @@ private fun getExtraStats(
codecIds: Set<String?>,
localCandidateId: String?,
remoteCandidateId: String?,
statsMap: Map<String, RTCStats>
statsMap: Map<String, RTCStats>,
): Set<RTCStats> {
val extraStats: MutableSet<RTCStats> = HashSet()
for (stats in statsMap.values) {
... ... @@ -185,4 +184,3 @@ fun createStatsGetter(peerConnection: PeerConnection, receiver: RtpReceiver): RT
{ statsCallback: RTCStatsCollectorCallback ->
peerConnection.getStats(receiver, statsCallback)
}
... ...
/*
* Copyright 2023 LiveKit, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.livekit.android.webrtc
import io.livekit.android.util.LKLog
... ... @@ -25,7 +41,7 @@ limitations under the License.
open class SimulcastVideoEncoderFactoryWrapper(
sharedContext: EglBase.Context?,
enableIntelVp8Encoder: Boolean,
enableH264HighProfile: Boolean
enableH264HighProfile: Boolean,
) : VideoEncoderFactory {
/**
... ... @@ -72,7 +88,6 @@ open class SimulcastVideoEncoderFactoryWrapper(
supportedCodecInfos.addAll(hardwareVideoEncoderFactory.supportedCodecs)
return supportedCodecInfos.toTypedArray()
}
}
/**
... ... @@ -89,10 +104,11 @@ open class SimulcastVideoEncoderFactoryWrapper(
override fun initEncode(
settings: VideoEncoder.Settings,
callback: VideoEncoder.Callback?
callback: VideoEncoder.Callback?,
): VideoCodecStatus {
streamSettings = settings
val future = executor.submit(Callable {
val future = executor.submit(
Callable {
LKLog.i {
"""initEncode() thread=${Thread.currentThread().name} [${Thread.currentThread().id}]
| encoder=${encoder.implementationName}
... ... @@ -108,7 +124,8 @@ open class SimulcastVideoEncoderFactoryWrapper(
""".trimMargin()
}
return@Callable encoder.initEncode(settings, callback)
})
},
)
return future.get()
}
... ... @@ -119,10 +136,11 @@ open class SimulcastVideoEncoderFactoryWrapper(
override fun encode(
frame: VideoFrame,
encodeInfo: VideoEncoder.EncodeInfo?
encodeInfo: VideoEncoder.EncodeInfo?,
): VideoCodecStatus {
val future = executor.submit(Callable {
//LKLog.d { "encode() buffer=${frame.buffer}, thread=${Thread.currentThread().name} " +
val future = executor.submit(
Callable {
// LKLog.d { "encode() buffer=${frame.buffer}, thread=${Thread.currentThread().name} " +
// "[${Thread.currentThread().id}]" }
if (streamSettings == null) {
return@Callable encoder.encode(frame, encodeInfo)
... ... @@ -134,28 +152,35 @@ open class SimulcastVideoEncoderFactoryWrapper(
val originalBuffer = frame.buffer
// TODO: Do we need to handle when the scale factor is weird?
val adaptedBuffer = originalBuffer.cropAndScale(
0, 0, originalBuffer.width, originalBuffer.height,
streamSettings!!.width, streamSettings!!.height
0,
0,
originalBuffer.width,
originalBuffer.height,
streamSettings!!.width,
streamSettings!!.height,
)
val adaptedFrame = VideoFrame(adaptedBuffer, frame.rotation, frame.timestampNs)
val result = encoder.encode(adaptedFrame, encodeInfo)
adaptedBuffer.release()
return@Callable result
}
})
},
)
return future.get()
}
override fun setRateAllocation(
allocation: VideoEncoder.BitrateAllocation?,
frameRate: Int
frameRate: Int,
): VideoCodecStatus {
val future = executor.submit(Callable {
val future = executor.submit(
Callable {
return@Callable encoder.setRateAllocation(
allocation,
frameRate
frameRate,
)
},
)
})
return future.get()
}
... ... @@ -202,7 +227,7 @@ open class SimulcastVideoEncoderFactoryWrapper(
if (encoder == null) {
return null
}
if(encoder is WrappedNativeVideoEncoder){
if (encoder is WrappedNativeVideoEncoder) {
return encoder
}
return StreamEncoderWrapper(encoder)
... ... @@ -213,14 +238,15 @@ open class SimulcastVideoEncoderFactoryWrapper(
}
}
private val primary: VideoEncoderFactory
private val fallback: VideoEncoderFactory
private val native: SimulcastVideoEncoderFactory
init {
val hardwareVideoEncoderFactory = HardwareVideoEncoderFactory(
sharedContext, enableIntelVp8Encoder, enableH264HighProfile
sharedContext,
enableIntelVp8Encoder,
enableH264HighProfile,
)
primary = StreamEncoderWrapperFactory(hardwareVideoEncoderFactory)
fallback = StreamEncoderWrapperFactory(FallbackFactory(primary))
... ... @@ -234,5 +260,4 @@ open class SimulcastVideoEncoderFactoryWrapper(
override fun getSupportedCodecs(): Array<VideoCodecInfo> {
return native.supportedCodecs
}
}
... ...
... ... @@ -32,13 +32,13 @@ internal class Camera1Helper {
fun findClosestCaptureFormat(
cameraId: Int,
width: Int,
height: Int
height: Int,
): Size {
return CameraEnumerationAndroid.getClosestSupportedSize(
getSupportedFormats(cameraId)
.map { Size(it.width, it.height) },
width,
height
height,
)
}
}
... ...
... ... @@ -38,7 +38,7 @@ internal class Camera2Helper {
cameraManager: CameraManager,
cameraId: String?,
width: Int,
height: Int
height: Int,
): Size {
val sizes = getSupportedFormats(cameraManager, cameraId)
?.map { Size(it.width, it.height) }
... ...
... ... @@ -45,8 +45,7 @@ fun <T> Flow<T>.takeUntilSignal(signal: Flow<Unit?>): Flow<T> = flow {
emit(it)
}
}
} catch (e: CancellationException) {
//ignore
// ignore
}
}
... ...
... ... @@ -41,7 +41,7 @@ class TestCoroutineRule : TestRule {
dispatcher.scheduler.advanceUntilIdle() // run the remaining tasks
Assert.assertEquals(
timeAfterTest,
dispatcher.scheduler.currentTime
dispatcher.scheduler.currentTime,
) // will fail if there were tasks scheduled at a later moment
Dispatchers.resetMain()
}
... ...
... ... @@ -20,5 +20,5 @@ import kotlinx.coroutines.CoroutineScope
class EventCollector<T : Event>(
eventListenable: EventListenable<T>,
coroutineScope: CoroutineScope
coroutineScope: CoroutineScope,
) : FlowCollector<T>(eventListenable.events, coroutineScope)
... ...
... ... @@ -25,7 +25,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
open class FlowCollector<T>(
private val flow: Flow<T>,
coroutineScope: CoroutineScope
coroutineScope: CoroutineScope,
) {
private val signal = MutableStateFlow<Unit?>(null)
private val collectEventsDeferred = coroutineScope.async {
... ... @@ -40,5 +40,4 @@ open class FlowCollector<T>(
signal.compareAndSet(null, Unit)
return collectEventsDeferred.await()
}
}
... ...
... ... @@ -21,7 +21,7 @@ import android.view.Surface
import org.webrtc.EglBase
class MockEglBase(
private val eglContext: EglBase.Context = EglBase.Context { 0 }
private val eglContext: EglBase.Context = EglBase.Context { 0 },
) : EglBase {
override fun createSurface(p0: Surface?) {}
... ...
... ... @@ -21,7 +21,7 @@ import org.webrtc.MediaStream
import org.webrtc.VideoTrack
fun createMediaStreamId(participantSid: String, trackSid: String) =
"${participantSid}|${trackSid}"
"$participantSid|$trackSid"
class MockMediaStream(private val id: String = "id") : MediaStream(1L) {
... ...
... ... @@ -40,7 +40,7 @@ private class MockNativePeerConnectionFactory : NativePeerConnectionFactory {
class MockPeerConnection(
var rtcConfig: RTCConfiguration,
val observer: Observer?
val observer: Observer?,
) : PeerConnection(MockNativePeerConnectionFactory()) {
private var closed = false
... ... @@ -78,7 +78,6 @@ class MockPeerConnection(
observer?.onCreateSuccess(sdp)
}
override fun setAudioPlayout(playout: Boolean) {
}
... ... @@ -142,7 +141,7 @@ class MockPeerConnection(
override fun addTransceiver(
track: MediaStreamTrack,
init: RtpTransceiver.RtpTransceiverInit?
init: RtpTransceiver.RtpTransceiverInit?,
): RtpTransceiver {
val transceiver = MockRtpTransceiver.create(track, init ?: RtpTransceiver.RtpTransceiverInit())
transceivers.add(transceiver)
... ... @@ -155,7 +154,7 @@ class MockPeerConnection(
override fun addTransceiver(
mediaType: MediaStreamTrack.MediaType?,
init: RtpTransceiver.RtpTransceiverInit?
init: RtpTransceiver.RtpTransceiverInit?,
): RtpTransceiver {
return super.addTransceiver(mediaType, init)
}
... ...