Hello and Welcome again, in this article, we will create a simple video calling application with Django, Django Channels, and WebRTC. Django is a high-level Python web framework. Channels is a project that takes Django and extends its abilities beyond HTTP - to handle WebSockets. WebRTC is an open standard for real-time, plugin-free video, audio, and data communication. WebRTC enables peer-to-peer communication, it allows communication among browsers and devices.
Prerequisite
You should have a basic understanding of the Django framework. Having the knowledge of Django Channels is good. Some Basic understanding of JavaScript. Having the knowledge of Promises and DOM is good. If you are here to understand the flow of WebRTC and how it works, you can follow it thoroughly along as well.
WebRTC
Web Real-Time Communication is a technology that allows Web applications and sites to capture audio and/or video media. WebRTC allows Web applications and sites to exchange data between browsers without requiring any intermediary.
WebRTC establishes connections between two peers and is represented by the RTCPeerConnection interface. Once the connection is established, media streams and/or data channels can be added to the connection. Connections between peers can be made without requiring any special drivers or plug-ins, and can often be made without any intermediary servers.
There is no way we can share all of the code here, so I will try to share some important parts and share the GitHub for the project.
We first start a Django project, 'videocall', then start an app. let's call it 'call'. Then we will define a view that will serve as a static template. Then define the url to get to that view.
Update your settings.py to include the 'call' and 'channels'. Then, add about ASGI. Let's use InMemoryChannelLayer as BACKEND channel layer.
...
...
...
INSTALLED_APPS = [
...
...
'call',
'channels',
]
...
...
...
ASGI_APPLICATION = 'videocall.asgi.application'
CHANNEL_LAYERS={
"default": {
"BACKEND": "channels.layers.InMemoryChannelLayer"
}
}
Now, create the 'consumer.py'
# call/consumers.py
import json
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
classCallConsumer(WebsocketConsumer):
defconnect(self):
self.accept()
# response to client, that we are connected.
self.send(text_data=json.dumps({
'type': 'connection',
'data': {
'message': "Connected"
}
}))
defdisconnect(self, close_code):
# Leave room group
async_to_sync(self.channel_layer.group_discard)(
self.my_name,
self.channel_name
)
# Receive message from client WebSocket
defreceive(self, text_data):
text_data_json = json.loads(text_data)
# print(text_data_json)
eventType = text_data_json['type']
if eventType == 'login':
name = text_data_json['data']['name']
# we will use this as room name as well
self.my_name = name
# Join room
async_to_sync(self.channel_layer.group_add)(
self.my_name,
self.channel_name
)
if eventType == 'call':
name = text_data_json['data']['name']
print(self.my_name, "is calling", name);
# print(text_data_json)
# to notify the callee we sent an event to the group name
In the above consumers.py, we create a CallConsumer, which will interact with the frontend. The channel is mainly responsible to transfer the "Offer", "Answer" and "ICECandidates".
The receive method will be triggered for any event from the frontend, then based on the event type we will perform the necessary actions.
The above code section will create a connection to the WebSocket (Django channels). Then it listens to the events from the socket. based on the event type, it handles the UI and data.
We need to send some events to the backend as well. we need to send "Call", "Answer" and "ICECandidates"
We define the methods, will be called as needed. The send call will be called when the user enters who to call and presses the call button. The answerCall will be called, when the user get the call and have to accept the call.
sendICECandidate(), will be called whenever the Connection get the ICE candidates, we will talk about this letter.
STUN is on the public internet, the apps can use STUN server to discover its IP:port from a public perspective. STUN server simply check the IP:Port of the incoming request and respond it back, there is not much work there is so not much powerful server is required.
If WebRTC cannot establish a connection with the above methods, TURN servers can be used as a fallback, relaying data between endpoints.
The beReady method will be called, whenever the user have to call or answer a call. The processCall, will be called to create an offer and processAccept is called whenever a user get the call(the offer), and have to create an answer.
The handleIceCandidate is an listener for RTCPeerConnection, which will be fired everytime new ICE Candidates are found. Here we will simply forward it to the other user.
WebRTC not Working on Lan
Here we use the getUserMedia API to get the audio-video of the user, But some browsers restrict the use of these APIs to Secure Origins only. As Described on Deprecating Powerful Features on Insecure Origins. These APIs include:
Geolocation
Device motion / orientation
EME
getUserMedia
AppCache
Notifications
But Lan network is not considered a secure origin. As described on Prefer Secure Origins For Powerful New Features, "Secure origins" are origins that match at least one of the following (scheme, host, port) patterns:
We implement a Video calling application on Django, using the Django Channels and WebRTC. There is not much to do on the backend side, as Django is used just as a signaling server, and data are transferred directly between clients.
2 Comments
how to disconnect the video if user end the call
ReplyDeletesimply stop your webrtc peer connection instance
ReplyDelete