Skip to content

Commit

Permalink
Merge pull request #9 from SimerusM/rtc-changes
Browse files Browse the repository at this point in the history
webrtc working
  • Loading branch information
16BitNarwhal authored Aug 29, 2024
2 parents 67328f7 + f8415d8 commit 1e9f56d
Show file tree
Hide file tree
Showing 12 changed files with 439 additions and 106 deletions.
78 changes: 70 additions & 8 deletions api-server/app.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from flask import Flask
from flask_socketio import SocketIO
from flask import Flask, jsonify, request
from flask_socketio import SocketIO, emit, join_room, leave_room
from flask_cors import CORS
from chat import setup_chat_routes, setup_chat_sockets
from webrtc import setup_webrtc_sockets
from chat import setup_chat
from webrtc import setup_webrtc
import uuid

# Define log levels and color codes
DEBUG = 'DEBUG'
Expand All @@ -18,7 +19,7 @@
CRITICAL_COLOR = '\033[41m'
RESET_COLOR = '\033[0m'

def log_message(level, message, meeting=''):
def log_message(level: str, message: str, meeting=''):
color_map = {
DEBUG: DEBUG_COLOR,
INFO: INFO_COLOR,
Expand All @@ -39,9 +40,70 @@ def log_message(level, message, meeting=''):
session_storage = {}

# Setup routes and sockets
setup_chat_routes(app, session_storage, log_message)
setup_chat_sockets(socketio, session_storage, log_message)
setup_webrtc_sockets(socketio)
@app.route('/api/create-meeting', methods=['POST'])
def create_meeting():
meeting_id = str(uuid.uuid4())
data = request.get_json()
username = data['username']

if username == '':
return jsonify({'error': 'Username cannot be empty'}), 400
if meeting_id in session_storage:
return jsonify({'error': 'Meeting ID already exists, please try again'}), 400

session_storage[meeting_id] = {
'host': username,
'users': {}, # {username: sid}
'chat_history': [] # [{sender: username, text: message}]
}
log_message('INFO', f'User {username} created a new meeting', meeting_id)
return jsonify({'meeting_id': meeting_id})

@app.route('/api/session/<meeting_id>', methods=['GET'])
def get_session(meeting_id):
if meeting_id not in session_storage:
return jsonify({'error': 'Meeting ID not found'}), 404
return jsonify(session_storage[meeting_id])

@app.route('/api/users/<meeting_id>', methods=['GET'])
def get_users(meeting_id):
if meeting_id not in session_storage:
return jsonify({'error': 'Meeting ID not found'}), 404
return jsonify(list(session_storage[meeting_id]['users'].keys()))

@socketio.on('join')
def handle_join(data):
if 'username' not in data or 'meeting_id' not in data:
log_message('ERROR', f'Join request missing username or meeting ID: {data}')
emit('error', {'message': 'Missing username or meeting ID'}, to=request.sid)
return

meeting_id = data['meeting_id']
username = data['username']
join_room(meeting_id)
session = session_storage[meeting_id]
session['users'][username] = request.sid

log_message('INFO', f'User {username} joined the meeting', meeting_id)
emit('user_joined', {'username': username, 'meeting_id': meeting_id}, room=meeting_id)

@socketio.on('disconnect')
def handle_disconnect():
to_delete = []
for meeting_id, session in session_storage.items():
if request.sid in session['users'].values():
username = [username for username, sid in session['users'].items() if sid == request.sid][0]
del session['users'][username]
if len(session['users']) == 0:
to_delete.append(meeting_id)
log_message('INFO', f'User {request.sid} left the meeting', meeting_id)
emit('user_left', {'meeting_id': meeting_id, 'username': username}, room=meeting_id)

for meeting_id in to_delete:
del session_storage[meeting_id]

setup_chat(app, socketio, session_storage, log_message)
setup_webrtc(app, socketio, session_storage, log_message)

if __name__ == '__main__':
import os
Expand Down
48 changes: 8 additions & 40 deletions api-server/chat.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,24 @@
from flask import jsonify, request
from flask_socketio import emit, join_room
import uuid

def setup_chat_routes(app, session_storage, log_message):
@app.route('/api/create-meeting', methods=['POST'])
def create_meeting():
meeting_id = str(uuid.uuid4())
data = request.get_json()
username = data['username']
session_storage[meeting_id] = {
'host': username,
'users': [],
'chat_history': []
}
log_message('INFO', f'User {username} created a new meeting', meeting_id)
return jsonify({'meeting_id': meeting_id})
from flask_socketio import emit

def setup_chat(app, socketio, session_storage, log_message):
@app.route('/api/chat_history/<meeting_id>', methods=['GET'])
def get_chat_history(meeting_id):
if meeting_id in session_storage:
return jsonify(session_storage[meeting_id]['chat_history'])
else:
return jsonify({'error': 'Meeting ID not found'}), 404

@app.route('/api/session/<meeting_id>', methods=['GET'])
def get_users(meeting_id):
if meeting_id in session_storage:
return jsonify(session_storage[meeting_id])
else:
if meeting_id not in session_storage:
return jsonify({'error': 'Meeting ID not found'}), 404

def setup_chat_sockets(socketio, session_storage, log_message):
@socketio.on('join')
def handle_join(data):
if 'username' not in data or 'meeting_id' not in data:
log_message('ERROR', f'Join request missing username or meeting ID: {data}')
return
meeting_id = data['meeting_id']
username = data['username']
join_room(meeting_id)
session = session_storage[meeting_id]
session['users'].append(username)
log_message('INFO', f'User {username} joined the meeting', meeting_id)
emit('user_joined', {'username': username, 'meeting_id': meeting_id}, room=meeting_id)
return jsonify(session_storage[meeting_id]['chat_history'])

@socketio.on('chat_message')
def handle_chat_message(data):
meeting_id = data['meeting_id']
sender = data['sender']
message = data['text']

if meeting_id not in session_storage:
log_message('ERROR', f'Meeting ID {meeting_id} not found', meeting_id)
emit('error', {'message': 'Meeting ID not found'}, to=request.sid)
return

session_storage[meeting_id]['chat_history'].append({'sender': sender, 'text': message})
log_message('INFO', f'User {sender} sent: {message}', meeting_id)
emit('chat_message', {'sender': sender, 'text': message}, room=meeting_id)
20 changes: 20 additions & 0 deletions api-server/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { io } from 'socket.io-client';

const socket = io('http://127.0.0.1:5000');

// Join a room with a specific meeting ID
socket.emit('join', { 'username': 'teet', meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804' });

// Emit the SDP offer immediately
socket.emit('offer', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804', sdp: '...' });

// Simulate receiving the offer and sending back an SDP answer after 1 second
socket.emit('answer', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b26804', sdp: 'v=0\r\no=- 25678 753849 IN IP4 192.0.2.2\r\ns=-\r\nc=IN IP4 192.0.2.2\r\nt=0 0\r\na=recvonly\r\nm=video 49170 RTP/AVP 98\r\na=rtpmap:98 H264/90000\r\n' });

// Simulate sending ICE candidates after 2 seconds
socket.emit('ice_candidate', { meeting_id: 'e45f73db-9973-4acd-9467-c48f56b2', candidate: 'candidate:842163049 1 udp 1677729535 192.0.2.1 3478 typ srflx raddr 192.0.2.1 rport 3478' });

// Listen for events
socket.on('offer', (data) => console.log('Received offer:', data));
socket.on('answer', (data) => console.log('Received answer:', data));
socket.on('ice_candidate', (data) => console.log('Received ICE candidate:', data));
17 changes: 10 additions & 7 deletions api-server/webrtc.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
from flask import request
from flask_socketio import emit

def setup_webrtc_sockets(socketio):
def setup_webrtc(app, socketio, session_storage, log_message):
@socketio.on('offer')
def handle_offer(data):
meeting_id = data['meeting_id']
emit('offer', data, room=meeting_id)
to_sid = session_storage[data['meeting_id']]['users'][data['to']]
log_message('INFO', f'User {data["from"]} sent an offer', data['meeting_id'])
emit('offer', data, room=to_sid, skip_sid=request.sid)

@socketio.on('answer')
def handle_answer(data):
meeting_id = data['meeting_id']
emit('answer', data, room=meeting_id)
to_sid = session_storage[data['meeting_id']]['users'][data['to']]
log_message('INFO', f'User {data["from"]} sent an answer', data['meeting_id'])
emit('answer', data, room=to_sid, skip_sid=request.sid)

@socketio.on('ice_candidate')
def handle_ice_candidate(data):
meeting_id = data['meeting_id']
emit('ice_candidate', data, room=meeting_id)
to_sid = session_storage[data['meeting_id']]['users'][data['to']]
emit('ice_candidate', data, room=to_sid, skip_sid=request.sid)
9 changes: 5 additions & 4 deletions client/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom';

import HomePage from './pages/HomePage';
import MeetingPage from './pages/MeetingPage';
Expand All @@ -8,11 +8,12 @@ const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/meet/:meeting_id" element={<MeetingPage />} />
<Route path="/" element={<HomePage />} />
<Route path="/meet/:meeting_id" element={<MeetingPage />} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
</Router>
);
};

export default App;
export default App;
4 changes: 2 additions & 2 deletions client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
// <React.StrictMode>
<App />
</React.StrictMode>
// </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
Expand Down
6 changes: 3 additions & 3 deletions client/src/pages/HomePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ const HomePage = () => {
return;
}

fetch(`${apiUrl}/api/session/${meetCode}`).then((response) => {
fetch(`${apiUrl}/api/users/${meetCode}`).then((response) => {
if (!response.ok) {
toast.error('Meeting code not found. Please try again.');
return;
}
return response.json();
}).then((data) => {
if (data.users.includes(username)) {
}).then((users) => {
if (users.includes(username)) {
toast.error(`User ${username} is already in this meeting.`);
return;
}
Expand Down
Loading

0 comments on commit 1e9f56d

Please sign in to comment.