SRS流媒体服务器——SRS4.0 WebRTC⼀对⼀通话环境搭建与逻辑分析

SRS流媒体服务器——SRS4.0 WebRTC⼀对⼀通话环境搭建与逻辑分析


目录

  1. 概述
  2. 环境搭建
  3. SRS4.0 WebRTC1对1通话逻辑分析

SRS安装部署相关内容:

  1. SRS流媒体服务器——单机环境搭建和源码目录介绍
  2. SRS流媒体服务器——Forward集群搭建和源码分析
  3. SRS流媒体服务器——Edge集群搭建
  4. SRS流媒体服务器——WebRTC推拉流演示
  5. SRS流媒体服务器——SRS4.0 WebRTC⼀对⼀通话环境搭建与逻辑分析

SRS部分源码分析相关内容(请按照如下顺序阅读):

  1. SRS流媒体服务器——基本流程简单分析
  2. SRS流媒体服务器——RTMP端⼝监听逻辑分析
  3. SRS流媒体服务器——RTMP推流、拉流创建连接
  4. SRS流媒体服务器——服务器读取RTMP推流数据
  5. SRS流媒体服务器——服务器给RTMP拉流端转发数据

1. 概述

  1. SRS负责媒体能⼒,外置信令服务器负责房间管理。
  2. 官⽅⽂档参考:https://github.com/ossrs/srs/wiki/v4_CN_WebRTC#sfu-one-to-one
  3. signaling(信令)和httpx-static(web访问)这两个项⽬,代码都放在了SRS的3rdparty⽬录,不依赖⽹络就可以编译,但依赖Go环境。

2. 环境搭建

