Update main.py
Browse files
main.py
CHANGED
|
@@ -113,6 +113,7 @@ HTML_TEMPLATE = '''
|
|
| 113 |
margin-top: 10px;
|
| 114 |
border-radius: 15px;
|
| 115 |
font-size: 14px;
|
|
|
|
| 116 |
}
|
| 117 |
|
| 118 |
.messages-container {
|
|
@@ -299,12 +300,14 @@ HTML_TEMPLATE = '''
|
|
| 299 |
z-index: 100;
|
| 300 |
max-height: 200px;
|
| 301 |
overflow-y: auto;
|
|
|
|
| 302 |
}
|
| 303 |
|
| 304 |
.user-item {
|
| 305 |
-
padding:
|
| 306 |
border-bottom: 1px solid #eee;
|
| 307 |
cursor: pointer;
|
|
|
|
| 308 |
}
|
| 309 |
|
| 310 |
.user-item:last-child {
|
|
@@ -314,6 +317,20 @@ HTML_TEMPLATE = '''
|
|
| 314 |
.user-item:active {
|
| 315 |
background: #f0f0f0;
|
| 316 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
</style>
|
| 318 |
</head>
|
| 319 |
<body>
|
|
@@ -336,6 +353,10 @@ HTML_TEMPLATE = '''
|
|
| 336 |
<h2>💬 Мессенджер</h2>
|
| 337 |
<div class="online-users" onclick="toggleUserList()">
|
| 338 |
Онлайн: <span id="onlineCount">0</span> пользователей
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
</div>
|
| 340 |
<div id="userList" class="user-list"></div>
|
| 341 |
</div>
|
|
@@ -362,7 +383,7 @@ HTML_TEMPLATE = '''
|
|
| 362 |
<div id="recordingOverlay" class="recording-overlay">
|
| 363 |
<div class="recording-animation"></div>
|
| 364 |
<h3>Запись голосового сообщения...</h3>
|
| 365 |
-
<p
|
| 366 |
</div>
|
| 367 |
|
| 368 |
<script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
|
|
@@ -377,6 +398,7 @@ HTML_TEMPLATE = '''
|
|
| 377 |
let peerConnection = null;
|
| 378 |
let currentCall = null;
|
| 379 |
let selectedUser = null;
|
|
|
|
| 380 |
|
| 381 |
// WebRTC configuration
|
| 382 |
const rtcConfig = {
|
|
@@ -395,11 +417,11 @@ HTML_TEMPLATE = '''
|
|
| 395 |
currentUser = data;
|
| 396 |
document.getElementById('loginScreen').style.display = 'none';
|
| 397 |
document.getElementById('chatScreen').style.display = 'flex';
|
| 398 |
-
updateUserList();
|
| 399 |
});
|
| 400 |
|
| 401 |
socket.on('user_list_update', (data) => {
|
| 402 |
document.getElementById('onlineCount').textContent = data.count;
|
|
|
|
| 403 |
updateUserList();
|
| 404 |
});
|
| 405 |
|
|
@@ -499,6 +521,12 @@ HTML_TEMPLATE = '''
|
|
| 499 |
|
| 500 |
container.appendChild(messageDiv);
|
| 501 |
container.scrollTop = container.scrollHeight;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
}
|
| 503 |
|
| 504 |
function displayVoiceMessage(data) {
|
|
@@ -526,13 +554,25 @@ HTML_TEMPLATE = '''
|
|
| 526 |
const userList = document.getElementById('userList');
|
| 527 |
userList.innerHTML = '';
|
| 528 |
|
| 529 |
-
|
| 530 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 531 |
const userItem = document.createElement('div');
|
| 532 |
userItem.className = 'user-item';
|
| 533 |
-
userItem.textContent = user
|
| 534 |
userItem.onclick = () => {
|
| 535 |
-
selectedUser = user
|
|
|
|
|
|
|
| 536 |
userList.style.display = 'none';
|
| 537 |
};
|
| 538 |
userList.appendChild(userItem);
|
|
@@ -542,6 +582,10 @@ HTML_TEMPLATE = '''
|
|
| 542 |
|
| 543 |
function toggleUserList() {
|
| 544 |
const userList = document.getElementById('userList');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 545 |
userList.style.display = userList.style.display === 'block' ? 'none' : 'block';
|
| 546 |
}
|
| 547 |
|
|
@@ -617,42 +661,48 @@ HTML_TEMPLATE = '''
|
|
| 617 |
|
| 618 |
function playVoiceMessage(filename) {
|
| 619 |
const audio = new Audio(`/voice/${filename}`);
|
| 620 |
-
audio.play();
|
| 621 |
}
|
| 622 |
|
| 623 |
// WebRTC Functions
|
| 624 |
async function createPeerConnection(isCaller) {
|
| 625 |
-
|
| 626 |
-
|
| 627 |
-
// Add local stream if available
|
| 628 |
-
if (localStream) {
|
| 629 |
-
localStream.getTracks().forEach(track => {
|
| 630 |
-
peerConnection.addTrack(track, localStream);
|
| 631 |
-
});
|
| 632 |
-
}
|
| 633 |
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
};
|
| 639 |
-
|
| 640 |
-
// Handle ICE candidates
|
| 641 |
-
peerConnection.onicecandidate = (event) => {
|
| 642 |
-
if (event.candidate) {
|
| 643 |
-
socket.emit('webrtc_ice_candidate', {
|
| 644 |
-
candidate: event.candidate,
|
| 645 |
-
to_user: selectedUser || Object.values(users).find(u => u.username !== currentUser.username)?.username
|
| 646 |
});
|
| 647 |
}
|
| 648 |
-
};
|
| 649 |
|
| 650 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 651 |
}
|
| 652 |
|
| 653 |
async function startAudioCall() {
|
| 654 |
if (!selectedUser) {
|
| 655 |
-
alert('
|
| 656 |
toggleUserList();
|
| 657 |
return;
|
| 658 |
}
|
|
@@ -661,7 +711,7 @@ HTML_TEMPLATE = '''
|
|
| 661 |
|
| 662 |
async function startVideoCall() {
|
| 663 |
if (!selectedUser) {
|
| 664 |
-
alert('
|
| 665 |
toggleUserList();
|
| 666 |
return;
|
| 667 |
}
|
|
@@ -677,8 +727,7 @@ HTML_TEMPLATE = '''
|
|
| 677 |
audio: true,
|
| 678 |
video: isVideo ? {
|
| 679 |
width: { ideal: 1280 },
|
| 680 |
-
height: { ideal: 720 }
|
| 681 |
-
frameRate: { ideal: 30 }
|
| 682 |
} : false
|
| 683 |
};
|
| 684 |
|
|
@@ -694,9 +743,11 @@ HTML_TEMPLATE = '''
|
|
| 694 |
|
| 695 |
socket.emit('webrtc_offer', {
|
| 696 |
offer: offer,
|
| 697 |
-
to_user: targetUser
|
|
|
|
| 698 |
});
|
| 699 |
|
|
|
|
| 700 |
socket.emit('call_request', {
|
| 701 |
call_id: Date.now().toString(),
|
| 702 |
from_user: currentUser.username,
|
|
@@ -727,40 +778,26 @@ HTML_TEMPLATE = '''
|
|
| 727 |
currentCall = null;
|
| 728 |
}
|
| 729 |
|
| 730 |
-
function toggleMute() {
|
| 731 |
-
if (localStream) {
|
| 732 |
-
const audioTrack = localStream.getAudioTracks()[0];
|
| 733 |
-
if (audioTrack) {
|
| 734 |
-
audioTrack.enabled = !audioTrack.enabled;
|
| 735 |
-
}
|
| 736 |
-
}
|
| 737 |
-
}
|
| 738 |
-
|
| 739 |
-
function toggleVideo() {
|
| 740 |
-
if (localStream) {
|
| 741 |
-
const videoTrack = localStream.getVideoTracks()[0];
|
| 742 |
-
if (videoTrack) {
|
| 743 |
-
videoTrack.enabled = !videoTrack.enabled;
|
| 744 |
-
}
|
| 745 |
-
}
|
| 746 |
-
}
|
| 747 |
-
|
| 748 |
// Touch events for voice recording
|
| 749 |
let recordingTimer;
|
| 750 |
-
document.querySelector('.action-btn[title="Голосовое сообщение"]')
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
| 754 |
-
|
| 755 |
-
|
|
|
|
|
|
|
|
|
|
| 756 |
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
|
|
|
| 764 |
|
| 765 |
// Click on recording overlay to stop
|
| 766 |
document.getElementById('recordingOverlay').addEventListener('click', stopRecording);
|
|
@@ -778,12 +815,17 @@ HTML_TEMPLATE = '''
|
|
| 778 |
}
|
| 779 |
});
|
| 780 |
|
| 781 |
-
//
|
| 782 |
-
document.addEventListener('
|
| 783 |
-
if (e.target.
|
| 784 |
-
|
| 785 |
}
|
| 786 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 787 |
</script>
|
| 788 |
</body>
|
| 789 |
</html>
|
|
@@ -796,6 +838,11 @@ def index():
|
|
| 796 |
@socketio.on('connect')
|
| 797 |
def handle_connect():
|
| 798 |
print(f'Client connected: {request.sid}')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 799 |
|
| 800 |
@socketio.on('disconnect')
|
| 801 |
def handle_disconnect():
|
|
@@ -803,7 +850,11 @@ def handle_disconnect():
|
|
| 803 |
if user_data.get('sid') == request.sid:
|
| 804 |
del users[user_id]
|
| 805 |
break
|
| 806 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
|
| 808 |
@socketio.on('register')
|
| 809 |
def handle_register(username):
|
|
@@ -819,7 +870,10 @@ def handle_register(username):
|
|
| 819 |
'username': username
|
| 820 |
})
|
| 821 |
|
| 822 |
-
emit('user_list_update', {
|
|
|
|
|
|
|
|
|
|
| 823 |
|
| 824 |
@socketio.on('message')
|
| 825 |
def handle_message(data):
|
|
@@ -883,7 +937,7 @@ def handle_call_answer(data):
|
|
| 883 |
if target_sid:
|
| 884 |
emit('call_answered', {
|
| 885 |
'answer': data['answer'],
|
| 886 |
-
'from_user': data.get('from_user'),
|
| 887 |
'isVideo': data.get('isVideo', False)
|
| 888 |
}, room=target_sid)
|
| 889 |
|
|
|
|
| 113 |
margin-top: 10px;
|
| 114 |
border-radius: 15px;
|
| 115 |
font-size: 14px;
|
| 116 |
+
cursor: pointer;
|
| 117 |
}
|
| 118 |
|
| 119 |
.messages-container {
|
|
|
|
| 300 |
z-index: 100;
|
| 301 |
max-height: 200px;
|
| 302 |
overflow-y: auto;
|
| 303 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
| 304 |
}
|
| 305 |
|
| 306 |
.user-item {
|
| 307 |
+
padding: 12px 15px;
|
| 308 |
border-bottom: 1px solid #eee;
|
| 309 |
cursor: pointer;
|
| 310 |
+
color: #333;
|
| 311 |
}
|
| 312 |
|
| 313 |
.user-item:last-child {
|
|
|
|
| 317 |
.user-item:active {
|
| 318 |
background: #f0f0f0;
|
| 319 |
}
|
| 320 |
+
|
| 321 |
+
.selected-user {
|
| 322 |
+
margin-top: 10px;
|
| 323 |
+
font-size: 14px;
|
| 324 |
+
background: rgba(255,255,255,0.3);
|
| 325 |
+
padding: 8px 12px;
|
| 326 |
+
border-radius: 15px;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
.call-info {
|
| 330 |
+
margin-top: 5px;
|
| 331 |
+
font-size: 12px;
|
| 332 |
+
opacity: 0.9;
|
| 333 |
+
}
|
| 334 |
</style>
|
| 335 |
</head>
|
| 336 |
<body>
|
|
|
|
| 353 |
<h2>💬 Мессенджер</h2>
|
| 354 |
<div class="online-users" onclick="toggleUserList()">
|
| 355 |
Онлайн: <span id="onlineCount">0</span> пользователей
|
| 356 |
+
<div class="call-info">Нажмите для выбора</div>
|
| 357 |
+
</div>
|
| 358 |
+
<div id="selectedUserInfo" class="selected-user" style="display: none;">
|
| 359 |
+
Выбрано: <span id="selectedUserName">-</span>
|
| 360 |
</div>
|
| 361 |
<div id="userList" class="user-list"></div>
|
| 362 |
</div>
|
|
|
|
| 383 |
<div id="recordingOverlay" class="recording-overlay">
|
| 384 |
<div class="recording-animation"></div>
|
| 385 |
<h3>Запись голосового сообщения...</h3>
|
| 386 |
+
<p>Нажмите для остановки</p>
|
| 387 |
</div>
|
| 388 |
|
| 389 |
<script src="https://cdn.socket.io/4.5.0/socket.io.min.js"></script>
|
|
|
|
| 398 |
let peerConnection = null;
|
| 399 |
let currentCall = null;
|
| 400 |
let selectedUser = null;
|
| 401 |
+
let onlineUsers = [];
|
| 402 |
|
| 403 |
// WebRTC configuration
|
| 404 |
const rtcConfig = {
|
|
|
|
| 417 |
currentUser = data;
|
| 418 |
document.getElementById('loginScreen').style.display = 'none';
|
| 419 |
document.getElementById('chatScreen').style.display = 'flex';
|
|
|
|
| 420 |
});
|
| 421 |
|
| 422 |
socket.on('user_list_update', (data) => {
|
| 423 |
document.getElementById('onlineCount').textContent = data.count;
|
| 424 |
+
onlineUsers = data.users || [];
|
| 425 |
updateUserList();
|
| 426 |
});
|
| 427 |
|
|
|
|
| 521 |
|
| 522 |
container.appendChild(messageDiv);
|
| 523 |
container.scrollTop = container.scrollHeight;
|
| 524 |
+
|
| 525 |
+
// Убираем placeholder если есть сообщения
|
| 526 |
+
const placeholder = container.querySelector('div[style*="text-align: center"]');
|
| 527 |
+
if (placeholder) {
|
| 528 |
+
placeholder.remove();
|
| 529 |
+
}
|
| 530 |
}
|
| 531 |
|
| 532 |
function displayVoiceMessage(data) {
|
|
|
|
| 554 |
const userList = document.getElementById('userList');
|
| 555 |
userList.innerHTML = '';
|
| 556 |
|
| 557 |
+
if (onlineUsers.length === 0) {
|
| 558 |
+
const emptyItem = document.createElement('div');
|
| 559 |
+
emptyItem.className = 'user-item';
|
| 560 |
+
emptyItem.textContent = 'Нет других пользователей онлайн';
|
| 561 |
+
emptyItem.style.color = '#999';
|
| 562 |
+
emptyItem.style.cursor = 'default';
|
| 563 |
+
userList.appendChild(emptyItem);
|
| 564 |
+
return;
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
onlineUsers.forEach(user => {
|
| 568 |
+
if (user !== currentUser.username) {
|
| 569 |
const userItem = document.createElement('div');
|
| 570 |
userItem.className = 'user-item';
|
| 571 |
+
userItem.textContent = user;
|
| 572 |
userItem.onclick = () => {
|
| 573 |
+
selectedUser = user;
|
| 574 |
+
document.getElementById('selectedUserName').textContent = user;
|
| 575 |
+
document.getElementById('selectedUserInfo').style.display = 'block';
|
| 576 |
userList.style.display = 'none';
|
| 577 |
};
|
| 578 |
userList.appendChild(userItem);
|
|
|
|
| 582 |
|
| 583 |
function toggleUserList() {
|
| 584 |
const userList = document.getElementById('userList');
|
| 585 |
+
if (onlineUsers.length <= 1) {
|
| 586 |
+
alert('Нет других пользователей онлайн');
|
| 587 |
+
return;
|
| 588 |
+
}
|
| 589 |
userList.style.display = userList.style.display === 'block' ? 'none' : 'block';
|
| 590 |
}
|
| 591 |
|
|
|
|
| 661 |
|
| 662 |
function playVoiceMessage(filename) {
|
| 663 |
const audio = new Audio(`/voice/${filename}`);
|
| 664 |
+
audio.play().catch(e => console.error('Error playing audio:', e));
|
| 665 |
}
|
| 666 |
|
| 667 |
// WebRTC Functions
|
| 668 |
async function createPeerConnection(isCaller) {
|
| 669 |
+
try {
|
| 670 |
+
peerConnection = new RTCPeerConnection(rtcConfig);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
|
| 672 |
+
// Add local stream if available
|
| 673 |
+
if (localStream) {
|
| 674 |
+
localStream.getTracks().forEach(track => {
|
| 675 |
+
peerConnection.addTrack(track, localStream);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 676 |
});
|
| 677 |
}
|
|
|
|
| 678 |
|
| 679 |
+
// Handle incoming tracks
|
| 680 |
+
peerConnection.ontrack = (event) => {
|
| 681 |
+
remoteStream = event.streams[0];
|
| 682 |
+
// Можно добавить отображение удаленного видео
|
| 683 |
+
console.log('Remote track received');
|
| 684 |
+
};
|
| 685 |
+
|
| 686 |
+
// Handle ICE candidates
|
| 687 |
+
peerConnection.onicecandidate = (event) => {
|
| 688 |
+
if (event.candidate && selectedUser) {
|
| 689 |
+
socket.emit('webrtc_ice_candidate', {
|
| 690 |
+
candidate: event.candidate,
|
| 691 |
+
to_user: selectedUser
|
| 692 |
+
});
|
| 693 |
+
}
|
| 694 |
+
};
|
| 695 |
+
|
| 696 |
+
return peerConnection;
|
| 697 |
+
} catch (error) {
|
| 698 |
+
console.error('Error creating peer connection:', error);
|
| 699 |
+
throw error;
|
| 700 |
+
}
|
| 701 |
}
|
| 702 |
|
| 703 |
async function startAudioCall() {
|
| 704 |
if (!selectedUser) {
|
| 705 |
+
alert('Сначала выберите пользователя из списка онлайн (нажмите на "Онлайн: X пользователей")');
|
| 706 |
toggleUserList();
|
| 707 |
return;
|
| 708 |
}
|
|
|
|
| 711 |
|
| 712 |
async function startVideoCall() {
|
| 713 |
if (!selectedUser) {
|
| 714 |
+
alert('Сначала выберите пользователя из списка онлайн (нажмите на "Онлайн: X пользователей")');
|
| 715 |
toggleUserList();
|
| 716 |
return;
|
| 717 |
}
|
|
|
|
| 727 |
audio: true,
|
| 728 |
video: isVideo ? {
|
| 729 |
width: { ideal: 1280 },
|
| 730 |
+
height: { ideal: 720 }
|
|
|
|
| 731 |
} : false
|
| 732 |
};
|
| 733 |
|
|
|
|
| 743 |
|
| 744 |
socket.emit('webrtc_offer', {
|
| 745 |
offer: offer,
|
| 746 |
+
to_user: targetUser,
|
| 747 |
+
isVideo: isVideo
|
| 748 |
});
|
| 749 |
|
| 750 |
+
// Send call request
|
| 751 |
socket.emit('call_request', {
|
| 752 |
call_id: Date.now().toString(),
|
| 753 |
from_user: currentUser.username,
|
|
|
|
| 778 |
currentCall = null;
|
| 779 |
}
|
| 780 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 781 |
// Touch events for voice recording
|
| 782 |
let recordingTimer;
|
| 783 |
+
const voiceBtn = document.querySelector('.action-btn[title="Голосовое сообщение"]');
|
| 784 |
+
|
| 785 |
+
if (voiceBtn) {
|
| 786 |
+
voiceBtn.addEventListener('touchstart', function(e) {
|
| 787 |
+
e.preventDefault();
|
| 788 |
+
recordingTimer = setTimeout(() => {
|
| 789 |
+
startRecording();
|
| 790 |
+
}, 500);
|
| 791 |
+
});
|
| 792 |
|
| 793 |
+
voiceBtn.addEventListener('touchend', function(e) {
|
| 794 |
+
e.preventDefault();
|
| 795 |
+
clearTimeout(recordingTimer);
|
| 796 |
+
if (isRecording) {
|
| 797 |
+
stopRecording();
|
| 798 |
+
}
|
| 799 |
+
});
|
| 800 |
+
}
|
| 801 |
|
| 802 |
// Click on recording overlay to stop
|
| 803 |
document.getElementById('recordingOverlay').addEventListener('click', stopRecording);
|
|
|
|
| 815 |
}
|
| 816 |
});
|
| 817 |
|
| 818 |
+
// Close user list when clicking outside
|
| 819 |
+
document.addEventListener('click', (e) => {
|
| 820 |
+
if (!e.target.closest('.online-users') && !e.target.closest('.user-list')) {
|
| 821 |
+
document.getElementById('userList').style.display = 'none';
|
| 822 |
}
|
| 823 |
});
|
| 824 |
+
|
| 825 |
+
// Initialize
|
| 826 |
+
window.onload = function() {
|
| 827 |
+
onlineUsers = [];
|
| 828 |
+
};
|
| 829 |
</script>
|
| 830 |
</body>
|
| 831 |
</html>
|
|
|
|
| 838 |
@socketio.on('connect')
|
| 839 |
def handle_connect():
|
| 840 |
print(f'Client connected: {request.sid}')
|
| 841 |
+
# Send current user list to the newly connected client
|
| 842 |
+
emit('user_list_update', {
|
| 843 |
+
'count': len(users),
|
| 844 |
+
'users': [user_data['username'] for user_data in users.values()]
|
| 845 |
+
})
|
| 846 |
|
| 847 |
@socketio.on('disconnect')
|
| 848 |
def handle_disconnect():
|
|
|
|
| 850 |
if user_data.get('sid') == request.sid:
|
| 851 |
del users[user_id]
|
| 852 |
break
|
| 853 |
+
|
| 854 |
+
emit('user_list_update', {
|
| 855 |
+
'count': len(users),
|
| 856 |
+
'users': [user_data['username'] for user_data in users.values()]
|
| 857 |
+
}, broadcast=True)
|
| 858 |
|
| 859 |
@socketio.on('register')
|
| 860 |
def handle_register(username):
|
|
|
|
| 870 |
'username': username
|
| 871 |
})
|
| 872 |
|
| 873 |
+
emit('user_list_update', {
|
| 874 |
+
'count': len(users),
|
| 875 |
+
'users': [user_data['username'] for user_data in users.values()]
|
| 876 |
+
}, broadcast=True)
|
| 877 |
|
| 878 |
@socketio.on('message')
|
| 879 |
def handle_message(data):
|
|
|
|
| 937 |
if target_sid:
|
| 938 |
emit('call_answered', {
|
| 939 |
'answer': data['answer'],
|
| 940 |
+
'from_user': data.get('from_user', current_user),
|
| 941 |
'isVideo': data.get('isVideo', False)
|
| 942 |
}, room=target_sid)
|
| 943 |
|