diff --git a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/pipelines/StreamerPipelineFileTest.kt b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/pipelines/StreamerPipelineFileTest.kt index 36992df8f..6907d02e1 100644 --- a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/pipelines/StreamerPipelineFileTest.kt +++ b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/pipelines/StreamerPipelineFileTest.kt @@ -40,6 +40,7 @@ import org.junit.Assert.assertTrue import org.junit.Test import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @OptIn(InternalStreamPackApi::class) @LargeTest @@ -62,7 +63,7 @@ class StreamerPipelineFileTest : DeviceTest() { } @Test - fun testAudioOrVideoStream() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds) { + fun testAudioOrVideoStream() = runTest(timeout = TEST_TIMEOUT) { // Add sources streamerPipeline.setAudioSource(MicrophoneSourceFactory()) streamerPipeline.setVideoSource(CameraSourceFactory(context)) @@ -93,8 +94,8 @@ class StreamerPipelineFileTest : DeviceTest() { } videoOnlyOutput.startStream(videoOnlyDescriptor) - val duration: Duration = STREAM_DURATION_MS.milliseconds - val pollDuration: Duration = STREAM_POLLING_MS.milliseconds + val duration: Duration = STREAM_DURATION + val pollDuration: Duration = STREAM_POLLING var i = 0 val numOfLoop = duration / pollDuration @@ -133,9 +134,9 @@ class StreamerPipelineFileTest : DeviceTest() { companion object { private const val TAG = "StreamerPipelineFileTest" - private const val TEST_TIMEOUT_MS = 60_000L - private const val STREAM_DURATION_MS = 30_000L - private const val STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 60.seconds + private val STREAM_DURATION = 30.seconds + private val STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 1280 private const val VIDEO_HEIGHT = 720 diff --git a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/dual/file/CameraDualStreamerFileTest.kt b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/dual/file/CameraDualStreamerFileTest.kt index 0c4cefd2a..7d2891f3d 100644 --- a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/dual/file/CameraDualStreamerFileTest.kt +++ b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/dual/file/CameraDualStreamerFileTest.kt @@ -38,6 +38,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @LargeTest @RunWith(Parameterized::class) @@ -92,7 +93,7 @@ class CameraDualStreamerFileTest( } @Test - fun writeToFile() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds) { + fun writeToFile() = runTest(timeout = TEST_TIMEOUT) { // Configure streamer.setConfig( audioConfig, videoConfig @@ -103,8 +104,8 @@ class CameraDualStreamerFileTest( streamer, firstDescriptor, secondDescriptor, - STREAM_DURATION_MS.milliseconds, - STREAM_POLLING_MS.milliseconds + STREAM_DURATION, + STREAM_POLLING ) streamer.release() @@ -128,9 +129,9 @@ class CameraDualStreamerFileTest( companion object { private const val TAG = "CameraDualStrFileTest" - private const val TEST_TIMEOUT_MS = 60_000L - private const val STREAM_DURATION_MS = 30_000L - private const val STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 60.seconds + private val STREAM_DURATION = 30.seconds + private val STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 640 private const val VIDEO_HEIGHT = 360 diff --git a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerFileTest.kt b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerFileTest.kt index 81ecbae84..866aecda9 100644 --- a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerFileTest.kt +++ b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerFileTest.kt @@ -37,7 +37,7 @@ import org.junit.After import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.Parameterized -import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @LargeTest @RunWith(Parameterized::class) @@ -76,7 +76,7 @@ class CameraSingleStreamerFileTest( } @Test - fun writeToFile() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds) { + fun writeToFile() = runTest(timeout = TEST_TIMEOUT) { // Run stream streamer.setConfig( audioConfig, @@ -87,8 +87,8 @@ class CameraSingleStreamerFileTest( StreamerUtils.runSingleStream( streamer, descriptor, - STREAM_DURATION_MS.milliseconds, - STREAM_POLLING_MS.milliseconds + STREAM_DURATION, + STREAM_POLLING ) streamer.release() @@ -105,9 +105,9 @@ class CameraSingleStreamerFileTest( companion object { private const val TAG = "CameraSinStrFileTest" - private const val TEST_TIMEOUT_MS = 60_000L - private const val STREAM_DURATION_MS = 30_000L - private const val STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 60.seconds + private val STREAM_DURATION = 30.seconds + private val STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 640 private const val VIDEO_HEIGHT = 360 diff --git a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerMultiEndpointTest.kt b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerMultiEndpointTest.kt index 34da1422f..7326760f1 100644 --- a/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerMultiEndpointTest.kt +++ b/core/src/androidTest/java/io/github/thibaultbee/streampack/core/streamer/single/file/CameraSingleStreamerMultiEndpointTest.kt @@ -35,6 +35,7 @@ import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Test import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds /** * Test [cameraSingleStreamer] with multiple endpoint. @@ -61,7 +62,7 @@ class CameraSingleStreamerMultiEndpointTest : DeviceTest() { } @Test - fun writeToEndpoints() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds * descriptors.size) { + fun writeToEndpoints() = runTest(timeout = TEST_TIMEOUT * descriptors.size) { val audioConfig = AudioConfig() val videoConfig = VideoConfig(resolution = Size(VIDEO_WIDTH, VIDEO_HEIGHT)) @@ -94,8 +95,8 @@ class CameraSingleStreamerMultiEndpointTest : DeviceTest() { StreamerUtils.runSingleStream( streamer, descriptor, - STREAM_DURATION_MS.milliseconds, - STREAM_POLLING_MS.milliseconds + STREAM_DURATION, + STREAM_POLLING ) // Check file @@ -122,9 +123,9 @@ class CameraSingleStreamerMultiEndpointTest : DeviceTest() { companion object { private const val TAG = "MultiEndpointTest" - private const val TEST_TIMEOUT_MS = 40_000L - private const val STREAM_DURATION_MS = 20_000L - private const val STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 40.seconds + private val STREAM_DURATION = 20.seconds + private val STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 1280 private const val VIDEO_HEIGHT = 720 diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSettings.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSettings.kt index 88da01cd2..ec8c0a73c 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSettings.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/elements/sources/video/camera/CameraSettings.kt @@ -62,6 +62,8 @@ import io.github.thibaultbee.streampack.core.elements.utils.extensions.isNormali import io.github.thibaultbee.streampack.core.elements.utils.extensions.launchIn import io.github.thibaultbee.streampack.core.elements.utils.extensions.rotate import io.github.thibaultbee.streampack.core.logger.Logger +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job @@ -1262,7 +1264,7 @@ class CameraSettings internal constructor( afRectangles: List, aeRectangles: List, awbRectangles: List, - timeoutDurationMs: Long + timeoutDuration: Duration ) { disableAutoCancel() @@ -1284,9 +1286,9 @@ class CameraSettings internal constructor( addFocusMetering(afRectangles, aeRectangles, awbRectangles) - // Auto cancel AF trigger after timeoutDurationMs - if (timeoutDurationMs > 0) { - autoCancelHandle = coroutineScope.launchIn(timeoutDurationMs) + // Auto cancel AF trigger after timeoutDuration + if (timeoutDuration.isPositive()) { + autoCancelHandle = coroutineScope.launchIn(timeoutDuration) { autoCancelHandle = null try { @@ -1308,7 +1310,7 @@ class CameraSettings internal constructor( aePoints: List, awbPoints: List, fovAspectRatio: Rational, - timeoutDurationMs: Long + timeoutDuration: Duration ) { val cropRegion = zoom.getCropSensorRegion() @@ -1330,7 +1332,7 @@ class CameraSettings internal constructor( "At least one of AF, AE, AWB rectangles must be non empty" } - executeMetering(afRectangles, aeRectangles, awbRectangles, timeoutDurationMs) + executeMetering(afRectangles, aeRectangles, awbRectangles, timeoutDuration) } private fun disableAutoCancel() { @@ -1429,14 +1431,14 @@ class CameraSettings internal constructor( * @param point the point to focus * @param factory the factory to normalize the view points * @param viewRotationDegree the orientation of the field of view - * @param timeoutDurationMs duration in milliseconds after which the focus and metering will be cancelled automatically + * @param timeoutDuration duration after which the focus and metering will be cancelled automatically */ @RequiresPermission(Manifest.permission.CAMERA) suspend fun tapToFocus( point: PointF, factory: MeteringPointFactory, viewRotationDegree: Int, - timeoutDurationMs: Long + timeoutDuration: Duration ) { val points = listOf(point) return onTap( @@ -1445,7 +1447,7 @@ class CameraSettings internal constructor( emptyList(), factory, viewRotationDegree, - timeoutDurationMs + timeoutDuration ) } @@ -1459,7 +1461,7 @@ class CameraSettings internal constructor( * @param awbPoints the points where the white balance is done * @param factory the factory to normalize the view points * @param viewRotationDegree the orientation of the view - * @param timeoutDurationMs duration in milliseconds after which the focus and metering will be cancelled automatically + * @param timeoutDuration duration after which the focus and metering will be cancelled automatically */ @RequiresPermission(Manifest.permission.CAMERA) suspend fun onTap( @@ -1468,7 +1470,7 @@ class CameraSettings internal constructor( awbPoints: List, factory: MeteringPointFactory, viewRotationDegree: Int, - timeoutDurationMs: Long = DEFAULT_AUTO_CANCEL_DURATION_MS + timeoutDuration: Duration = DEFAULT_AUTO_CANCEL_DURATION ) { val relativeRotation = getSensorRotationDegrees( @@ -1483,7 +1485,7 @@ class CameraSettings internal constructor( aePoints.map { normalizePoint(it, factory, relativeRotation, isFrontCamera) }, awbPoints.map { normalizePoint(it, factory, relativeRotation, isFrontCamera) }, Rational(1, 1), - timeoutDurationMs + timeoutDuration ) } @@ -1502,7 +1504,7 @@ class CameraSettings internal constructor( private const val DEFAULT_AE_SIZE = DEFAULT_AF_SIZE * 1.5f private const val DEFAULT_METERING_WEIGHT_MAX = MeteringRectangle.METERING_WEIGHT_MAX - const val DEFAULT_AUTO_CANCEL_DURATION_MS = 5000L + val DEFAULT_AUTO_CANCEL_DURATION = 5000.milliseconds private fun getPreferredAFMode( characteristics: CameraCharacteristics, preferredMode: Int diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/elements/utils/extensions/CoroutineScopeExtensions.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/elements/utils/extensions/CoroutineScopeExtensions.kt index c48adf146..92f412061 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/elements/utils/extensions/CoroutineScopeExtensions.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/elements/utils/extensions/CoroutineScopeExtensions.kt @@ -21,15 +21,14 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext -import kotlin.time.Duration.Companion.milliseconds - +import kotlin.time.Duration fun CoroutineScope.launchIn( - delayTimeInMs: Long, + delayTime: Duration, context: CoroutineContext = EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ) = launch(context, start) { - delay(delayTimeInMs.milliseconds) + delay(delayTime) block() } \ No newline at end of file diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/interfaces/ISource.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/interfaces/ISource.kt index 81440c51f..3d0302b4f 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/interfaces/ISource.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/interfaces/ISource.kt @@ -79,25 +79,25 @@ interface IWithVideoSource { } /** - * Sets the [cameraId] as the new video source. + * Sets the camera [cameraId] as the new video source. * * Same as [IWithVideoSource.setVideoSource] with a [CameraSourceFactory]. * * @param cameraId the camera id */ @RequiresPermission(Manifest.permission.CAMERA) -suspend fun IWithVideoSource.setCameraId(cameraId: String) { +suspend fun IWithVideoSource.setCameraSource(cameraId: String) { setVideoSource(CameraSourceFactory(cameraId)) } /** * Sets the [Bitmap] as the new video source. * - * Same as [IWithVideoSource.setVideoSource] with a [CameraSourceFactory]. + * Same as [IWithVideoSource.setVideoSource] with a [BitmapSourceFactory]. * * @param bitmap the [Bitmap] to stream */ -suspend fun IWithVideoSource.setBitmap(bitmap: Bitmap) { +suspend fun IWithVideoSource.setBitmapSource(bitmap: Bitmap) { setVideoSource(BitmapSourceFactory(bitmap)) } diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/pipelines/utils/HandlerThreadExecutor.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/pipelines/utils/HandlerThreadExecutor.kt index 66c9a34e5..67f28b172 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/pipelines/utils/HandlerThreadExecutor.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/pipelines/utils/HandlerThreadExecutor.kt @@ -19,6 +19,7 @@ import android.os.Handler import android.os.HandlerThread import io.github.thibaultbee.streampack.core.elements.utils.ProcessThreadPriorityValue import java.util.concurrent.Executor +import kotlin.time.Duration /** * Helper class that wraps a Handler/HandlerThread combination and implements the [Executor] @@ -36,8 +37,8 @@ class HandlerThreadExecutor(name: String, @ProcessThreadPriorityValue priority: handler.post(runnable) } - fun postDelayed(runnable: Runnable, delayMillis: Long) { - handler.postDelayed(runnable, delayMillis) + fun postDelayed(runnable: Runnable, delay: Duration) { + handler.postDelayed(runnable, delay.inWholeMilliseconds) } fun removeCallbacksAndMessages(token: Any) { diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/DualStreamer.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/DualStreamer.kt index f4480d4c1..d8bda8d96 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/DualStreamer.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/DualStreamer.kt @@ -37,7 +37,7 @@ import io.github.thibaultbee.streampack.core.elements.sources.video.camera.exten import io.github.thibaultbee.streampack.core.elements.sources.video.mediaprojection.MediaProjectionVideoSourceFactory import io.github.thibaultbee.streampack.core.elements.utils.RotationValue import io.github.thibaultbee.streampack.core.elements.utils.extensions.displayRotation -import io.github.thibaultbee.streampack.core.interfaces.setCameraId +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource import io.github.thibaultbee.streampack.core.pipelines.DispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.IDispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.inputs.IAudioInput @@ -78,7 +78,7 @@ suspend fun cameraDualStreamer( dispatcherProvider = dispatcherProvider ) - streamer.setCameraId(cameraId) + streamer.setCameraSource(cameraId) if (audioSourceFactory != null) { streamer.setAudioSource(audioSourceFactory) } diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/VideoOnlyDualStreamer.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/VideoOnlyDualStreamer.kt index 07e1fb804..28bbe391e 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/VideoOnlyDualStreamer.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/dual/VideoOnlyDualStreamer.kt @@ -30,7 +30,7 @@ import io.github.thibaultbee.streampack.core.elements.sources.video.camera.exten import io.github.thibaultbee.streampack.core.elements.sources.video.mediaprojection.MediaProjectionVideoSourceFactory import io.github.thibaultbee.streampack.core.elements.utils.RotationValue import io.github.thibaultbee.streampack.core.elements.utils.extensions.displayRotation -import io.github.thibaultbee.streampack.core.interfaces.setCameraId +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource import io.github.thibaultbee.streampack.core.pipelines.DispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.IDispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.inputs.IVideoInput @@ -66,7 +66,7 @@ suspend fun cameraVideoOnlyDualStreamer( surfaceProcessorFactory = surfaceProcessorFactory, dispatcherProvider = dispatcherProvider ) - streamer.setCameraId(cameraId) + streamer.setCameraSource(cameraId) return streamer } diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/SingleStreamer.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/SingleStreamer.kt index 20456afde..a64b3dafc 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/SingleStreamer.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/SingleStreamer.kt @@ -37,7 +37,7 @@ import io.github.thibaultbee.streampack.core.elements.sources.video.camera.exten import io.github.thibaultbee.streampack.core.elements.sources.video.mediaprojection.MediaProjectionVideoSourceFactory import io.github.thibaultbee.streampack.core.elements.utils.RotationValue import io.github.thibaultbee.streampack.core.elements.utils.extensions.displayRotation -import io.github.thibaultbee.streampack.core.interfaces.setCameraId +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource import io.github.thibaultbee.streampack.core.pipelines.AudioInputMode import io.github.thibaultbee.streampack.core.pipelines.DispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.IDispatcherProvider @@ -78,7 +78,7 @@ suspend fun cameraSingleStreamer( surfaceProcessorFactory = surfaceProcessorFactory, dispatcherProvider = dispatcherProvider ) - streamer.setCameraId(cameraId) + streamer.setCameraSource(cameraId) if (audioSourceFactory != null) { streamer.setAudioSource(audioSourceFactory) } diff --git a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/VideoOnlySingleStreamer.kt b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/VideoOnlySingleStreamer.kt index c10caa068..48a3ed250 100644 --- a/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/VideoOnlySingleStreamer.kt +++ b/core/src/main/java/io/github/thibaultbee/streampack/core/streamers/single/VideoOnlySingleStreamer.kt @@ -32,7 +32,7 @@ import io.github.thibaultbee.streampack.core.elements.sources.video.camera.exten import io.github.thibaultbee.streampack.core.elements.sources.video.mediaprojection.MediaProjectionVideoSourceFactory import io.github.thibaultbee.streampack.core.elements.utils.RotationValue import io.github.thibaultbee.streampack.core.elements.utils.extensions.displayRotation -import io.github.thibaultbee.streampack.core.interfaces.setCameraId +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource import io.github.thibaultbee.streampack.core.pipelines.DispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.IDispatcherProvider import io.github.thibaultbee.streampack.core.pipelines.inputs.IVideoInput @@ -66,7 +66,7 @@ suspend fun cameraVideoOnlySingleStreamer( surfaceProcessorFactory = surfaceProcessorFactory, dispatcherProvider = dispatcherProvider ) - streamer.setCameraId(cameraId) + streamer.setCameraSource(cameraId) return streamer } diff --git a/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/ui/main/PreviewViewModel.kt b/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/ui/main/PreviewViewModel.kt index 1a431ee97..843b7abed 100644 --- a/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/ui/main/PreviewViewModel.kt +++ b/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/ui/main/PreviewViewModel.kt @@ -51,14 +51,14 @@ import io.github.thibaultbee.streampack.core.elements.metrics.metricsFlow import io.github.thibaultbee.streampack.core.elements.metrics.writtenBitrateInBps import io.github.thibaultbee.streampack.core.elements.sources.audio.audiorecord.MicrophoneSourceFactory import io.github.thibaultbee.streampack.core.elements.sources.video.IVideoSource -import io.github.thibaultbee.streampack.core.elements.sources.video.bitmap.BitmapSourceFactory import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings -import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSourceFactory import io.github.thibaultbee.streampack.core.elements.sources.video.camera.ICameraSource import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.cameraManager import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.defaultCameraId import io.github.thibaultbee.streampack.core.interfaces.IWithVideoSource import io.github.thibaultbee.streampack.core.interfaces.releaseBlocking +import io.github.thibaultbee.streampack.core.interfaces.setBitmapSource +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource import io.github.thibaultbee.streampack.core.regulator.controllers.intervalBitrateRegulatorControllerFactory import io.github.thibaultbee.streampack.core.streamers.single.IAudioSingleStreamer import io.github.thibaultbee.streampack.core.streamers.single.IVideoSingleStreamer @@ -297,7 +297,7 @@ class PreviewViewModel(private val application: Application) : ObservableViewMod videoSourceMutex.withLock { streamer?.let { if (it.videoInput.sourceFlow.value == null) { - it.setVideoSource(CameraSourceFactory(defaultCameraId)) + it.setCameraSource(defaultCameraId) } else { Log.i(TAG, "Camera source already set") } @@ -419,7 +419,7 @@ class PreviewViewModel(private val application: Application) : ObservableViewMod viewModelScope.launch(defaultDispatcher) { videoSourceMutex.withLock { Log.i(TAG, "Switch video source to Camera $cameraId") - streamer?.setVideoSource(CameraSourceFactory(cameraId)) + streamer?.setCameraSource(cameraId) } } } @@ -435,7 +435,7 @@ class PreviewViewModel(private val application: Application) : ObservableViewMod } Log.i(TAG, "Switch video source to default Camera") - streamer?.setVideoSource(CameraSourceFactory(defaultCameraId)) + streamer?.setCameraSource(defaultCameraId) } } } @@ -444,7 +444,7 @@ class PreviewViewModel(private val application: Application) : ObservableViewMod viewModelScope.launch(defaultDispatcher) { videoSourceMutex.withLock { Log.i(TAG, "Switch video source to Bitmap") - streamer?.setVideoSource(BitmapSourceFactory(testBitmap)) + streamer?.setBitmapSource(testBitmap) } } } diff --git a/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/utils/Extensions.kt b/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/utils/Extensions.kt index b3e28ca9d..4ca4a3a1e 100644 --- a/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/utils/Extensions.kt +++ b/demos/camera/src/main/java/io/github/thibaultbee/streampack/app/utils/Extensions.kt @@ -33,7 +33,7 @@ import io.github.thibaultbee.streampack.core.elements.sources.video.camera.exten import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.frontCameras import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.isBackCamera import io.github.thibaultbee.streampack.core.interfaces.IWithVideoSource -import io.github.thibaultbee.streampack.core.interfaces.setCameraId +import io.github.thibaultbee.streampack.core.interfaces.setCameraSource @RequiresPermission(Manifest.permission.CAMERA) suspend fun IWithVideoSource.setNextCameraId(context: Context) { @@ -48,7 +48,7 @@ suspend fun IWithVideoSource.setNextCameraId(context: Context) { context.defaultCameraId } - setCameraId(newCameraId) + setCameraSource(newCameraId) } @RequiresPermission(Manifest.permission.CAMERA) @@ -66,7 +66,7 @@ suspend fun IWithVideoSource.switchBackToFront(context: Context) { } if (cameras.isNotEmpty()) { - setCameraId(cameras[0]) + setCameraSource(cameras[0]) } else { throw Exception("No camera available") } diff --git a/docs/configuration/SourceConfiguration.md b/docs/configuration/SourceConfiguration.md index 2bbed22dd..7e84f974a 100644 --- a/docs/configuration/SourceConfiguration.md +++ b/docs/configuration/SourceConfiguration.md @@ -35,11 +35,11 @@ StreamPack provides convenient extension functions to quickly configure specific ```kotlin // Switch to a specific camera ID (often "0" for back, "1" for front but you should always query the camera list) -streamer.setCameraId("0") +streamer.setCameraSource("0") // Set a static image/bitmap as the video source (useful for "stream starting soon" screens) val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.holding_image) -streamer.setBitmap(bitmap) +streamer.setBitmapSource(bitmap) ``` ## On-the-fly control diff --git a/docs/getting_started/QuickStartCamera.md b/docs/getting_started/QuickStartCamera.md index 3f9ba7478..fe354500a 100644 --- a/docs/getting_started/QuickStartCamera.md +++ b/docs/getting_started/QuickStartCamera.md @@ -120,7 +120,7 @@ val streamer = cameraSingleStreamer(context = requireContext()) * You can also create the `SingleStreamer`or the `DualStreamer` and add later the audio and video source with `setAudioSource` * and `setVideoSource`. * val streamer = SingleStreamer(context = requireContext()) - * streamer.setVideoSource(CameraSourceFactory()) // Same as streamer.setCameraId(context.defaultCameraId) + * streamer.setVideoSource(CameraSourceFactory()) // Same as streamer.setCameraSource(context.defaultCameraId) * streamer.setAudioSource(MicrophoneSourceFactory()) */ ``` diff --git a/extensions/rtmp/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/RtmpSingleStreamerTest.kt b/extensions/rtmp/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/RtmpSingleStreamerTest.kt index 8f0dd2592..e6a0e707f 100644 --- a/extensions/rtmp/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/RtmpSingleStreamerTest.kt +++ b/extensions/rtmp/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/RtmpSingleStreamerTest.kt @@ -25,6 +25,7 @@ import video.api.client.api.models.Environment import video.api.client.api.models.LiveStreamCreationPayload import video.api.client.api.models.VideoStatus import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @LargeTest class RtmpSingleStreamerTest { @@ -43,7 +44,7 @@ class RtmpSingleStreamerTest { } @Test - fun writeToRtmp() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds) { + fun writeToRtmp() = runTest(timeout = TEST_TIMEOUT) { assumeTrue("Required API key", apiKey != null) assumeTrue("API key not set", apiKey != "null") @@ -62,15 +63,15 @@ class RtmpSingleStreamerTest { ) streamer.startStream("rtmps://broadcast.api.video:1936/s/${liveStream.streamKey}") var i = 0 - val numOfLoop = LIVE_STREAM_DURATION_MS / LIVE_STREAM_POLLING_MS + val numOfLoop = LIVE_STREAM_DURATION / LIVE_STREAM_POLLING withContext(Dispatchers.Default) { while (i < numOfLoop) { i++ Log.d( TAG, - "Waiting for 1s (${i * LIVE_STREAM_POLLING_MS} ms/$LIVE_STREAM_DURATION_MS) ms" + "Waiting for 1s (${LIVE_STREAM_POLLING * i}/$LIVE_STREAM_DURATION)" ) - delay(LIVE_STREAM_POLLING_MS.milliseconds) + delay(LIVE_STREAM_POLLING) val isBroadcasting = liveStreamEndpoint.get(liveStream.liveStreamId).broadcasting!! Log.i(TAG, "Is broadcasting $isBroadcasting") @@ -124,9 +125,9 @@ class RtmpSingleStreamerTest { companion object { private const val TAG = "RTMPStreamerTest" - private const val TEST_TIMEOUT_MS = 200_000L - private const val LIVE_STREAM_DURATION_MS = 30_000L - private const val LIVE_STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 200.seconds + private val LIVE_STREAM_DURATION = 30.seconds + private val LIVE_STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 640 private const val VIDEO_HEIGHT = 360 diff --git a/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/SrtSingleStreamerTest.kt b/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/SrtSingleStreamerTest.kt index 01e9ac294..09fb8c10d 100644 --- a/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/SrtSingleStreamerTest.kt +++ b/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/core/streamers/single/SrtSingleStreamerTest.kt @@ -25,6 +25,7 @@ import video.api.client.api.models.Environment import video.api.client.api.models.LiveStreamCreationPayload import video.api.client.api.models.VideoStatus import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds @LargeTest class SrtSingleStreamerTest { @@ -43,7 +44,7 @@ class SrtSingleStreamerTest { } @Test - fun writeToSrt() = runTest(timeout = TEST_TIMEOUT_MS.milliseconds) { + fun writeToSrt() = runTest(timeout = TEST_TIMEOUT) { assumeTrue("Required API key", apiKey != null) assumeTrue("API key not set", apiKey != "null") @@ -62,15 +63,15 @@ class SrtSingleStreamerTest { ) streamer.startStream("srt://broadcast.api.video:6200?streamid=${liveStream.streamKey}") var i = 0 - val numOfLoop = LIVE_STREAM_DURATION_MS / LIVE_STREAM_POLLING_MS + val numOfLoop = LIVE_STREAM_DURATION / LIVE_STREAM_POLLING withContext(Dispatchers.Default) { while (i < numOfLoop) { i++ Log.d( TAG, - "Waiting for 1s (${i * LIVE_STREAM_POLLING_MS} ms/$LIVE_STREAM_DURATION_MS) ms" + "Waiting for 1s (${LIVE_STREAM_POLLING * i}/$LIVE_STREAM_DURATION)" ) - delay(LIVE_STREAM_POLLING_MS.milliseconds) + delay(LIVE_STREAM_POLLING) val isBroadcasting = liveStreamEndpoint.get(liveStream.liveStreamId).broadcasting!! Log.i(TAG, "Is broadcasting $isBroadcasting") @@ -124,9 +125,9 @@ class SrtSingleStreamerTest { companion object { private const val TAG = "SRTStreamerTest" - private const val TEST_TIMEOUT_MS = 200_000L - private const val LIVE_STREAM_DURATION_MS = 30_000L - private const val LIVE_STREAM_POLLING_MS = 1_000L + private val TEST_TIMEOUT = 200.seconds + private val LIVE_STREAM_DURATION = 30.seconds + private val LIVE_STREAM_POLLING = 1.seconds private const val VIDEO_WIDTH = 640 private const val VIDEO_HEIGHT = 360 diff --git a/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptorTest.kt b/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptorTest.kt index aaed5cd1c..ff4554d5a 100644 --- a/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptorTest.kt +++ b/extensions/srt/src/androidTest/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptorTest.kt @@ -17,6 +17,7 @@ package io.github.thibaultbee.streampack.ext.srt.configuration.mediadescriptor import org.junit.Assert import org.junit.Test +import kotlin.time.Duration.Companion.milliseconds class SrtMediaDescriptorTest { @Test @@ -67,4 +68,16 @@ class SrtMediaDescriptorTest { ) } } + + @Test + fun fromParametersWithDuration() { + val connection = SrtMediaDescriptor( + host = "192.168.1.12", + port = 1234, + latency = 120.milliseconds, + connectionTimeout = 3000.milliseconds + ) + Assert.assertEquals(120, connection.srtUrl.latencyInMs) + Assert.assertEquals(3000, connection.srtUrl.connectTimeoutInMs) + } } \ No newline at end of file diff --git a/extensions/srt/src/main/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptor.kt b/extensions/srt/src/main/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptor.kt index fc69c2f67..d01415703 100644 --- a/extensions/srt/src/main/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptor.kt +++ b/extensions/srt/src/main/java/io/github/thibaultbee/streampack/ext/srt/configuration/mediadescriptor/SrtMediaDescriptor.kt @@ -25,6 +25,7 @@ import io.github.thibaultbee.streampack.core.elements.endpoints.MediaSinkType import io.github.thibaultbee.streampack.core.elements.endpoints.composites.muxers.ts.data.TSServiceInfo import java.security.InvalidParameterException import androidx.core.net.toUri +import kotlin.time.Duration /** * Creates a SRT connection descriptor from an [descriptor]. @@ -74,8 +75,8 @@ fun SrtMediaDescriptor(uri: Uri, serviceInfo: TSServiceInfo = createDefaultTsSer * @param port the server port * @param streamId the SRT stream ID * @param passPhrase the SRT passphrase - * @param latency the SRT latency in ms - * @param connectionTimeout the SRT connection timeout in ms + * @param latency the SRT latency + * @param connectionTimeout the SRT connection timeout * @param serviceInfo the TS service information */ fun SrtMediaDescriptor( @@ -83,19 +84,19 @@ fun SrtMediaDescriptor( port: Int, streamId: String? = null, passPhrase: String? = null, - latency: Int? = null, - connectionTimeout: Int? = null, + latency: Duration? = null, + connectionTimeout: Duration? = null, serviceInfo: TSServiceInfo = createDefaultTsServiceInfo() ) = SrtMediaDescriptor( SrtUrl( hostname = host, port = port, - connectTimeoutInMs = connectionTimeout, + connectTimeoutInMs = connectionTimeout?.inWholeMilliseconds?.toInt(), null, null, null, null, - latencyInMs = latency, + latencyInMs = latency?.inWholeMilliseconds?.toInt(), null, null, null, diff --git a/ui/compose/src/main/java/io/github/thibaultbee/streampack/compose/SourcePreview.kt b/ui/compose/src/main/java/io/github/thibaultbee/streampack/compose/SourcePreview.kt index aa2e1035d..cb6d028b9 100644 --- a/ui/compose/src/main/java/io/github/thibaultbee/streampack/compose/SourcePreview.kt +++ b/ui/compose/src/main/java/io/github/thibaultbee/streampack/compose/SourcePreview.kt @@ -27,13 +27,14 @@ import io.github.thibaultbee.streampack.compose.utils.BitmapUtils import io.github.thibaultbee.streampack.core.elements.sources.video.IPreviewableSource import io.github.thibaultbee.streampack.core.elements.sources.video.bitmap.BitmapSourceFactory import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings -import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings.FocusMetering.Companion.DEFAULT_AUTO_CANCEL_DURATION_MS +import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings.FocusMetering.Companion.DEFAULT_AUTO_CANCEL_DURATION import io.github.thibaultbee.streampack.core.interfaces.IWithVideoSource import io.github.thibaultbee.streampack.core.logger.Logger import io.github.thibaultbee.streampack.core.streamers.single.SingleStreamer import io.github.thibaultbee.streampack.ui.views.PreviewView import kotlinx.coroutines.launch import kotlinx.coroutines.sync.withLock +import kotlin.time.Duration private const val TAG = "ComposeSourcePreview" @@ -46,7 +47,7 @@ private const val TAG = "ComposeSourcePreview" * @param modifier the [Modifier] to apply to the [PreviewView] * @param enableZoomOnPinch enable zoom on pinch gesture * @param enableTapToFocus enable tap to focus - * @param onTapToFocusTimeoutMs the duration in milliseconds after which the focus area set by tap-to-focus is cleared + * @param onTapToFocusTimeout the duration after which the focus area set by tap-to-focus is cleared */ @Composable fun SourcePreview( @@ -55,7 +56,7 @@ fun SourcePreview( onZoomChanged: ((zoomRatio: Float) -> Unit)? = null, enableZoomOnPinch: Boolean = true, enableTapToFocus: Boolean = true, - onTapToFocusTimeoutMs: Long = DEFAULT_AUTO_CANCEL_DURATION_MS + onTapToFocusTimeout: Duration = DEFAULT_AUTO_CANCEL_DURATION ) { val scope = rememberCoroutineScope() @@ -64,7 +65,7 @@ fun SourcePreview( PreviewView(context).apply { this.enableZoomOnPinch = enableZoomOnPinch this.enableTapToFocus = enableTapToFocus - this.onTapToFocusTimeoutMs = onTapToFocusTimeoutMs + this.onTapToFocusTimeout = onTapToFocusTimeout onZoomChanged?.let { val onZoomChangedListener = object : CameraSettings.Zoom.OnZoomChangedListener { override fun onZoomChanged(zoomRatio: Float) { diff --git a/ui/ui/src/main/java/io/github/thibaultbee/streampack/ui/views/PreviewView.kt b/ui/ui/src/main/java/io/github/thibaultbee/streampack/ui/views/PreviewView.kt index c7bf3caf6..fb9234e1f 100644 --- a/ui/ui/src/main/java/io/github/thibaultbee/streampack/ui/views/PreviewView.kt +++ b/ui/ui/src/main/java/io/github/thibaultbee/streampack/ui/views/PreviewView.kt @@ -41,6 +41,8 @@ import androidx.camera.viewfinder.core.populateFromCharacteristics import androidx.core.content.ContextCompat import io.github.thibaultbee.streampack.core.elements.sources.video.IPreviewableSource import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings +import io.github.thibaultbee.streampack.core.elements.sources.video.camera.CameraSettings.FocusMetering.Companion.DEFAULT_AUTO_CANCEL_DURATION +import kotlin.time.Duration import io.github.thibaultbee.streampack.core.elements.sources.video.camera.ICameraSource import io.github.thibaultbee.streampack.core.elements.sources.video.camera.extensions.getCameraCharacteristics import io.github.thibaultbee.streampack.core.elements.utils.ConflatedJob @@ -91,9 +93,9 @@ class PreviewView @JvmOverloads constructor( var enableTapToFocus: Boolean /** - * The duration in milliseconds after which the focus area set by tap-to-focus is cleared. + * The duration after which the focus area set by tap-to-focus is cleared. */ - var onTapToFocusTimeoutMs = 5000L + var onTapToFocusTimeout: Duration = DEFAULT_AUTO_CANCEL_DURATION private var scaleType: ScaleType = ScaleType.FIT_CENTER set(value) { @@ -419,7 +421,7 @@ class PreviewView @JvmOverloads constructor( PointF(x, y), meteringPointFactory, OrientationUtils.getSurfaceRotationDegrees(display.rotation), - onTapToFocusTimeoutMs + onTapToFocusTimeout ) } catch (t: Throwable) { Logger.e(TAG, "Failed to focus at $x, $y", t)