1. 安装go语⾔环境

  1. 在Go语⾔官⽹找到对应的安装包(https://golang.google.cn/dl/
  2. 下载和解析(使用的是阿里云的Ubuntu系统):
cd /usr/local/
wget https://dl.google.com/go/go1.16.5.linux-amd64.tar.gz --no-check-certificate
tar -C /usr/local -xzf go1.16.5.linux-amd64.tar.gz
  1. 需要配置 GOROOT 和 PATH环境变量,在/etc/profile中配置。
vim /etc/profile

# 将环境变量添加到/etc/profile⽂件末尾。
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin:$GOBIN
  1. 然后使⽤ source /etc/profile 命令使配置⽂件⽣效,就可以在任意⽬录使⽤Go语⾔命令。
source /etc/profile 
  1. 执行go version可以查看安装go是否成功。

2. 编译和启动srs

git clone -b v4.0.123 https://gitee.com/winlinvip/srs.oschina.git
srs.4.0.123
cd srs.4.0.123/trunk
./configure
make
./objs/srs -c conf/rtc.conf

3. 编译和启动信令服务器

  1. 进行srs/trunk目录下。
cd 3rdparty/signaling
make
./objs/signaling

在这里插入图片描述

  1. 注意:云服务器需要先开通1989端口。

4. 编译和启动web服务器

  1. 需要server.crt和server.key,如果没有则⽤openssl⽣成。
  2. 进入srs/trunk/3rdparty/httpx-static目录,执行:
# ⽣成 server.key
openssl genrsa -out server.key 2048

# ⽣成 server.crt
openssl req -new -x509 -key server.key -out server.crt -days 3650
  1. 编译和启动web服务器
cd 3rdparty/httpx-static
make
./objs/httpx-static -http 80 -https 443 -ssk server.key -ssc server.crt \
-proxy http://127.0.0.1:1989/sig -proxy http://127.0.0.1:1985/rtc \
-proxy http://127.0.0.1:8080/

在这里插入图片描述

5. 进入测试页面

  1. 打开demo地址:
https://localhost/demos/
https://192.xxx.3.6/demos/  #公网ip

在这里插入图片描述

  1. 输入Room和Display就可以进行1对1通话。
    在这里插入图片描述

3. SRS4.0 WebRTC1对1通话逻辑分析

  1. 按f12打开一对一通话http页面源码,在 one2one.html?autostart=true&room=fbe219e 中可以看到,“开始通话”按钮id是btn_start,当点击按钮后,执行startDemo函数。
  2. startDemo函数如下:
        var startDemo = async function () {
            var host = $('#txt_host').val(); //获取ip或者域名,房间id,参与者名字
            var room = $('#txt_room').val();
            var display = $('#txt_display').val();

            // Connect to signaling first. //关闭先前的websock连接
            if (sig) {
                sig.close(); //见srs.sig.js close部分
            }
            sig = new SrsRtcSignalingAsync(); //创建SrsRtcSignalingAsync,RTC信令
            sig.onmessage = function (msg) { //onmessage订阅新的信令消息
                console.log('Notify: ', msg);

                if (msg.event === 'leave') {
                    $('#player').hide();
                }

                if (msg.event === 'publish') { //房间已经存在的参与者,收到publish信令后再去订阅新加入者
                    if (msg.peer && msg.peer.publishing && msg.peer.display !== display) {
                        startPlay(host, room, msg.peer.display);
                    }
                }

                if (msg.event === 'control') {
                    if (msg.param === 'refresh') {
                        setTimeout(function () {
                            window.location.reload();
                        }, 500);
                    } else if (msg.param === 'alert') {
                        alert('From ' + msg.peer.display + ': ' + msg.data);
                    }
                }

                if (msg.participants.length >= 2) {
                    $('.srs_merge').show();
                } else {
                    $('.srs_merge').hide();
                }
            };
            await sig.connect(conf.wsSchema, conf.wsHost, room, display); //连接websock,见下面SrsRtcSignalingAsync代码

            control_refresh_peer = async function () {
                let r1 = await sig.send({action:'control', room:room, display:display, call:'refresh'});
                console.log('Signaling: control peer to refresh ok', r1);
            };
            control_alert_peer = async function () {
                let r1 = await sig.send({action:'control', room:room, display:display, call:'alert', data:$('#txt_alert').val()});
                console.log('Signaling: control peer to alert ok', r1);
            };

            let r0 = await sig.send({action:'join', room:room, display:display}); //向信令服务器发送join信令,会返回房间列表,包括当前房间id,房间人数和每个display的名字和是否推流,见下图。
            console.log('Signaling: join ok', r0);

            // For one to one demo, alert and ignore when room is full. 判断房间人数是否超过2个,因为是1v1场景
            if (r0.participants.length > 2) {
                alert('Room is full, already ' + (r0.participants.length - 1) + ' participants');
                sig.close();
                return;
            }

            // Start publish media if signaling is ok.
            await startPublish(host, room, display); //向srs流媒体服务器开始推流,代码见下面
            let r1 = await sig.send({action:'publish', room:room, display:display}); //向信令服务器发送publish信令
            console.log('Signaling: publish ok', r1);

            // Play the stream already in room. 对于新建的房间,会拉取房间内另一个人的流
            r0.participants.forEach(function(participant) {
                if (participant.display === display || !participant.publishing) return;
                startPlay(host, room, participant.display); //向srs流媒体拉房间内另一个人的流
            });

            if (r0.participants.length >= 2) {
                $('.srs_merge').show();
            }
        };
  1. SrsRtcSignalingAsync代码:
// Async-await-promise based SRS RTC Signaling.
function SrsRtcSignalingAsync() {
    var self = {};

    // The schema is ws or wss, host is ip or ip:port, display is nickname
    // of user to join the room.
    self.connect = async function (schema, host, room, display) {
        var url = schema + '://' + host + '/sig/v1/rtc'; //如:wss://8.xxx.75.248/sig/v1/rtc
        self.ws = new WebSocket(url + '?room=' + room + '&display=' + display); //建立websock连接,地址为:wss://8.xxx.75.248/sig/v1/rtc?room=123&display=zhangsan

        self.ws.onmessage = function(event) {
            var r = JSON.parse(event.data);
            var promise = self._internals.msgs[r.tid];
            if (promise) {
                promise.resolve(r.msg);
                delete self._internals.msgs[r.tid];
            } else {
                self.onmessage(r.msg);
            }
        };

        return new Promise(function (resolve, reject) {
            self.ws.onopen = function (event) {
                resolve(event);
            };

            self.ws.onerror = function (event) {
                reject(event);
            };
        });
    };

    // The message is a json object.
    self.send = async function (message) {
        return new Promise(function (resolve, reject) {
            var r = {tid: Number(parseInt(new Date().getTime()*Math.random()*100)).toString(16).substr(0, 7), msg: message};
            self._internals.msgs[r.tid] = {resolve: resolve, reject: reject};
            self.ws.send(JSON.stringify(r));
        });
    };

    self.close = function () {
        self.ws && self.ws.close();
        self.ws = null;

        for (const tid in self._internals.msgs) {
            var promise = self._internals.msgs[tid];
            promise.reject('close');
        }
    };

    // The callback when got messages from signaling server.
    self.onmessage = function (msg) {
    };

    self._internals = {
        // Key is tid, value is object {resolve, reject, response}.
        msgs: {}
    };

    return self;
}
  1. join信息返回信息。
    在这里插入图片描述

  2. startPublish和startPlay代码。

       var startPublish = function (host, room, display) {
            $(".ff_first").each(function(i,e) {
                $(e).text(display);
            });

            var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query; //如: webrtc://8.xxx.75.248/123/wangwu
            $('#rtc_media_publisher').show();
            $('#publisher').show();

            if (publisher) {
                publisher.close();
            }
            publisher = new SrsRtcPublisherAsync(); //创建RTC异步推流
            $('#rtc_media_publisher').prop('srcObject', publisher.stream);

            return publisher.publish(url).then(function(session){
                $('#self').text('Self: ' + url);
            }).catch(function (reason) {
                publisher.close();
                $('#rtc_media_publisher').hide();
                console.error(reason);
            });
        };

        var startPlay = function (host, room, display) {
            $(".ff_second").each(function(i,e) {
                $(e).text(display);
            });

            var url = 'webrtc://' + host + '/' + room + '/' + display + conf.query; //
            $('#rtc_media_player').show();
            $('#player').show();

            if (player) {
                player.close();
            }

            player = new SrsRtcPlayerAsync();
            $('#rtc_media_player').prop('srcObject', player.stream);

            player.play(url).then(function(session){
                $('#peer').text('Peer: ' + display);
                $('#rtc_media_player').prop('muted', false);
            }).catch(function (reason) {
                player.close();
                $('#rtc_media_player').hide();
                console.error(reason);
            });
        };
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WebRTC (Web Real-Time Communication) is a free, open-source project that enables real-time communication between web browsers, mobile applications, and IoT devices. It provides protocols and APIs for building applications such as voice and video calls, file sharing, and real-time messaging. To implement WebRTC in Python, you can use the aiortc library, which is an asyncio-based framework for WebRTC. Here's a brief overview of how you can get started: 1. Install aiortc using pip: ``` pip install aiortc ``` 2. Import the necessary modules in your Python code: ```python import asyncio from aiortc import RTCPeerConnection, RTCSessionDescription ``` 3. Create an asyncio event loop and define your signaling logic: ```python async def offer(): # Create a peer connection pc = RTCPeerConnection() # Create an offer offer = await pc.createOffer() await pc.setLocalDescription(offer) # Implement your signaling to send the offer to the remote peer async def answer(offer): # Create a peer connection pc = RTCPeerConnection() # Set the remote description from the offer await pc.setRemoteDescription(RTCSessionDescription(offer["sdp"], "offer")) # Create an answer answer = await pc.createAnswer() await pc.setLocalDescription(answer) # Implement your signaling to send the answer back to the remote peer async def connect(answer): # Set the remote description from the answer await pc.setRemoteDescription(RTCSessionDescription(answer["sdp"], "answer")) # Implement your signaling to finalize the connection # Run the event loop loop = asyncio.get_event_loop() loop.run_until_complete(offer()) ``` Keep in mind that this is just a basic example to get you started with WebRTC in Python using aiortc. You'll need to implement the signaling logic to exchange SDP offers and answers between peers. For more advanced usage and additional features, refer to the aiortc documentation: https://aiortc.readthedocs.io/ Remember, WebRTC involves more than just Python code, as it requires signaling servers and potentially STUN/TURN servers for NAT traversal.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值