美文网首页
Android Studio下使用WebRTC简要流程

Android Studio下使用WebRTC简要流程

作者: Euirgo | 来源:发表于2022-05-30 11:43 被阅读0次

1.添加WebRTC库

  implementation 'org.webrtc:google-webrtc:1.0.32006'

2.配置xml,添加Surface用于展示相机画面

    <org.webrtc.SurfaceViewRenderer
        android:id="@+id/webrtc_surface_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <org.webrtc.SurfaceViewRenderer
        android:id="@+id/webrtc_surface_remote_view"
        android:layout_width="90dp"
        android:layout_height="160dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_margin="30dp"
        />
  • 可能使用到的参数

    public class Constant {
        // 穿透服务器地址
        public static final String STUN = "stun:stun.l.google.com:19302";
    
        public static final String CHANNEL = "channel";
    
        public static final int VIDEO_RESOLUTION_WIDTH = 720;
        public static final int VIDEO_RESOLUTION_HEIGHT = 480;
        public static final int VIDEO_FPS = 30;
        //声音调节
        public static final int VOLUME = 10;
    
        public static final String VIDEO_TRACK_ID = "videtrack";
        public static final String AUDIO_TRACK_ID = "audiotrack";
    
        public static final String LOCAL_VIDEO_STREAM = "localVideoStream";
        public static final String LOCAL_AUDIO_STREAM = "localAudioStream";
    }
    

3.创建PeerConnectionFactory、PeerConnection

public void createPeerConnection() {
    // 初始化 PeerConnectionFactory
    PeerConnectionFactory.InitializationOptions initializationOptions = PeerConnectionFactory
            .InitializationOptions.builder(Utils.getApp())
            .setEnableInternalTracer(true)
            .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
            .createInitializationOptions();
    PeerConnectionFactory.initialize(initializationOptions);
    //创建EglBase对象
    eglBaseContext = EglBase.create().getEglBaseContext();
    PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
    options.disableEncryption = true;
    options.disableNetworkMonitor = true;
    peerConnectionFactory = PeerConnectionFactory.builder()
            .setVideoDecoderFactory(new DefaultVideoDecoderFactory(eglBaseContext))
            .setVideoEncoderFactory(new DefaultVideoEncoderFactory(eglBaseContext, true, true))
            .setOptions(options)
            .createPeerConnectionFactory();
    // 配置STUN穿透服务器  转发服务器
    iceServers = new ArrayList<>();
    PeerConnection.IceServer iceServer = PeerConnection.IceServer.builder(Constant.STUN).createIceServer();
    iceServers.add(iceServer);
    streamList = new ArrayList<>();
    PeerConnection.RTCConfiguration configuration = new PeerConnection.RTCConfiguration(iceServers);
    PeerConnectionObserver connectionObserver = getObserver();
    peerConnection = peerConnectionFactory.createPeerConnection(configuration, connectionObserver);
    // DataChannel.Init 可配参数说明:
    // ordered:是否保证顺序传输;
    // maxRetransmitTimeMs:重传允许的最长时间;
    // maxRetransmits:重传允许的最大次数;
    DataChannel.Init init = new DataChannel.Init();
    if (peerConnection != null) {
        channel = peerConnection.createDataChannel(Constant.CHANNEL, init);
    }
    DateChannelObserver channelObserver = new DateChannelObserver();
    connectionObserver.setObserver(channelObserver);
    // 初始化Surface
    initSurface();
    // 初始化Sdp回调
    initObserver();
}
  • PeerConnectionObserver 实现 PeerConnection.Observer

    @NonNull
    private PeerConnectionObserver getObserver() {
        return new PeerConnectionObserver() {
            @Override
            public void onIceCandidate(IceCandidate iceCandidate) {
                super.onIceCandidate(iceCandidate);
                LogUtils.eTag(TAG, "创建iceCandidate");
                // setIceCandidate(iceCandidate);
                // 添加对方的ice
                peerConnection.addIceCandidate(iceCandidate);
            }

            @Override
            public void onAddStream(MediaStream mediaStream) {
                super.onAddStream(mediaStream);
                LogUtils.eTag(TAG, "onAddStream : " + mediaStream.toString());
                List<VideoTrack> videoTracks = mediaStream.videoTracks;
                if (videoTracks != null && videoTracks.size() > 0) {
                    VideoTrack videoTrack = videoTracks.get(0);
                    if (videoTrack != null) {
                        videoTrack.addSink(remoteSurfaceView);
                    }
                }
                List<AudioTrack> audioTracks = mediaStream.audioTracks;
                if (audioTracks != null && audioTracks.size() > 0) {
                    AudioTrack audioTrack = audioTracks.get(0);
                    if (audioTrack != null) {
                        audioTrack.setVolume(Constant.VOLUME);
                    }
                }
            }
        };
    }

