From 6b3f043332b34922f87b715b26fd4f0a3426fa56 Mon Sep 17 00:00:00 2001 From: Raven Scott Date: Thu, 13 Jun 2024 03:53:23 -0400 Subject: [PATCH] first attempt at audio messages --- app.js | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 1 + style.css | 16 ++++++++ 3 files changed, 127 insertions(+) diff --git a/app.js b/app.js index 2fe4caa..565b1f7 100644 --- a/app.js +++ b/app.js @@ -54,6 +54,7 @@ async function initialize() { const removeRoomBtn = document.querySelector('#remove-room-btn'); const attachFileButton = document.getElementById('attach-file'); const fileInput = document.getElementById('file-input'); + const talkButton = document.getElementById('talk-btn'); if (registerForm) { registerForm.addEventListener('submit', registerUser); @@ -87,6 +88,9 @@ async function initialize() { if (fileInput) { fileInput.addEventListener('change', handleFileInput); } + if (talkButton) { + setupTalkButton(); + } const configExists = fs.existsSync("./config.json"); if (configExists) { @@ -138,6 +142,12 @@ async function initialize() { } } else if (messageObj.type === 'message') { onMessageAdded(messageObj.name, messageObj.message, messageObj.avatar, messageObj.topic); + } else if (messageObj.type === 'audio') { + const audioBuffer = b4a.from(messageObj.audio, 'base64'); + const filePath = `/audio/${Date.now()}.webm`; + await drive.put(filePath, audioBuffer); + const audioUrl = `http://localhost:${servePort}${filePath}`; + addAudioMessage(messageObj.name, audioUrl, messageObj.avatar, messageObj.topic); } else { console.error('Received unknown message type:', messageObj); } @@ -185,6 +195,68 @@ async function initialize() { }); } +function setupTalkButton() { + const talkButton = document.getElementById('talk-btn'); + if (!talkButton) return; + + let mediaRecorder; + let audioChunks = []; + + talkButton.addEventListener('mousedown', async () => { + const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); + mediaRecorder = new MediaRecorder(stream); + mediaRecorder.start(); + + mediaRecorder.addEventListener('dataavailable', event => { + audioChunks.push(event.data); + }); + + mediaRecorder.addEventListener('stop', async () => { + const audioBlob = new Blob(audioChunks); + audioChunks = []; + + const arrayBuffer = await audioBlob.arrayBuffer(); + const buffer = new Uint8Array(arrayBuffer); + + const topic = document.querySelector('#chat-room-topic').innerText; + const filePath = `/audio/${Date.now()}.webm`; + await drive.put(filePath, buffer); + + const audioUrl = `http://localhost:${servePort}${filePath}`; + + const audioMessage = { + type: 'audio', + name: config.userName, + audio: b4a.toString(buffer, 'base64'), + audioType: audioBlob.type, + avatar: updatePortInUrl(config.userAvatar), + topic: topic + }; + + console.log('Sending audio message:', audioMessage); // Debugging log + + const peers = [...swarm.connections]; + for (const peer of peers) { + peer.write(JSON.stringify(audioMessage)); + } + + addAudioMessage(config.userName, audioUrl, config.userAvatar, topic); + }); + }); + + talkButton.addEventListener('mouseup', () => { + if (mediaRecorder) { + mediaRecorder.stop(); + } + }); + + talkButton.addEventListener('mouseleave', () => { + if (mediaRecorder && mediaRecorder.state === 'recording') { + mediaRecorder.stop(); + } + }); +} + function registerUser(e) { e.preventDefault(); const regUsername = document.querySelector('#reg-username').value; @@ -557,6 +629,44 @@ function onMessageAdded(from, message, avatar, topic) { } } +function addAudioMessage(from, audioUrl, avatar, topic) { + console.log('Adding audio message:', { from, audioUrl, avatar, topic }); // Debugging log + const $div = document.createElement('div'); + $div.classList.add('message'); + + const $img = document.createElement('img'); + $img.src = updatePortInUrl(avatar) || 'https://via.placeholder.com/40'; + $img.classList.add('avatar'); + $div.appendChild($img); + + const $content = document.createElement('div'); + $content.classList.add('message-content'); + + const $header = document.createElement('div'); + $header.classList.add('message-header'); + $header.textContent = from; + $content.appendChild($header); + + const $audio = document.createElement('audio'); + $audio.controls = true; + if (from !== config.userName) { + $audio.autoplay = true; // Add autoplay attribute for peers only + } + $audio.src = audioUrl; + $audio.classList.add('attached-audio'); + $content.appendChild($audio); + + $div.appendChild($content); + + // Only render the message if it's for the current room + const currentTopic = document.querySelector('#chat-room-topic').innerText; + if (currentTopic === topic) { + document.querySelector('#messages').appendChild($div); + scrollToBottom(); + } else { + console.log(`Message for topic ${topic} not rendered because current topic is ${currentTopic}`); // Debugging log + } +} function truncateHash(hash) { return `${hash.slice(0, 6)}...${hash.slice(-6)}`; } diff --git a/index.html b/index.html index 0f31c1b..2a8d905 100644 --- a/index.html +++ b/index.html @@ -62,6 +62,7 @@ + diff --git a/style.css b/style.css index 6567450..22f2c79 100644 --- a/style.css +++ b/style.css @@ -268,6 +268,22 @@ textarea::placeholder { margin-left: 0.5rem; /* Add margin between buttons */ } +#talk-btn { + padding: 0.5rem 1rem; /* Add padding to the button */ + margin-left: 0.5rem; /* Add margin between buttons */ + font-size: 14px; + border-radius: 5px; + cursor: pointer; +} + +#talk-btn:active { + color : #fff; /* White text when clicked */ + background-color: #f04747; /* Red color when clicked */ +} + +#talk-btn:hover { +} + /* Main container styles */ main { display: flex;