davidliu
Committed by GitHub

Detect screenshare rotation (#552)

* Update gradle and build tools

* Update Kotlin to 1.9.25

* Add separate default capture/publish options for screenshare tracks

* Detect rotation for screenshare tracks

* spotless

* Update robolectric to 4.14.1
  1 +---
  2 +"client-sdk-android": minor
  3 +---
  4 +
  5 +Detect rotation for screenshare tracks
  1 +---
  2 +"client-sdk-android": patch
  3 +---
  4 +
  5 +Update Kotlin dependency to 1.9.25
  1 +---
  2 +"client-sdk-android": minor
  3 +---
  4 +
  5 +Add separate default capture/publish options for screenshare tracks
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4"> 2 <project version="4">
3 <component name="KotlinJpsPluginSettings"> 3 <component name="KotlinJpsPluginSettings">
4 - <option name="version" value="1.8.20" /> 4 + <option name="version" value="1.9.25" />
5 </component> 5 </component>
6 </project> 6 </project>
1 ext { 1 ext {
2 - android_build_tools_version = '8.2.2' 2 + android_build_tools_version = '8.7.2'
3 compose_version = '1.2.1' 3 compose_version = '1.2.1'
4 - compose_compiler_version = '1.4.5'  
5 - kotlin_version = '1.8.20' 4 + compose_compiler_version = '1.5.15'
  5 + kotlin_version = '1.9.25'
6 java_version = JavaVersion.VERSION_1_8 6 java_version = JavaVersion.VERSION_1_8
7 - dokka_version = '1.8.20' 7 + dokka_version = '1.9.20'
8 androidSdk = [ 8 androidSdk = [
9 - compileVersion: 34,  
10 - targetVersion : 34, 9 + compileVersion: 35,
  10 + targetVersion : 35,
11 minVersion : 21, 11 minVersion : 21,
12 ] 12 ]
13 generated = [ 13 generated = [
@@ -92,7 +92,7 @@ mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "4.1. @@ -92,7 +92,7 @@ mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version = "4.1.
92 #noinspection GradleDependency 92 #noinspection GradleDependency
93 mockito-inline = { module = "org.mockito:mockito-inline", version = "4.11.0" } 93 mockito-inline = { module = "org.mockito:mockito-inline", version = "4.11.0" }
94 94
95 -robolectric = { module = "org.robolectric:robolectric", version = "4.11.1" } 95 +robolectric = { module = "org.robolectric:robolectric", version = "4.14.1" }
96 turbine = { module = "app.cash.turbine:turbine", version = "1.0.0" } 96 turbine = { module = "app.cash.turbine:turbine", version = "1.0.0" }
97 appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } 97 appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
98 material = { group = "com.google.android.material", name = "material", version.ref = "material" } 98 material = { group = "com.google.android.material", name = "material", version.ref = "material" }
1 #Mon May 01 22:58:53 JST 2023 1 #Mon May 01 22:58:53 JST 2023
2 distributionBase=GRADLE_USER_HOME 2 distributionBase=GRADLE_USER_HOME
3 distributionPath=wrapper/dists 3 distributionPath=wrapper/dists
4 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip 4 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
5 zipStoreBase=GRADLE_USER_HOME 5 zipStoreBase=GRADLE_USER_HOME
6 zipStorePath=wrapper/dists 6 zipStorePath=wrapper/dists
@@ -52,8 +52,9 @@ android { @@ -52,8 +52,9 @@ android {
52 targetCompatibility java_version 52 targetCompatibility java_version
53 } 53 }
54 packagingOptions { 54 packagingOptions {
55 - // Exclude our protos from being included in the final aar.  
56 - exclude "**/*.proto" 55 + resources {
  56 + excludes += ['**/*.proto']
  57 + }
57 } 58 }
58 59
59 buildFeatures { 60 buildFeatures {
@@ -43,4 +43,6 @@ data class RoomOptions( @@ -43,4 +43,6 @@ data class RoomOptions(
43 val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null, 43 val videoTrackCaptureDefaults: LocalVideoTrackOptions? = null,
44 val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null, 44 val audioTrackPublishDefaults: AudioTrackPublishDefaults? = null,
45 val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null, 45 val videoTrackPublishDefaults: VideoTrackPublishDefaults? = null,
  46 + val screenShareTrackCaptureDefaults: LocalVideoTrackOptions? = null,
  47 + val screenShareTrackPublishDefaults: VideoTrackPublishDefaults? = null,
46 ) 48 )
1 /* 1 /*
2 - * Copyright 2023 LiveKit, Inc. 2 + * Copyright 2023-2024 LiveKit, Inc.
3 * 3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import io.livekit.android.room.participant.AudioTrackPublishDefaults @@ -20,6 +20,7 @@ import io.livekit.android.room.participant.AudioTrackPublishDefaults
20 import io.livekit.android.room.participant.VideoTrackPublishDefaults 20 import io.livekit.android.room.participant.VideoTrackPublishDefaults
21 import io.livekit.android.room.track.LocalAudioTrackOptions 21 import io.livekit.android.room.track.LocalAudioTrackOptions
22 import io.livekit.android.room.track.LocalVideoTrackOptions 22 import io.livekit.android.room.track.LocalVideoTrackOptions
  23 +import io.livekit.android.room.track.ScreenSharePresets
23 import javax.inject.Inject 24 import javax.inject.Inject
24 import javax.inject.Singleton 25 import javax.inject.Singleton
25 26
@@ -31,4 +32,6 @@ constructor() { @@ -31,4 +32,6 @@ constructor() {
31 var audioTrackPublishDefaults: AudioTrackPublishDefaults = AudioTrackPublishDefaults() 32 var audioTrackPublishDefaults: AudioTrackPublishDefaults = AudioTrackPublishDefaults()
32 var videoTrackCaptureDefaults: LocalVideoTrackOptions = LocalVideoTrackOptions() 33 var videoTrackCaptureDefaults: LocalVideoTrackOptions = LocalVideoTrackOptions()
33 var videoTrackPublishDefaults: VideoTrackPublishDefaults = VideoTrackPublishDefaults() 34 var videoTrackPublishDefaults: VideoTrackPublishDefaults = VideoTrackPublishDefaults()
  35 + var screenShareTrackCaptureDefaults: LocalVideoTrackOptions = LocalVideoTrackOptions(isScreencast = true, captureParams = ScreenSharePresets.ORIGINAL.capture)
  36 + var screenShareTrackPublishDefaults: VideoTrackPublishDefaults = VideoTrackPublishDefaults(videoEncoding = ScreenSharePresets.ORIGINAL.encoding)
34 } 37 }
@@ -251,6 +251,16 @@ constructor( @@ -251,6 +251,16 @@ constructor(
251 */ 251 */
252 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults 252 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults
253 253
  254 + /**
  255 + * Default options to use when creating a screen share track.
  256 + */
  257 + var screenShareTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::screenShareTrackCaptureDefaults
  258 +
  259 + /**
  260 + * Default options to use when publishing a screen share track.
  261 + */
  262 + var screenShareTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::screenShareTrackPublishDefaults
  263 +
254 val localParticipant: LocalParticipant = localParticipantFactory.create(dynacast = false).apply { 264 val localParticipant: LocalParticipant = localParticipantFactory.create(dynacast = false).apply {
255 internalListener = this@Room 265 internalListener = this@Room
256 } 266 }
@@ -285,11 +295,13 @@ constructor( @@ -285,11 +295,13 @@ constructor(
285 RoomOptions( 295 RoomOptions(
286 adaptiveStream = adaptiveStream, 296 adaptiveStream = adaptiveStream,
287 dynacast = dynacast, 297 dynacast = dynacast,
  298 + e2eeOptions = e2eeOptions,
288 audioTrackCaptureDefaults = audioTrackCaptureDefaults, 299 audioTrackCaptureDefaults = audioTrackCaptureDefaults,
289 videoTrackCaptureDefaults = videoTrackCaptureDefaults, 300 videoTrackCaptureDefaults = videoTrackCaptureDefaults,
290 audioTrackPublishDefaults = audioTrackPublishDefaults, 301 audioTrackPublishDefaults = audioTrackPublishDefaults,
291 videoTrackPublishDefaults = videoTrackPublishDefaults, 302 videoTrackPublishDefaults = videoTrackPublishDefaults,
292 - e2eeOptions = e2eeOptions, 303 + screenShareTrackCaptureDefaults = screenShareTrackCaptureDefaults,
  304 + screenShareTrackPublishDefaults = screenShareTrackPublishDefaults,
293 ) 305 )
294 306
295 /** 307 /**
@@ -502,6 +514,12 @@ constructor( @@ -502,6 +514,12 @@ constructor(
502 options.videoTrackPublishDefaults?.let { 514 options.videoTrackPublishDefaults?.let {
503 videoTrackPublishDefaults = it 515 videoTrackPublishDefaults = it
504 } 516 }
  517 + options.screenShareTrackCaptureDefaults?.let {
  518 + screenShareTrackCaptureDefaults = it
  519 + }
  520 + options.screenShareTrackPublishDefaults?.let {
  521 + screenShareTrackPublishDefaults = it
  522 + }
505 adaptiveStream = options.adaptiveStream 523 adaptiveStream = options.adaptiveStream
506 dynacast = options.dynacast 524 dynacast = options.dynacast
507 e2eeOptions = options.e2eeOptions 525 e2eeOptions = options.e2eeOptions
@@ -93,6 +93,8 @@ internal constructor( @@ -93,6 +93,8 @@ internal constructor(
93 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults 93 var audioTrackPublishDefaults: AudioTrackPublishDefaults by defaultsManager::audioTrackPublishDefaults
94 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults 94 var videoTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::videoTrackCaptureDefaults
95 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults 95 var videoTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::videoTrackPublishDefaults
  96 + var screenShareTrackCaptureDefaults: LocalVideoTrackOptions by defaultsManager::screenShareTrackCaptureDefaults
  97 + var screenShareTrackPublishDefaults: VideoTrackPublishDefaults by defaultsManager::screenShareTrackPublishDefaults
96 98
97 private var republishes: List<LocalTrackPublication>? = null 99 private var republishes: List<LocalTrackPublication>? = null
98 private val localTrackPublications 100 private val localTrackPublications
@@ -181,13 +183,13 @@ internal constructor( @@ -181,13 +183,13 @@ internal constructor(
181 * @param name The name of the track. 183 * @param name The name of the track.
182 * @param mediaProjectionPermissionResultData The resultData returned from launching 184 * @param mediaProjectionPermissionResultData The resultData returned from launching
183 * [MediaProjectionManager.createScreenCaptureIntent()](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#createScreenCaptureIntent()). 185 * [MediaProjectionManager.createScreenCaptureIntent()](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#createScreenCaptureIntent()).
184 - * @param options The capture options to use for this track, or [Room.videoTrackCaptureDefaults] if none is passed. 186 + * @param options The capture options to use for this track, or [Room.screenShareTrackCaptureDefaults] if none is passed.
185 * @param videoProcessor A video processor to attach to this track that can modify the frames before publishing. 187 * @param videoProcessor A video processor to attach to this track that can modify the frames before publishing.
186 */ 188 */
187 fun createScreencastTrack( 189 fun createScreencastTrack(
188 name: String = "", 190 name: String = "",
189 mediaProjectionPermissionResultData: Intent, 191 mediaProjectionPermissionResultData: Intent,
190 - options: LocalVideoTrackOptions = videoTrackCaptureDefaults.copy(), 192 + options: LocalVideoTrackOptions = screenShareTrackCaptureDefaults.copy(),
191 videoProcessor: VideoProcessor? = null, 193 videoProcessor: VideoProcessor? = null,
192 ): LocalScreencastVideoTrack { 194 ): LocalScreencastVideoTrack {
193 val screencastOptions = options.copy(isScreencast = true) 195 val screencastOptions = options.copy(isScreencast = true)
@@ -249,8 +251,8 @@ internal constructor( @@ -249,8 +251,8 @@ internal constructor(
249 * @param mediaProjectionPermissionResultData The resultData returned from launching 251 * @param mediaProjectionPermissionResultData The resultData returned from launching
250 * [MediaProjectionManager.createScreenCaptureIntent()](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#createScreenCaptureIntent()). 252 * [MediaProjectionManager.createScreenCaptureIntent()](https://developer.android.com/reference/android/media/projection/MediaProjectionManager#createScreenCaptureIntent()).
251 * @throws IllegalArgumentException if attempting to enable screenshare without [mediaProjectionPermissionResultData] 253 * @throws IllegalArgumentException if attempting to enable screenshare without [mediaProjectionPermissionResultData]
252 - * @see Room.videoTrackCaptureDefaults  
253 - * @see Room.videoTrackPublishDefaults 254 + * @see Room.screenShareTrackCaptureDefaults
  255 + * @see Room.screenShareTrackPublishDefaults
254 */ 256 */
255 suspend fun setScreenShareEnabled( 257 suspend fun setScreenShareEnabled(
256 enabled: Boolean, 258 enabled: Boolean,
@@ -294,7 +296,7 @@ internal constructor( @@ -294,7 +296,7 @@ internal constructor(
294 createScreencastTrack(mediaProjectionPermissionResultData = mediaProjectionPermissionResultData) 296 createScreencastTrack(mediaProjectionPermissionResultData = mediaProjectionPermissionResultData)
295 track.startForegroundService(null, null) 297 track.startForegroundService(null, null)
296 track.startCapture() 298 track.startCapture()
297 - publishVideoTrack(track) 299 + publishVideoTrack(track, options = VideoTrackPublishOptions(null, screenShareTrackPublishDefaults))
298 } 300 }
299 301
300 else -> { 302 else -> {
@@ -22,15 +22,35 @@ import android.app.NotificationManager @@ -22,15 +22,35 @@ import android.app.NotificationManager
22 import android.content.Context 22 import android.content.Context
23 import android.content.Intent 23 import android.content.Intent
24 import android.media.projection.MediaProjection 24 import android.media.projection.MediaProjection
  25 +import android.util.DisplayMetrics
  26 +import android.view.OrientationEventListener
  27 +import android.view.WindowManager
25 import dagger.assisted.Assisted 28 import dagger.assisted.Assisted
26 import dagger.assisted.AssistedFactory 29 import dagger.assisted.AssistedFactory
27 import dagger.assisted.AssistedInject 30 import dagger.assisted.AssistedInject
28 import io.livekit.android.room.DefaultsManager 31 import io.livekit.android.room.DefaultsManager
  32 +import io.livekit.android.room.participant.LocalParticipant
29 import io.livekit.android.room.track.screencapture.ScreenCaptureConnection 33 import io.livekit.android.room.track.screencapture.ScreenCaptureConnection
30 import io.livekit.android.room.track.screencapture.ScreenCaptureService 34 import io.livekit.android.room.track.screencapture.ScreenCaptureService
31 -import livekit.org.webrtc.*  
32 -import java.util.* 35 +import io.livekit.android.util.LKLog
  36 +import livekit.org.webrtc.EglBase
  37 +import livekit.org.webrtc.PeerConnectionFactory
  38 +import livekit.org.webrtc.ScreenCapturerAndroid
  39 +import livekit.org.webrtc.SurfaceTextureHelper
  40 +import livekit.org.webrtc.VideoCapturer
  41 +import livekit.org.webrtc.VideoProcessor
  42 +import livekit.org.webrtc.VideoSource
  43 +import java.util.UUID
33 44
  45 +/**
  46 + * A video track that captures the screen for publishing.
  47 + *
  48 + * Note: A foreground service is generally required for use. Use [startForegroundService] or start
  49 + * your own foreground service before starting the video track.
  50 + *
  51 + * @see LocalParticipant.createScreencastTrack
  52 + * @see LocalScreencastVideoTrack.startForegroundService
  53 + */
34 class LocalScreencastVideoTrack 54 class LocalScreencastVideoTrack
35 @AssistedInject 55 @AssistedInject
36 constructor( 56 constructor(
@@ -58,6 +78,76 @@ constructor( @@ -58,6 +78,76 @@ constructor(
58 videoTrackFactory, 78 videoTrackFactory,
59 ) { 79 ) {
60 80
  81 + private var prevDisplayWidth = 0
  82 + private var prevDisplayHeight = 0
  83 + private val displayMetrics = DisplayMetrics()
  84 + private val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
  85 + private val orientationEventListener = object : OrientationEventListener(context) {
  86 + override fun onOrientationChanged(orientation: Int) {
  87 + if (isDisposed) {
  88 + this.disable()
  89 + return
  90 + }
  91 + updateCaptureFormatIfNeeded()
  92 + }
  93 + }
  94 +
  95 + private fun getCaptureDimensions(displayWidth: Int, displayHeight: Int): Pair<Int, Int> {
  96 + val captureWidth: Int
  97 + val captureHeight: Int
  98 +
  99 + if (options.captureParams.width == 0 && options.captureParams.height == 0) {
  100 + // Use raw display size
  101 + captureWidth = displayWidth
  102 + captureHeight = displayHeight
  103 + } else {
  104 + // Use captureParams.width as longest side and captureParams.height as shortest side.
  105 + if (displayWidth > displayHeight) {
  106 + captureWidth = options.captureParams.width
  107 + captureHeight = options.captureParams.height
  108 + } else {
  109 + captureWidth = options.captureParams.height
  110 + captureHeight = options.captureParams.width
  111 + }
  112 + }
  113 +
  114 + return captureWidth to captureHeight
  115 + }
  116 +
  117 + private fun updateCaptureFormatIfNeeded() {
  118 + windowManager.defaultDisplay.getRealMetrics(displayMetrics)
  119 + val displayWidth = displayMetrics.widthPixels
  120 + val displayHeight = displayMetrics.heightPixels
  121 +
  122 + // Updates whenever the display rotates
  123 + if (displayWidth != prevDisplayWidth || displayHeight != prevDisplayHeight) {
  124 + prevDisplayWidth = displayWidth
  125 + prevDisplayHeight = displayHeight
  126 +
  127 + val (captureWidth, captureHeight) = getCaptureDimensions(displayWidth, displayHeight)
  128 +
  129 + try {
  130 + capturer.changeCaptureFormat(captureWidth, captureHeight, options.captureParams.maxFps)
  131 + } catch (e: Exception) {
  132 + LKLog.w(e) { "Exception when changing capture format of the screen share track." }
  133 + }
  134 + }
  135 + }
  136 +
  137 + override fun startCapture() {
  138 + // Don't use super.startCapture, must calculate correct dimensions
  139 + windowManager.defaultDisplay.getRealMetrics(displayMetrics)
  140 + val displayWidth = displayMetrics.widthPixels
  141 + val displayHeight = displayMetrics.heightPixels
  142 + val (captureWidth, captureHeight) = getCaptureDimensions(displayWidth, displayHeight)
  143 +
  144 + capturer.startCapture(captureWidth, captureHeight, options.captureParams.maxFps)
  145 +
  146 + if (orientationEventListener.canDetectOrientation()) {
  147 + orientationEventListener.enable()
  148 + }
  149 + }
  150 +
61 private val serviceConnection = ScreenCaptureConnection(context) 151 private val serviceConnection = ScreenCaptureConnection(context)
62 152
63 init { 153 init {
@@ -95,6 +185,7 @@ constructor( @@ -95,6 +185,7 @@ constructor(
95 override fun stop() { 185 override fun stop() {
96 super.stop() 186 super.stop()
97 serviceConnection.stop() 187 serviceConnection.stop()
  188 + orientationEventListener.disable()
98 } 189 }
99 190
100 @AssistedFactory 191 @AssistedFactory
@@ -129,7 +220,7 @@ constructor( @@ -129,7 +220,7 @@ constructor(
129 options: LocalVideoTrackOptions, 220 options: LocalVideoTrackOptions,
130 rootEglBase: EglBase, 221 rootEglBase: EglBase,
131 screencastVideoTrackFactory: Factory, 222 screencastVideoTrackFactory: Factory,
132 - videoProcessor: VideoProcessor? 223 + videoProcessor: VideoProcessor?,
133 ): LocalScreencastVideoTrack { 224 ): LocalScreencastVideoTrack {
134 val source = peerConnectionFactory.createVideoSource(options.isScreencast) 225 val source = peerConnectionFactory.createVideoSource(options.isScreencast)
135 source.setVideoProcessor(videoProcessor) 226 source.setVideoProcessor(videoProcessor)
@@ -172,3 +172,48 @@ enum class VideoPreset43( @@ -172,3 +172,48 @@ enum class VideoPreset43(
172 VideoEncoding(3_800_000, 30), 172 VideoEncoding(3_800_000, 30),
173 ), 173 ),
174 } 174 }
  175 +
  176 +/**
  177 + * 16:9 Video presets along with suggested bitrates.
  178 + */
  179 +enum class ScreenSharePresets(
  180 + override val capture: VideoCaptureParameter,
  181 + override val encoding: VideoEncoding,
  182 +) : VideoPreset {
  183 + H360_FPS3(
  184 + VideoCaptureParameter(640, 360, 3),
  185 + VideoEncoding(200_000, 3),
  186 + ),
  187 + H360_FPS15(
  188 + VideoCaptureParameter(640, 360, 15),
  189 + VideoEncoding(400_000, 15),
  190 + ),
  191 + H720_FPS5(
  192 + VideoCaptureParameter(1280, 720, 5),
  193 + VideoEncoding(800_000, 5),
  194 + ),
  195 + H720_FPS15(
  196 + VideoCaptureParameter(1280, 720, 15),
  197 + VideoEncoding(1_500_000, 15),
  198 + ),
  199 + H720_FPS30(
  200 + VideoCaptureParameter(1280, 720, 30),
  201 + VideoEncoding(2_000_000, 30),
  202 + ),
  203 + H1080_FPS15(
  204 + VideoCaptureParameter(1920, 1080, 15),
  205 + VideoEncoding(2_500_000, 15),
  206 + ),
  207 + H1080_FPS30(
  208 + VideoCaptureParameter(1920, 1080, 30),
  209 + VideoEncoding(5_000_000, 30),
  210 + ),
  211 +
  212 + /**
  213 + * Uses the original resolution without resizing.
  214 + */
  215 + ORIGINAL(
  216 + VideoCaptureParameter(0, 0, 30),
  217 + VideoEncoding(7_000_000, 30),
  218 + )
  219 +}
@@ -17,9 +17,6 @@ android { @@ -17,9 +17,6 @@ android {
17 consumerProguardFiles "consumer-rules.pro" 17 consumerProguardFiles "consumer-rules.pro"
18 } 18 }
19 19
20 - lintOptions {  
21 - disable 'VisibleForTests'  
22 - }  
23 buildTypes { 20 buildTypes {
24 release { 21 release {
25 minifyEnabled false 22 minifyEnabled false
@@ -39,6 +36,9 @@ android { @@ -39,6 +36,9 @@ android {
39 includeAndroidResources = true 36 includeAndroidResources = true
40 } 37 }
41 } 38 }
  39 + lint {
  40 + disable 'VisibleForTests'
  41 + }
42 } 42 }
43 43
44 dokkaHtml { 44 dokkaHtml {
@@ -39,15 +39,19 @@ class MockAudioProcessingController : AudioProcessingController { @@ -39,15 +39,19 @@ class MockAudioProcessingController : AudioProcessingController {
39 @get:FlowObservable 39 @get:FlowObservable
40 override var bypassCapturePostProcessing: Boolean by flowDelegate(false) 40 override var bypassCapturePostProcessing: Boolean by flowDelegate(false)
41 41
  42 + @Deprecated("Use the capturePostProcessing variable directly instead")
42 override fun setCapturePostProcessing(processing: AudioProcessorInterface?) { 43 override fun setCapturePostProcessing(processing: AudioProcessorInterface?) {
43 } 44 }
44 45
  46 + @Deprecated("Use the bypassCapturePostProcessing variable directly instead")
45 override fun setBypassForCapturePostProcessing(bypass: Boolean) { 47 override fun setBypassForCapturePostProcessing(bypass: Boolean) {
46 } 48 }
47 49
  50 + @Deprecated("Use the renderPreProcessing variable directly instead")
48 override fun setRenderPreProcessing(processing: AudioProcessorInterface?) { 51 override fun setRenderPreProcessing(processing: AudioProcessorInterface?) {
49 } 52 }
50 53
  54 + @Deprecated("Use the bypassRendererPreProcessing variable directly instead")
51 override fun setBypassForRenderPreProcessing(bypass: Boolean) { 55 override fun setBypassForRenderPreProcessing(bypass: Boolean) {
52 } 56 }
53 } 57 }