開始撰寫 init()、createAudioConstraints() 及 createVideoCapture() 就可以開始預覽相機
啟動相機完整代碼
底下程式碼可以正確啟動相機
import android.content.Context import android.media.MediaCodecInfo import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import net.ddns.mahaljsp.cameraw.databinding.ActivityMainBinding import org.webrtc.AudioTrack import org.webrtc.Camera1Enumerator import org.webrtc.Camera2Enumerator import org.webrtc.CameraEnumerator import org.webrtc.CameraVideoCapturer import org.webrtc.DefaultVideoDecoderFactory import org.webrtc.EglBase import org.webrtc.MediaConstraints import org.webrtc.PeerConnection import org.webrtc.PeerConnectionFactory import org.webrtc.RendererCommon import org.webrtc.SurfaceTextureHelper import org.webrtc.VideoEncoderSupportedCallback import org.webrtc.VideoTrack import org.webrtc.createCustomVideoEncoderFactory class MainActivity : AppCompatActivity() { lateinit var permission:MainPermission lateinit var ui:ActivityMainBinding lateinit var rtcConfig : PeerConnection.RTCConfiguration var surfaceTextureHelper: SurfaceTextureHelper? = null var videoTrack: VideoTrack? = null var audioTrack: AudioTrack? = null val eglBaseContext = EglBase.create().eglBaseContext lateinit var peerConnectionFactory: PeerConnectionFactory fun init(){ ui.localView.init(eglBaseContext, null) ui.localView.setEnableHardwareScaler(true) ui.localView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL) ui.localView.setZOrderMediaOverlay(true); PeerConnectionFactory.initialize( PeerConnectionFactory.InitializationOptions .builder(this).createInitializationOptions() ) val options = PeerConnectionFactory.Options() val encoderFactory = createCustomVideoEncoderFactory( eglBaseContext,true,true, object : VideoEncoderSupportedCallback { override fun isSupportedVp8(info: MediaCodecInfo): Boolean { return true } override fun isSupportedVp9(info: MediaCodecInfo): Boolean { return true } override fun isSupportedH264(info: MediaCodecInfo): Boolean { return true } }) val decoderFactory = DefaultVideoDecoderFactory(eglBaseContext) peerConnectionFactory = PeerConnectionFactory.builder() .setOptions(options) .setVideoEncoderFactory(encoderFactory) .setVideoDecoderFactory(decoderFactory) .createPeerConnectionFactory() val audioSource = peerConnectionFactory.createAudioSource( createAudioConstraints() ) audioTrack = peerConnectionFactory.createAudioTrack( "local_audio_track", audioSource ) val videoCapture = createVideoCapture(this) val videoSource = peerConnectionFactory.createVideoSource( videoCapture!!.isScreencast ) videoTrack =peerConnectionFactory.createVideoTrack( "local_video_track", videoSource ) surfaceTextureHelper = SurfaceTextureHelper.create( "surface_thread", eglBaseContext ) //第二個參數為 this,也可以是getApplicationContext() videoCapture?.initialize( surfaceTextureHelper, this, videoSource.capturerObserver ) videoTrack?.addSink(ui.localView) videoCapture?.startCapture(1920, 1080, 25) rtcConfig = PeerConnection.RTCConfiguration(emptyList()) rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN } private fun createAudioConstraints(): MediaConstraints { val audioConstraints = MediaConstraints() //消除回音 audioConstraints.mandatory.add( MediaConstraints.KeyValuePair( "googEchoCancellation", "true" ) ) //自動增益 Automatic Gain Control(AGC) 聲音輸入時有時大,有時小。 // 自動增益會依輸入的音量自動增減,讓輸出時保持固定音量 audioConstraints.mandatory.add(MediaConstraints.KeyValuePair( "googAutoGainControl", "true") ) //高音過濾 audioConstraints.mandatory.add(MediaConstraints.KeyValuePair( "googHighpassFilter", "true") ) //降噪 audioConstraints.mandatory.add( MediaConstraints.KeyValuePair( "googNoiseSuppression", "true" ) ) return audioConstraints } private fun createVideoCapture(context: Context): CameraVideoCapturer? { val enumerator: CameraEnumerator = if (Camera2Enumerator.isSupported(context)) { Camera2Enumerator(context) } else { Camera1Enumerator() } for (name in enumerator.deviceNames) { if (enumerator.isBackFacing(name)) { return enumerator.createCapturer(name, null) } } for (name in enumerator.deviceNames) { if (enumerator.isBackFacing(name)) { return enumerator.createCapturer(name, null) } } return null }
todo