天天看點

Android接入SRS WebRtc直播流

目前從事無人機配套程式開發,之前一直使用的是RTMP進行直播流顯示,由于網頁端要棄用flash,轉為使用WebRtc協定,改完後RTMP流延遲飙升,遂安卓端同步修改。

由于網絡上大部分教程文章都是多人視訊示例且不了解SRS和WebRtc通信流程 浪費了很多時間

本文章隻涉及安卓端的webrtc流播放 适用于SRS推流

參考以下文章 macaruina

WebRTC源碼研究(29)媒體能力協商過程

Web項目jswebrtc

SRS測試位址

1.SRS WebRtc通信流程

安卓端作為調用方 正常流程為由stable開始

createOffer->setLocalDescription->接收answer->setRemoteDescription
           

這裡由于SRS的存在 接收answer這一步驟需要手動使用網絡請求伺服器進行建立answer操作 如下

Android接入SRS WebRtc直播流

請求接口後SRS會建立answer 并在接口傳回Json資料包含spd 安卓端直接調用setRemoteDescription即可

2.安卓端整體代碼

build.gradle

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

布局

<org.webrtc.SurfaceViewRenderer
        android:id="@+id/activity_main_svr_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
           

初始化EglBase PeerConnectionFactory

//初始化EglBase macaruina
            EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext();
            PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions
                    .builder(context)
                    .createInitializationOptions());
            //初始化PeerConnectionFactory macaruina
            PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
            DefaultVideoEncoderFactory encoderFactory =
                    new DefaultVideoEncoderFactory(eglBaseContext, true, true);
            DefaultVideoDecoderFactory decoderFactory =
                    new DefaultVideoDecoderFactory(eglBaseContext);
            PeerConnectionFactory peerConnectionFactory = PeerConnectionFactory.builder()
                    .setOptions(options)
                    .setVideoEncoderFactory(encoderFactory)
                    .setVideoDecoderFactory(decoderFactory)
                    .createPeerConnectionFactory();
            //初始化SurfaceViewRenderer
            surfaceViewRenderer.init(eglBaseContext, null);
            //初始化peerConnectionFactory監聽 macaruina
             PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(new ArrayList<>());
            //修改模式 PlanB無法使用僅接收音視訊的配置
            rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;
            peerConnection = peerConnectionFactory.createPeerConnection(rtcConfig,
                    new PeerConnection.Observer() {
                ......

                @Override
                public void onAddStream(MediaStream mediaStream) {
                    //在這裡将流放進surfaceViewRenderer中 macaruina
                    mediaStream.videoTracks.get(0).addSink(surfaceViewRenderer);
                }
                ......
            });
             //設定僅接收音視訊
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_VIDEO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
            peerConnection.addTransceiver(MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO, new RtpTransceiver.RtpTransceiverInit(RtpTransceiver.RtpTransceiverDirection.RECV_ONLY));
           
           
peerConnection.createOffer(sdpObserver, new MediaConstraints());


SdpObserver sdpObserver = new SdpObserver() {
        @Override
        public void onCreateSuccess(SessionDescription sessionDescription) {
            if (sessionDescription.type == SessionDescription.Type.OFFER) {
                //設定setLocalDescription offer傳回sdp macaruina
                peerConnection.setLocalDescription(sdpObserver, sessionDescription);
                //請求SRS伺服器接口 macaruina
                //HttpPost.....網絡請求 得到結果後調用setRemoteDescription 傳入傳回的sdp
            } 
        }
        ......
};

void setRemoteDescription(String sdp) {
        SessionDescription remoteSpd = new SessionDescription(SessionDescription.Type.ANSWER, sdp);
        peerConnection.setRemoteDescription(sdpObserver, remoteSpd);
    }