Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -190,12 +190,20 @@ def room(token):
|
|
190 |
|
191 |
// Добавление видео в сетку
|
192 |
function addVideoStream(stream, user, muted = false) {
|
193 |
-
console.log(
|
194 |
const existingVideo = document.querySelector(`video[data-user="${user}"]`);
|
195 |
if (existingVideo) return;
|
|
|
196 |
const video = document.createElement('video');
|
197 |
video.srcObject = stream;
|
198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
if (muted) video.muted = true;
|
200 |
video.dataset.user = user;
|
201 |
document.getElementById('video-grid').appendChild(video);
|
@@ -204,7 +212,7 @@ def room(token):
|
|
204 |
// Создание соединения с другим пользователем
|
205 |
function connectToUser(user) {
|
206 |
if (user === username || peers[user]) return;
|
207 |
-
console.log(
|
208 |
const peer = new RTCPeerConnection({
|
209 |
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
210 |
});
|
@@ -213,13 +221,18 @@ def room(token):
|
|
213 |
localStream.getTracks().forEach(track => peer.addTrack(track, localStream));
|
214 |
|
215 |
peer.ontrack = event => {
|
216 |
-
console.log(
|
217 |
addVideoStream(event.streams[0], user);
|
218 |
};
|
219 |
|
220 |
peer.onicecandidate = event => {
|
221 |
if (event.candidate) {
|
222 |
-
socket.emit('signal', {
|
|
|
|
|
|
|
|
|
|
|
223 |
}
|
224 |
};
|
225 |
|
@@ -227,7 +240,12 @@ def room(token):
|
|
227 |
peer.createOffer()
|
228 |
.then(offer => peer.setLocalDescription(offer))
|
229 |
.then(() => {
|
230 |
-
socket.emit('signal', {
|
|
|
|
|
|
|
|
|
|
|
231 |
})
|
232 |
.catch(err => console.error('Ошибка создания предложения:', err));
|
233 |
};
|
@@ -235,19 +253,27 @@ def room(token):
|
|
235 |
|
236 |
// Обработка входящих сигналов
|
237 |
socket.on('signal', data => {
|
|
|
238 |
if (data.from === username) return;
|
239 |
-
console.log(
|
|
|
240 |
let peer = peers[data.from];
|
241 |
if (!peer) {
|
242 |
peer = new RTCPeerConnection({
|
243 |
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
244 |
});
|
245 |
peers[data.from] = peer;
|
|
|
246 |
localStream.getTracks().forEach(track => peer.addTrack(track, localStream));
|
247 |
peer.ontrack = event => addVideoStream(event.streams[0], data.from);
|
248 |
peer.onicecandidate = event => {
|
249 |
if (event.candidate) {
|
250 |
-
socket.emit('signal', {
|
|
|
|
|
|
|
|
|
|
|
251 |
}
|
252 |
};
|
253 |
}
|
@@ -256,7 +282,12 @@ def room(token):
|
|
256 |
peer.setRemoteDescription(new RTCSessionDescription(data.signal))
|
257 |
.then(() => peer.createAnswer())
|
258 |
.then(answer => peer.setLocalDescription(answer))
|
259 |
-
.then(() => socket.emit('signal', {
|
|
|
|
|
|
|
|
|
|
|
260 |
.catch(err => console.error('Ошибка обработки предложения:', err));
|
261 |
} else if (data.signal.type === 'answer') {
|
262 |
peer.setRemoteDescription(new RTCSessionDescription(data.signal))
|
@@ -268,7 +299,7 @@ def room(token):
|
|
268 |
});
|
269 |
|
270 |
socket.on('user_joined', data => {
|
271 |
-
console.log(
|
272 |
document.getElementById('users').innerText = 'Пользователи: ' + data.users.join(', ');
|
273 |
if (data.username !== username) {
|
274 |
connectToUser(data.username);
|
@@ -276,7 +307,7 @@ def room(token):
|
|
276 |
});
|
277 |
|
278 |
socket.on('user_left', data => {
|
279 |
-
console.log(
|
280 |
document.getElementById('users').innerText = 'Пользователи: ' + data.users.join(', ');
|
281 |
if (peers[data.username]) {
|
282 |
peers[data.username].close();
|
@@ -296,7 +327,9 @@ def room(token):
|
|
296 |
function leaveRoom() {
|
297 |
socket.emit('leave', { token: token, username: username });
|
298 |
localStream.getTracks().forEach(track => track.stop());
|
299 |
-
for (let user in peers)
|
|
|
|
|
300 |
window.location.href = '/dashboard';
|
301 |
}
|
302 |
</script>
|
@@ -330,6 +363,7 @@ def handle_leave(data):
|
|
330 |
|
331 |
@socketio.on('signal')
|
332 |
def handle_signal(data):
|
|
|
333 |
emit('signal', data, room=data['token'], skip_sid=request.sid)
|
334 |
|
335 |
if __name__ == '__main__':
|
|
|
190 |
|
191 |
// Добавление видео в сетку
|
192 |
function addVideoStream(stream, user, muted = false) {
|
193 |
+
console.log('Добавление видео для', user);
|
194 |
const existingVideo = document.querySelector(`video[data-user="${user}"]`);
|
195 |
if (existingVideo) return;
|
196 |
+
|
197 |
const video = document.createElement('video');
|
198 |
video.srcObject = stream;
|
199 |
+
// Важно для мобильных устройств:
|
200 |
+
video.setAttribute('playsinline', '');
|
201 |
+
video.setAttribute('autoplay', '');
|
202 |
+
// По умолчанию autoplay может блокироваться, поэтому вызываем play() явно
|
203 |
+
video.addEventListener('loadedmetadata', () => {
|
204 |
+
video.play().catch(e => console.error('Autoplay error:', e));
|
205 |
+
});
|
206 |
+
|
207 |
if (muted) video.muted = true;
|
208 |
video.dataset.user = user;
|
209 |
document.getElementById('video-grid').appendChild(video);
|
|
|
212 |
// Создание соединения с другим пользователем
|
213 |
function connectToUser(user) {
|
214 |
if (user === username || peers[user]) return;
|
215 |
+
console.log('Инициирую соединение с', user);
|
216 |
const peer = new RTCPeerConnection({
|
217 |
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
218 |
});
|
|
|
221 |
localStream.getTracks().forEach(track => peer.addTrack(track, localStream));
|
222 |
|
223 |
peer.ontrack = event => {
|
224 |
+
console.log('Получен поток от', user);
|
225 |
addVideoStream(event.streams[0], user);
|
226 |
};
|
227 |
|
228 |
peer.onicecandidate = event => {
|
229 |
if (event.candidate) {
|
230 |
+
socket.emit('signal', {
|
231 |
+
token: token,
|
232 |
+
from: username,
|
233 |
+
to: user,
|
234 |
+
signal: { type: 'candidate', candidate: event.candidate }
|
235 |
+
});
|
236 |
}
|
237 |
};
|
238 |
|
|
|
240 |
peer.createOffer()
|
241 |
.then(offer => peer.setLocalDescription(offer))
|
242 |
.then(() => {
|
243 |
+
socket.emit('signal', {
|
244 |
+
token: token,
|
245 |
+
from: username,
|
246 |
+
to: user,
|
247 |
+
signal: peer.localDescription
|
248 |
+
});
|
249 |
})
|
250 |
.catch(err => console.error('Ошибка создания предложения:', err));
|
251 |
};
|
|
|
253 |
|
254 |
// Обработка входящих сигналов
|
255 |
socket.on('signal', data => {
|
256 |
+
// Если сигнал пришёл от нас же, игнорируем
|
257 |
if (data.from === username) return;
|
258 |
+
console.log('Получен сигнал от', data.from, ':', data.signal.type);
|
259 |
+
|
260 |
let peer = peers[data.from];
|
261 |
if (!peer) {
|
262 |
peer = new RTCPeerConnection({
|
263 |
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
264 |
});
|
265 |
peers[data.from] = peer;
|
266 |
+
|
267 |
localStream.getTracks().forEach(track => peer.addTrack(track, localStream));
|
268 |
peer.ontrack = event => addVideoStream(event.streams[0], data.from);
|
269 |
peer.onicecandidate = event => {
|
270 |
if (event.candidate) {
|
271 |
+
socket.emit('signal', {
|
272 |
+
token: token,
|
273 |
+
from: username,
|
274 |
+
to: data.from,
|
275 |
+
signal: { type: 'candidate', candidate: event.candidate }
|
276 |
+
});
|
277 |
}
|
278 |
};
|
279 |
}
|
|
|
282 |
peer.setRemoteDescription(new RTCSessionDescription(data.signal))
|
283 |
.then(() => peer.createAnswer())
|
284 |
.then(answer => peer.setLocalDescription(answer))
|
285 |
+
.then(() => socket.emit('signal', {
|
286 |
+
token: token,
|
287 |
+
from: username,
|
288 |
+
to: data.from,
|
289 |
+
signal: peer.localDescription
|
290 |
+
}))
|
291 |
.catch(err => console.error('Ошибка обработки предложения:', err));
|
292 |
} else if (data.signal.type === 'answer') {
|
293 |
peer.setRemoteDescription(new RTCSessionDescription(data.signal))
|
|
|
299 |
});
|
300 |
|
301 |
socket.on('user_joined', data => {
|
302 |
+
console.log('Пользователь', data.username, 'присоединился');
|
303 |
document.getElementById('users').innerText = 'Пользователи: ' + data.users.join(', ');
|
304 |
if (data.username !== username) {
|
305 |
connectToUser(data.username);
|
|
|
307 |
});
|
308 |
|
309 |
socket.on('user_left', data => {
|
310 |
+
console.log('Пользователь', data.username, 'покинул комнату');
|
311 |
document.getElementById('users').innerText = 'Пользователи: ' + data.users.join(', ');
|
312 |
if (peers[data.username]) {
|
313 |
peers[data.username].close();
|
|
|
327 |
function leaveRoom() {
|
328 |
socket.emit('leave', { token: token, username: username });
|
329 |
localStream.getTracks().forEach(track => track.stop());
|
330 |
+
for (let user in peers) {
|
331 |
+
peers[user].close();
|
332 |
+
}
|
333 |
window.location.href = '/dashboard';
|
334 |
}
|
335 |
</script>
|
|
|
363 |
|
364 |
@socketio.on('signal')
|
365 |
def handle_signal(data):
|
366 |
+
# Пересылаем сигнал всем в комнате, кроме отправителя
|
367 |
emit('signal', data, room=data['token'], skip_sid=request.sid)
|
368 |
|
369 |
if __name__ == '__main__':
|