From 7aed891838b920079723d359948ab20f242a4372 Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Fri, 3 Jan 2025 23:14:18 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20stream=20back=20audio=20to?= =?UTF-8?q?=20user=20(test)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/package.json | 1 - .../services/WebSocket/WebSocketServer.js | 27 +++---- client/src/components/Chat/Input/Call.tsx | 38 +++++++++- client/src/hooks/useCall.ts | 60 ++++++++++++++- client/src/services/WebRTC/WebRTCService.ts | 73 ++++++++++++------- package-lock.json | 1 - 6 files changed, 151 insertions(+), 49 deletions(-) diff --git a/api/package.json b/api/package.json index 8fc6b73384..d2021dc7d6 100644 --- a/api/package.json +++ b/api/package.json @@ -82,7 +82,6 @@ "mongoose": "^8.9.5", "multer": "^1.4.5-lts.1", "nanoid": "^3.3.7", - "node-pre-gyp": "^0.17.0", "nodemailer": "^6.9.15", "ollama": "^0.5.0", "openai": "^4.47.1", diff --git a/api/server/services/WebSocket/WebSocketServer.js b/api/server/services/WebSocket/WebSocketServer.js index b5339377c2..268073bb7c 100644 --- a/api/server/services/WebSocket/WebSocketServer.js +++ b/api/server/services/WebSocket/WebSocketServer.js @@ -1,5 +1,5 @@ const { Server } = require('socket.io'); -const { RTCPeerConnection, RTCIceCandidate } = require('wrtc'); +const { RTCPeerConnection, RTCIceCandidate, MediaStream } = require('wrtc'); class WebRTCConnection { constructor(socket, config) { @@ -14,38 +14,31 @@ class WebRTCConnection { async handleOffer(offer) { try { - // Create new peer connection if needed if (!this.peerConnection) { this.peerConnection = new RTCPeerConnection(this.config.rtcConfig); this.setupPeerConnectionListeners(); } - // Set the remote description (client's offer) await this.peerConnection.setRemoteDescription(offer); - // Set up audio transceiver for two-way audio + // Create MediaStream instance properly + const mediaStream = new MediaStream(); + this.audioTransceiver = this.peerConnection.addTransceiver('audio', { direction: 'sendrecv', + streams: [mediaStream], }); - // Create and set local description (answer) const answer = await this.peerConnection.createAnswer(); await this.peerConnection.setLocalDescription(answer); - - // Send answer to client this.socket.emit('webrtc-answer', answer); - - // Process any pending ICE candidates - while (this.pendingCandidates.length) { - const candidate = this.pendingCandidates.shift(); - await this.addIceCandidate(candidate); - } - - this.state = 'connecting'; } catch (error) { this.log(`Error handling offer: ${error}`, 'error'); - this.socket.emit('error', { message: 'Failed to process offer' }); - this.cleanup(); + // Don't throw, handle gracefully + this.socket.emit('webrtc-error', { + message: error.message, + code: 'OFFER_ERROR', + }); } } diff --git a/client/src/components/Chat/Input/Call.tsx b/client/src/components/Chat/Input/Call.tsx index 15021a6801..c60900a68a 100644 --- a/client/src/components/Chat/Input/Call.tsx +++ b/client/src/components/Chat/Input/Call.tsx @@ -43,6 +43,8 @@ export const Call: React.FC = () => { useEffect(() => { if (remoteAudioRef.current && remoteStream) { remoteAudioRef.current.srcObject = remoteStream; + + remoteAudioRef.current.play().catch((err) => console.error('Error playing audio:', err)); } }, [remoteStream]); @@ -98,6 +100,36 @@ export const Call: React.FC = () => { const isActive = callState === CallState.ACTIVE; const isError = callState === CallState.ERROR; + // TESTS + + useEffect(() => { + if (remoteAudioRef.current && remoteStream) { + console.log('Setting up remote audio:', { + tracks: remoteStream.getTracks().length, + active: remoteStream.active, + }); + + remoteAudioRef.current.srcObject = remoteStream; + remoteAudioRef.current.muted = false; + remoteAudioRef.current.volume = 1.0; + + const playPromise = remoteAudioRef.current.play(); + if (playPromise) { + playPromise.catch((err) => { + console.error('Error playing audio:', err); + // Retry play on user interaction + document.addEventListener( + 'click', + () => { + remoteAudioRef.current?.play(); + }, + { once: true }, + ); + }); + } + } + }, [remoteStream]); + return ( @@ -200,7 +232,11 @@ export const Call: React.FC = () => { {/* Hidden Audio Element */} -