如何通过 Django Channels 实现视频通话?

Posted

技术标签:

【中文标题】如何通过 Django Channels 实现视频通话?【英文标题】:How to implement video calls over Django Channels? 【发布时间】:2020-05-07 17:29:11 【问题描述】:

我想创建一个允许用户进行视频通话的应用。 我发现了一些见解here,但不幸的是,答案既没有解释可以使用哪些第三方服务,也没有解释关于集成 WebRTC 的任何有意义的见解。

我已经设法使用 Channels 创建了一个基于 Django WebSocket 的实时聊天,并且我想出了“获取用户媒体”。但是我完全被 Peer2Peer 连接所淹没。

如何通过 Django 频道集成 WebRTC?或者我可以使用更简单的方式/第三方服务吗?

我的消费者.py:

from channels.generic.websocket import AsyncWebsocketConsumer
from channels.consumer import AsyncConsumer
import json

class ChatConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = 'chat_%s' % self.room_name
        self.user = self.scope["user"].username

        # Join room group
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.accept()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        user = text_data_json['user']

        # Send message to room group
        await self.channel_layer.group_send(
            self.room_group_name,
            
                'type': 'chat_message',
                'message': message,
                'user': user
            
        )

    # Receive message from room group
    async def chat_message(self, event):
        message = event['message'],
        user = event['user']

        # Send message to WebSocket
        await self.send(text_data=json.dumps(
            'message': message,
            'user': user
        ))

我的聊天室:

 % extends 'main/header.html' %

% block content %

<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>

<body>

<div class="container">
    <textarea id="chat-log"  class="materialize-textarea" ></textarea><br/>

<div class="input-field col s12 ">
    <input id="chat-message-input" type="text" />
    <a class="waves-effect waves-light btn prefix" id="chat-message-submit"><i class="material-icons right">send</i></a>

</div>

</div>

</body>
<script>
    var roomName = " room_name|escapejs ";

    var chatSocket = new WebSocket(
        'ws://' + window.location.host +
        '/ws/chat/' + roomName + '/');

    chatSocket.onmessage = function(e) 
        var data = JSON.parse(e.data);
        console.info(e)
        var message = data['message'];
        var user = data['user'];
        document.querySelector('#chat-log').value += (user +": " + message + '\n');
        elem = document.getElementById("chat-log")
        M.textareaAutoResize(elem);
    ;

    chatSocket.onclose = function(e) 
        console.error('Chat socket closed unexpectedly');
    ;

    document.querySelector('#chat-message-input').focus();
    document.querySelector('#chat-message-input').onkeyup = function(e) 
        if (e.keyCode === 13)   // enter, return
            document.querySelector('#chat-message-submit').click();
        
    ;

    document.querySelector('#chat-message-submit').onclick = function(e) 
        var messageInputDom = document.querySelector('#chat-message-input');
        var message = messageInputDom.value;
        var user = "user.username"
        chatSocket.send(JSON.stringify(
            'message': message,
            'user': user

        ));

        messageInputDom.value = '';
    ;
</script>

% endblock  %

我的客户端.js:

window.onload = function () 
   var constraints =  audio: true, video:  width: 1280, height: 720  ; 

navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) 
var video = document.querySelector('video');
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) 
video.play();
;
)
.catch(function(err)  console.log(err.name + ": " + err.message); );
;

我的视频:

<html>
 % load static %
   <head> 
      <meta charset = "utf-8"> 
      <script src = "% static 'main/js/client.js' %"></script>
   </head>

   <body> 
      <video controls="" id = 'video-player' name = 'video-player' autoplay></video> 

   </body> 

</html> 

【问题讨论】:

任何解决方案了吗? ***.com/a/64234291/3842788 -- 工作示例 【参考方案1】:

仅使用WebSockets 即可实现没有媒体传输的简单实时聊天应用程序,而实时媒体传输(音频、视频)则需要完全不同的协议。

WebRTC 原生支持所有现代浏览器,可用于实时媒体传输。

虽然 webRTC 可用于传输媒体,但设备之间的握手必须在此之外进行。

即使任何类型的 api/http 请求对此都是合理的,但 websocket 的实时数据传输能力还是不错的。

说了这么多,既然你已经选择了 django-channels,你可以用它来进行握手。

要建立 WebRTC 连接,客户端 A 需要使用其SDP(会话描述协议)生成一个报价并将其发送给客户端 B,客户端 B 必须将其 SDP 发送回客户端 B一个答案。

此时,两个客户端都会知道在传输数据时要使用哪些编解码器和编解码器参数。但是,两个客户端都不知道或不确定需要使用哪些网络设置或数据本身需要如何传输。

这就是ICE(交互式连接建立)谈判的切入点。双方客户都会来回发送从高到低的谈判,直到他们达成一致。这就是媒体流开始流动的地方。

以上只是沧海一粟,但是,如果您按照signalling and video calling 上的MDN's 主题进行操作,得到一个工作原型并不难。

【讨论】:

以上是关于如何通过 Django Channels 实现视频通话?的主要内容,如果未能解决你的问题,请参考以下文章

使用Django Channels 2上传文件

使用 Django Channels 2 上传文件

如何通过 Django Channels 将 cookie 添加到标头?

代码发布项目——django实现websocket(使用channels)基于channels实现群聊功能gojs插件paramiko模块

如何从 Django Channels Web 套接字数据包中获取当前用户?

django channels