Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
[MV-381] Add ability to toggle between cameras using camera name (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
graszka22 authored Mar 23, 2023
1 parent 492c094 commit 6a2a6ae
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,17 @@ constructor(
}
}

fun createLocalVideoTrack(videoParameters: VideoParameters, metadata: Metadata = mapOf()): LocalVideoTrack {
fun createLocalVideoTrack(
videoParameters: VideoParameters,
metadata: Metadata = mapOf(),
captureDeviceName: String? = null
): LocalVideoTrack {
val videoTrack = LocalVideoTrack.create(
context,
peerConnectionFactoryWrapper.peerConnectionFactory,
eglBase,
videoParameters
videoParameters,
captureDeviceName
).also {
it.start()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,16 @@ private constructor(
*
* @param videoParameters a set of target parameters such as camera resolution, frame rate or simulcast configuration
* @param metadata the metadata that will be sent to the <strong>Membrane RTC Engine</strong> for media negotiation
* @param captureDeviceName the name of the device to start video capture with, you can get device name by using
* `LocalVideoTrack.getCaptureDevices` method
* @return an instance of the video track
*/
public fun createVideoTrack(videoParameters: VideoParameters, metadata: Metadata): LocalVideoTrack {
return client.createLocalVideoTrack(videoParameters, metadata)
public fun createVideoTrack(
videoParameters: VideoParameters,
metadata: Metadata,
captureDeviceName: String? = null
): LocalVideoTrack {
return client.createLocalVideoTrack(videoParameters, metadata, captureDeviceName)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ constructor(
eglBase: EglBase,
val videoParameters: VideoParameters
) : VideoTrack(mediaTrack, eglBase.eglBaseContext), LocalTrack {

data class CaptureDevice(val deviceName: String, val isFrontFacing: Boolean, val isBackFacing: Boolean)

companion object {
fun create(
context: Context,
factory: PeerConnectionFactory,
eglBase: EglBase,
videoParameters: VideoParameters
videoParameters: VideoParameters,
cameraName: String? = null
): LocalVideoTrack {
val source = factory.createVideoSource(false)
val track = factory.createVideoTrack(UUID.randomUUID().toString(), source)
Expand All @@ -31,11 +35,27 @@ constructor(
context = context,
source = source,
rootEglBase = eglBase,
videoParameters = videoParameters
videoParameters = videoParameters,
cameraName
)

return LocalVideoTrack(track, capturer, eglBase, videoParameters)
}

fun getCaptureDevices(context: Context): List<CaptureDevice> {
val enumerator = if (Camera2Enumerator.isSupported(context)) {
Camera2Enumerator(context)
} else {
Camera1Enumerator(true)
}
return enumerator.deviceNames.map { name ->
CaptureDevice(
name,
enumerator.isFrontFacing(name),
enumerator.isBackFacing(name)
)
}
}
}

override fun start() {
Expand All @@ -57,6 +77,10 @@ constructor(
fun flipCamera() {
(capturer as? CameraCapturer)?.flipCamera()
}

fun switchCamera(deviceName: String) {
(capturer as? CameraCapturer)?.switchCamera(deviceName)
}
}

interface Capturer {
Expand All @@ -69,15 +93,15 @@ class CameraCapturer constructor(
private val context: Context,
private val source: VideoSource,
private val rootEglBase: EglBase,
private val videoParameters: VideoParameters
private val videoParameters: VideoParameters,
cameraName: String?
) : Capturer, CameraVideoCapturer.CameraSwitchHandler {
private lateinit var cameraCapturer: CameraVideoCapturer
private lateinit var size: Size
private var frontFacing = true
private var isCapturing = false

init {
createCapturer()
createCapturer(cameraName)
}

override fun capturer(): VideoCapturer {
Expand All @@ -99,40 +123,48 @@ class CameraCapturer constructor(
cameraCapturer.switchCamera(this)
}

private fun createCapturer() {
fun switchCamera(deviceName: String) {
cameraCapturer.switchCamera(this, deviceName)
}

private fun createCapturer(providedDeviceName: String?) {
val enumerator = if (Camera2Enumerator.isSupported(context)) {
Camera2Enumerator(context)
} else {
Camera1Enumerator(true)
}

for (deviceName in enumerator.deviceNames) {
if (enumerator.isFrontFacing(deviceName)) {
this.cameraCapturer = enumerator.createCapturer(deviceName, null)
var deviceName = providedDeviceName

this.cameraCapturer.initialize(
SurfaceTextureHelper.create("CameraCaptureThread", rootEglBase.eglBaseContext),
context,
source.capturerObserver
)
if (deviceName == null) {
for (name in enumerator.deviceNames) {
if (enumerator.isFrontFacing(name)) {
deviceName = name
break
}
}
}

val sizes = enumerator.getSupportedFormats(deviceName)
?.map { Size(it.width, it.height) }
?: emptyList()
this.cameraCapturer = enumerator.createCapturer(deviceName, null)

this.size = CameraEnumerationAndroid.getClosestSupportedSize(
sizes,
videoParameters.dimensions.width,
videoParameters.dimensions.height
)
this.cameraCapturer.initialize(
SurfaceTextureHelper.create("CameraCaptureThread", rootEglBase.eglBaseContext),
context,
source.capturerObserver
)

break
}
}
val sizes = enumerator.getSupportedFormats(deviceName)
?.map { Size(it.width, it.height) }
?: emptyList()

this.size = CameraEnumerationAndroid.getClosestSupportedSize(
sizes,
videoParameters.dimensions.width,
videoParameters.dimensions.height
)
}

override fun onCameraSwitchDone(isFrontCamera: Boolean) {
frontFacing = isFrontCamera
}

override fun onCameraSwitchError(errorDescription: String?) {
Expand Down

0 comments on commit 6a2a6ae

Please sign in to comment.