4. 初始化本地surface、音视频轨

    public void initSurface() {
        // 设置视频显示
        initSurfaceView(localSurfaceView);
        initSurfaceView(remoteSurfaceView);
        startLocalVideoCapture(localSurfaceView);
        startLocalAudioCapture();
    }
    private void initSurfaceView(SurfaceViewRenderer localSurfaceView) {
        localSurfaceView.init(eglBaseContext, null);
        localSurfaceView.setMirror(true);
        localSurfaceView.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL);
        localSurfaceView.setKeepScreenOn(true);
        localSurfaceView.setZOrderMediaOverlay(true);
        localSurfaceView.setEnableHardwareScaler(false);
    }
  • 配置本地视频轨

    private void startLocalVideoCapture(SurfaceViewRenderer localSurfaceView) {
        VideoSource videoSource = peerConnectionFactory.createVideoSource(true);
        SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create(Thread.currentThread().getName()
                , eglBaseContext);
        VideoCapturer videoCapturer = createCameraCapturer();
        videoCapturer.initialize(surfaceTextureHelper, ActivityUtils.getTopActivity(), videoSource.getCapturerObserver());
        videoCapturer.startCapture(Constant.VIDEO_RESOLUTION_WIDTH, Constant.VIDEO_RESOLUTION_HEIGHT, Constant.VIDEO_FPS); 
        // width, height, frame per second
        videoTrack = peerConnectionFactory
                .createVideoTrack(Constant.VIDEO_TRACK_ID, videoSource);
        videoTrack.addSink(localSurfaceView);
        MediaStream localMediaStream = peerConnectionFactory
                .createLocalMediaStream(Constant.LOCAL_VIDEO_STREAM);
        localMediaStream.addTrack(videoTrack);
        peerConnection.addTrack(videoTrack, streamList);
        peerConnection.addStream(localMediaStream);
    }
  • 配置相机捕获

    /**
         * 判断使用Camera1还是Camera2
         * @return VideoCapturer
         */
        private VideoCapturer createCameraCapturer() {
            Context context = ActivityUtils.getTopActivity();
            if (Camera2Enumerator.isSupported(context)) {
                return createCameraCapturer(new Camera2Enumerator(context));
            } else {
                return createCameraCapturer(new Camera1Enumerator(true));
            }
        }
    
        private VideoCapturer createCameraCapturer(CameraEnumerator enumerator) {
            final String[] deviceNames = enumerator.getDeviceNames();
    
            // 首先,尝试找到前置摄像头
            LogUtils.eTag(TAG, "尝试查找前置摄像头...");
            for (String deviceName : deviceNames) {
                if (enumerator.isFrontFacing(deviceName)) {
                    LogUtils.eTag(TAG, "前置摄像头捕捉器创建成功");
                    VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                    if (videoCapturer != null) {
                        return videoCapturer;
                    }
                }
            }
    
            // 没有找到前置摄像头,试试别的
            LogUtils.eTag(TAG, "Looking for other cameras.");
            for (String deviceName : deviceNames) {
                if (!enumerator.isFrontFacing(deviceName)) {
                    Logging.d(TAG, "Creating other camera capturer.");
                    VideoCapturer videoCapturer = enumerator.createCapturer(deviceName, null);
                    if (videoCapturer != null) {
                        return videoCapturer;
                    }
                }
            }
            return null;
        }
    
  • 配置本地音频轨

    private void startLocalAudioCapture() {
        //语音
        MediaConstraints audioConstraints = new MediaConstraints();
        //回声消除
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googEchoCancellation", "true"));
        //自动增益
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googAutoGainControl", "true"));
        //高音过滤
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googHighpassFilter", "true"));
        //噪音处理
        audioConstraints.mandatory.add(new MediaConstraints.KeyValuePair("googNoiseSuppression", "true"));
        AudioSource audioSource = peerConnectionFactory.createAudioSource(audioConstraints);
        audioTrack = peerConnectionFactory.createAudioTrack(Constant.AUDIO_TRACK_ID, audioSource);
        MediaStream localMediaStream = peerConnectionFactory.createLocalMediaStream(Constant.LOCAL_AUDIO_STREAM);
        localMediaStream.addTrack(audioTrack);
        audioTrack.setVolume(Constant.VOLUME);
        peerConnection.addTrack(audioTrack, streamList);
        peerConnection.addStream(localMediaStream);
    }

5.创建本地Sdp回调,发送给对方

  • MySdpObserver 实现SdpObserver

    private void initObserver() {
        observer = new MySdpObserver() {
            @Override
            public void onCreateSuccess(SessionDescription sessionDescription) {
                // 将会话描述设置在本地
                peerConnection.setLocalDescription(this, sessionDescription);
                SessionDescription localDescription = peerConnection.getLocalDescription();
                SessionDescription.Type type = localDescription.type;
                LogUtils.eTag(TAG, "onCreateSuccess == " + " type == " + type);
                // 将offer发送给服务器
                if (type == SessionDescription.Type.OFFER) {
                    // 发送呼叫
                    offer(sessionDescription);
                } else if (type == SessionDescription.Type.ANSWER) {
                    // 发送应答
                    answer(sessionDescription);
                } else if (type == SessionDescription.Type.PRANSWER) {
                    // 发送再次应答
                }
            }
        };
    }

6.所有配置完成

在PeerConnectionObserver的onAddStream对方音视频轨成功时,画面已建立。

相关文章

网友评论

      本文标题:Android Studio下使用WebRTC简要流程

      本文链接:https://www.haomeiwen.com/subject/hohoprtx.html