Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added base/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file added base/__pycache__/admin.cpython-313.pyc
Binary file not shown.
Binary file added base/__pycache__/apps.cpython-313.pyc
Binary file not shown.
Binary file added base/__pycache__/models.cpython-313.pyc
Binary file not shown.
Binary file added base/__pycache__/urls.cpython-313.pyc
Binary file not shown.
Binary file added base/__pycache__/views.cpython-313.pyc
Binary file not shown.
Binary file added base/migrations/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
37 changes: 35 additions & 2 deletions base/templates/base/lobby.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
{% extends 'base/main.html' %}
{% load static %}

{% block content %}

<main>
<section id="form-container">
<img id="logo" src="{% static 'images/chat_room_64px.png' %}" alt="chatIcon">
<div>
<h1>Welcome to MyChart</h1>
<p>A group calling application for you</p>
</div>

<form id="form">
<div class="form-field">
<input type="text" name="room" placeholder="Enter room name..." style="text-transform:uppercase" required />
</div>
<div class="form-field">
<input type="submit" value="Join Room" />
</div>
</form>
</section>
</main>
{% endblock content %}

<script type="text/javascript">
let form = document.getElementById('form')

let handleSubmit = async (e) => {
e.preventDefault()
let room = e.target.room.value.toUpperCase()

// Fetch the secure RTC token from our Django backend view
let response = await fetch(`/get_token/?channel=${room}`)
let data = await response.json()

// Store details in sessionStorage for stream.js to read inside the room
sessionStorage.setItem('room', room)
sessionStorage.setItem('token', data.token)
sessionStorage.setItem('uid', data.uid)

// Redirect the user to the video room page
window.open('/room/', '_self')
}

form.addEventListener('submit', handleSubmit)
</script>

{% endblock content %}
17 changes: 9 additions & 8 deletions base/templates/base/room.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
{% extends 'base/main.html' %}

{% block content %}

<main>
<section>
<p>Room Name: <span id="room-name-wrapper"> </span></p>
<section id="room-name-container">
<p>Room Name: <span id="room-name-wrapper"></span></p>
</section>

<section id="video-streams">
<div class="video-container" id="user-container-1">
<div class="username-wrapper"><span class="user-name">My Name</span></div>
<div class="video-player" id="user-1"></div>
</div>
<section id="video-streams"></section>

<section id="controls-container">
<button id="mic-btn">Mute Mic</button>
<button id="camera-btn">Turn Off Camera</button>
<button id="leave-btn">Leave Room</button>
</section>
</main>

{% endblock content %}

9 changes: 5 additions & 4 deletions base/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.urls import path
from . import views
from django.urls import path
from . import views

urlpatterns = [
path("", views.lobby),
path("room/", views.room),
path('', views.lobby),
path('room/', views.room),
path('get_token/', views.getToken),
]
18 changes: 18 additions & 0 deletions base/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
from django.shortcuts import render
from django.http import JsonResponse
import random
import time
from agora_token_builder import RtcTokenBuilder

def lobby(request):
return render(request, 'base/lobby.html')

def room(request):
return render(request, 'base/room.html')

def getToken(request):
appId = 'YOUR_AGORA_APP_ID'
appCertificate = 'YOUR_AGORA_APP_CERTIFICATE'
channelName = request.GET.get('channel')
uid = random.randint(1, 230)
expirationTimeInSeconds = 3600 * 24
currentTimeStamp = int(time.time())
privilegeExpiredTs = currentTimeStamp + expirationTimeInSeconds
role = 1

token = RtcTokenBuilder.buildTokenWithUid(appId, appCertificate, channelName, uid, role, privilegeExpiredTs)

return JsonResponse({'token': token, 'uid': uid}, safe=False)
Binary file added mychart/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file added mychart/__pycache__/settings.cpython-313.pyc
Binary file not shown.
Binary file added mychart/__pycache__/urls.cpython-313.pyc
Binary file not shown.
Binary file added mychart/__pycache__/wsgi.cpython-313.pyc
Binary file not shown.
98 changes: 98 additions & 0 deletions static/js/stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const APP_ID = 'YOUR_AGORA_APP_ID'
const CHANNEL = sessionStorage.getItem('room')
const TOKEN = sessionStorage.getItem('token')
let UID = Number(sessionStorage.getItem('uid'))

const client = AgoraRTC.createClient({mode:'rtc', codec:'vp8'})

let localTracks = []
let remoteUsers = {}

let joinAndDisplayLocalStream = async () => {
document.getElementById('room-name-wrapper').innerText = CHANNEL

client.on('user-published', handleUserJoined)
client.on('user-left', handleUserLeft)

try{
await client.join(APP_ID, CHANNEL, TOKEN, UID)
}catch(error){
console.error(error)
window.open('/', '_self')
}

localTracks = await AgoraRTC.createMicrophoneAndCameraTracks()

let player = `<div class="video-container" id="user-container-${UID}">
<div class="username-wrapper"><span class="user-name">My Stream</span></div>
<div class="video-player" id="user-${UID}"></div>
</div>`
document.getElementById('video-streams').insertAdjacentHTML('beforeend', player)

localTracks[1].play(`user-${UID}`)
await client.publish([localTracks[0], localTracks[1]])
}

let handleUserJoined = async (user, mediaType) => {
remoteUsers[user.uid] = user
await client.subscribe(user, mediaType)

if (mediaType === 'video'){
let player = document.getElementById(`user-container-${user.uid}`)
if (player != null){
player.remove()
}

player = `<div class="video-container" id="user-container-${user.uid}">
<div class="username-wrapper"><span class="user-name">User ${user.uid}</span></div>
<div class="video-player" id="user-${user.uid}"></div>
</div>`
document.getElementById('video-streams').insertAdjacentHTML('beforeend', player)
user.videoTrack.play(`user-${user.uid}`)
}

if (mediaType === 'audio'){
user.audioTrack.play()
}
}

let handleUserLeft = async (user) => {
delete remoteUsers[user.uid]
document.getElementById(`user-container-${user.uid}`).remove()
}

let leaveAndRemoveLocalStream = async () => {
for(let i = 0; localTracks.length > i; i++){
localTracks[i].stop()
localTracks[i].close()
}

await client.leave()
window.open('/', '_self')
}

let toggleMic = async (e) => {
if (localTracks[0].muted){
await localTracks[0].setMuted(false)
e.target.innerText = 'Mute Mic'
}else{
await localTracks[0].setMuted(true)
e.target.innerText = 'Unmute Mic'
}
}

let toggleCamera = async (e) => {
if (localTracks[1].muted){
await localTracks[1].setMuted(false)
e.target.innerText = 'Turn Off Camera'
}else{
await localTracks[1].setMuted(true)
e.target.innerText = 'Turn On Camera'
}
}

joinAndDisplayLocalStream()

document.getElementById('leave-btn').addEventListener('click', leaveAndRemoveLocalStream)
document.getElementById('mic-btn').addEventListener('click', toggleMic)
document.getElementById('camera-btn').addEventListener('click', toggleCamera)