Projet final V7
This commit is contained in:
parent
7dfe53647e
commit
9dfebe6d21
@ -24,7 +24,7 @@ class VoiceChannel {
|
|||||||
this.pollInterval = null;
|
this.pollInterval = null;
|
||||||
this.canSpeak = true;
|
this.canSpeak = true;
|
||||||
this.remoteAudios = {}; // userId -> Audio element
|
this.remoteAudios = {}; // userId -> Audio element
|
||||||
this.isMuted = false;
|
this.isSelfMuted = false;
|
||||||
this.isDeafened = false;
|
this.isDeafened = false;
|
||||||
|
|
||||||
this.audioContext = null;
|
this.audioContext = null;
|
||||||
@ -125,7 +125,7 @@ class VoiceChannel {
|
|||||||
}
|
}
|
||||||
this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
console.log('Microphone access granted');
|
console.log('Microphone access granted');
|
||||||
this.setMute(true);
|
this.setMute(false); // Join unmuted by default (self-mute off)
|
||||||
|
|
||||||
// Always setup VOX logic for volume meter and detection
|
// Always setup VOX logic for volume meter and detection
|
||||||
this.setupVOX();
|
this.setupVOX();
|
||||||
@ -166,7 +166,7 @@ class VoiceChannel {
|
|||||||
if (!this.myPeerId || !this.currentChannelId) return;
|
if (!this.myPeerId || !this.currentChannelId) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(`api_v1_voice.php?action=poll&room=${this.currentChannelId}&peer_id=${this.myPeerId}&is_muted=${this.isMuted ? 1 : 0}&is_deafened=${this.isDeafened ? 1 : 0}`);
|
const resp = await fetch(`api_v1_voice.php?action=poll&room=${this.currentChannelId}&peer_id=${this.myPeerId}&is_muted=${this.isSelfMuted ? 1 : 0}&is_deafened=${this.isDeafened ? 1 : 0}`);
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
@ -424,12 +424,11 @@ class VoiceChannel {
|
|||||||
console.log('updateMuteState: shouldTalk =', shouldTalk, 'mode =', this.settings.mode, 'canSpeak =', this.canSpeak);
|
console.log('updateMuteState: shouldTalk =', shouldTalk, 'mode =', this.settings.mode, 'canSpeak =', this.canSpeak);
|
||||||
if (this.isTalking !== shouldTalk) {
|
if (this.isTalking !== shouldTalk) {
|
||||||
this.isTalking = shouldTalk;
|
this.isTalking = shouldTalk;
|
||||||
this.setMute(!shouldTalk);
|
this.applyAudioState();
|
||||||
this.updateSpeakingUI(window.currentUserId, shouldTalk);
|
this.updateSpeakingUI(window.currentUserId, shouldTalk);
|
||||||
|
|
||||||
// Notify others
|
// Notify others
|
||||||
const msg = { type: 'voice_speaking', channel_id: this.currentChannelId, user_id: window.currentUserId, speaking: shouldTalk };
|
const msg = { type: 'voice_speaking', channel_id: this.currentChannelId, user_id: window.currentUserId, speaking: shouldTalk };
|
||||||
// ... (rest of method remains same, but I'll update it for clarity)
|
|
||||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||||
this.ws.send(JSON.stringify(msg));
|
this.ws.send(JSON.stringify(msg));
|
||||||
} else {
|
} else {
|
||||||
@ -440,18 +439,25 @@ class VoiceChannel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setMute(mute) {
|
applyAudioState() {
|
||||||
this.isMuted = mute;
|
|
||||||
if (this.localStream) {
|
if (this.localStream) {
|
||||||
console.log('Setting mute to:', mute);
|
const shouldTransmit = !this.isSelfMuted && this.isTalking && this.canSpeak;
|
||||||
this.localStream.getAudioTracks().forEach(track => { track.enabled = !mute; });
|
console.log('applyAudioState: transmitting =', shouldTransmit, '(selfMuted=', this.isSelfMuted, 'talking=', this.isTalking, 'canSpeak=', this.canSpeak, ')');
|
||||||
|
this.localStream.getAudioTracks().forEach(track => {
|
||||||
|
track.enabled = shouldTransmit;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.updateUserPanelButtons();
|
this.updateUserPanelButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMute(mute) {
|
||||||
|
this.isSelfMuted = mute;
|
||||||
|
this.applyAudioState();
|
||||||
|
}
|
||||||
|
|
||||||
toggleMute() {
|
toggleMute() {
|
||||||
if (this.canSpeak === false) return;
|
if (this.canSpeak === false) return;
|
||||||
this.setMute(!this.isMuted);
|
this.setMute(!this.isSelfMuted);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleDeafen() {
|
toggleDeafen() {
|
||||||
@ -462,13 +468,10 @@ class VoiceChannel {
|
|||||||
if (!this.isDeafened) audio.volume = this.settings.outputVolume || 1.0;
|
if (!this.isDeafened) audio.volume = this.settings.outputVolume || 1.0;
|
||||||
});
|
});
|
||||||
// If we deafen, we usually also mute in Discord
|
// If we deafen, we usually also mute in Discord
|
||||||
if (this.isDeafened && !this.isMuted) {
|
if (this.isDeafened && !this.isSelfMuted) {
|
||||||
this.setMute(true);
|
this.setMute(true);
|
||||||
} else if (!this.isDeafened && this.isMuted) {
|
|
||||||
// Not necessarily unmute when undeafen, but often expected
|
|
||||||
// Let's just update UI
|
|
||||||
}
|
}
|
||||||
this.updateUserPanelButtons();
|
this.applyAudioState();
|
||||||
}
|
}
|
||||||
|
|
||||||
setOutputVolume(vol) {
|
setOutputVolume(vol) {
|
||||||
@ -480,14 +483,11 @@ class VoiceChannel {
|
|||||||
|
|
||||||
setInputVolume(vol) {
|
setInputVolume(vol) {
|
||||||
this.settings.inputVolume = parseFloat(vol);
|
this.settings.inputVolume = parseFloat(vol);
|
||||||
// We could use a GainNode here, but for simplicity we'll just store it.
|
|
||||||
// If we want to actually change the transmitted volume, we need to insert a GainNode in the stream.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputDevice(deviceId) {
|
async setInputDevice(deviceId) {
|
||||||
this.settings.inputDevice = deviceId;
|
this.settings.inputDevice = deviceId;
|
||||||
if (this.currentChannelId && this.localStream) {
|
if (this.currentChannelId && this.localStream) {
|
||||||
// Re-join or switch track
|
|
||||||
const constraints = {
|
const constraints = {
|
||||||
audio: {
|
audio: {
|
||||||
echoCancellation: this.settings.echoCancellation,
|
echoCancellation: this.settings.echoCancellation,
|
||||||
@ -510,7 +510,7 @@ class VoiceChannel {
|
|||||||
this.localStream.getTracks().forEach(t => t.stop());
|
this.localStream.getTracks().forEach(t => t.stop());
|
||||||
this.localStream = newStream;
|
this.localStream = newStream;
|
||||||
this.setupVOX();
|
this.setupVOX();
|
||||||
this.setMute(this.isMuted);
|
this.applyAudioState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +549,7 @@ class VoiceChannel {
|
|||||||
this.localStream.getTracks().forEach(t => t.stop());
|
this.localStream.getTracks().forEach(t => t.stop());
|
||||||
this.localStream = newStream;
|
this.localStream = newStream;
|
||||||
this.setupVOX();
|
this.setupVOX();
|
||||||
this.setMute(this.isMuted);
|
this.applyAudioState();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to update audio constraints:', e);
|
console.error('Failed to update audio constraints:', e);
|
||||||
}
|
}
|
||||||
@ -560,7 +560,7 @@ class VoiceChannel {
|
|||||||
const btnMute = document.getElementById('btn-panel-mute');
|
const btnMute = document.getElementById('btn-panel-mute');
|
||||||
const btnDeafen = document.getElementById('btn-panel-deafen');
|
const btnDeafen = document.getElementById('btn-panel-deafen');
|
||||||
|
|
||||||
let displayMuted = this.isMuted;
|
let displayMuted = this.isSelfMuted;
|
||||||
if (this.canSpeak === false) {
|
if (this.canSpeak === false) {
|
||||||
displayMuted = true;
|
displayMuted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
assets/pasted-20260219-144524-4a4fe8eb.png
Normal file
BIN
assets/pasted-20260219-144524-4a4fe8eb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
assets/pasted-20260219-145037-ae47b380.png
Normal file
BIN
assets/pasted-20260219-145037-ae47b380.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 230 KiB |
@ -319,7 +319,7 @@ if ($is_dm_view) {
|
|||||||
|
|
||||||
// Fetch voice sessions for the sidebar
|
// Fetch voice sessions for the sidebar
|
||||||
$stmt_vs = db()->prepare("
|
$stmt_vs = db()->prepare("
|
||||||
SELECT vs.channel_id, vs.user_id, u.username, u.display_name, u.avatar_url
|
SELECT vs.channel_id, vs.user_id, vs.is_muted, vs.is_deafened, u.username, u.display_name, u.avatar_url
|
||||||
FROM voice_sessions vs
|
FROM voice_sessions vs
|
||||||
JOIN users u ON vs.user_id = u.id
|
JOIN users u ON vs.user_id = u.id
|
||||||
WHERE vs.last_seen > ?
|
WHERE vs.last_seen > ?
|
||||||
@ -573,7 +573,12 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
|||||||
<?php foreach($voice_users_by_channel[$c['id']] as $v_user): ?>
|
<?php foreach($voice_users_by_channel[$c['id']] as $v_user): ?>
|
||||||
<div class="voice-user small text-muted d-flex align-items-center mb-1" data-user-id="<?php echo $v_user['user_id']; ?>">
|
<div class="voice-user small text-muted d-flex align-items-center mb-1" data-user-id="<?php echo $v_user['user_id']; ?>">
|
||||||
<div class="message-avatar me-2" style="width: 16px; height: 16px; <?php echo $v_user['avatar_url'] ? "background-image: url('{$v_user['avatar_url']}');" : ""; ?>"></div>
|
<div class="message-avatar me-2" style="width: 16px; height: 16px; <?php echo $v_user['avatar_url'] ? "background-image: url('{$v_user['avatar_url']}');" : ""; ?>"></div>
|
||||||
<span style="font-size: 13px;"><?php echo htmlspecialchars($v_user['display_name'] ?? $v_user['username']); ?></span>
|
<span class="text-truncate" style="font-size: 13px; max-width: 100px;"><?php echo htmlspecialchars($v_user['display_name'] ?? $v_user['username']); ?></span>
|
||||||
|
<?php if ($v_user['is_deafened']): ?>
|
||||||
|
<i class="fa-solid fa-volume-xmark ms-auto text-danger" style="font-size: 10px;"></i>
|
||||||
|
<?php elseif ($v_user['is_muted']): ?>
|
||||||
|
<i class="fa-solid fa-microphone-slash ms-auto text-danger" style="font-size: 10px;"></i>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user