cduss commited on
Commit
55f8404
·
1 Parent(s): 94a9cda

retroo support one directional audio

Browse files
Files changed (1) hide show
  1. index.html +31 -23
index.html CHANGED
@@ -638,6 +638,7 @@
638
  // Microphone state (for speaking through the robot)
639
  let localMicStream = null;
640
  let isMicMuted = true; // Default mic off
 
641
 
642
  // Export functions
643
  window.loginToHuggingFace = loginToHuggingFace;
@@ -835,28 +836,24 @@
835
  isMuted = true;
836
  updateMuteButton();
837
 
838
- // Capture microphone for bidirectional audio (speak through robot)
 
 
839
  try {
840
  localMicStream = await navigator.mediaDevices.getUserMedia({ audio: true });
841
  localMicStream.getAudioTracks().forEach(t => t.enabled = false); // Start muted
842
  isMicMuted = true;
843
- updateMicButton();
844
  } catch (e) {
845
  console.warn('Microphone not available, speak-through-robot disabled:', e);
846
  localMicStream = null;
847
  }
848
 
 
 
849
  peerConnection = new RTCPeerConnection({
850
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
851
  });
852
 
853
- // Add mic track to PeerConnection (before SDP exchange)
854
- if (localMicStream) {
855
- for (const track of localMicStream.getAudioTracks()) {
856
- peerConnection.addTrack(track, localMicStream);
857
- }
858
- }
859
-
860
  peerConnection.ontrack = (e) => {
861
  if (e.track.kind === 'video') {
862
  const video = document.getElementById('remoteVideo');
@@ -907,16 +904,26 @@
907
  if (!peerConnection) return;
908
  try {
909
  if (msg.sdp) {
910
- let sdp = msg.sdp;
911
- // If we have a mic, ensure audio is sendrecv for bidirectional audio
912
- if (sdp.type === 'offer' && localMicStream) {
913
- sdp = { ...sdp, sdp: makeAudioBidirectional(sdp.sdp) };
914
- }
915
- await peerConnection.setRemoteDescription(new RTCSessionDescription(sdp));
916
  if (sdp.type === 'offer') {
 
 
 
 
 
 
 
 
 
 
 
 
917
  const answer = await peerConnection.createAnswer();
918
  await peerConnection.setLocalDescription(answer);
919
  await sendToServer({ type: 'peer', sessionId: currentSessionId, sdp: { type: 'answer', sdp: answer.sdp } });
 
 
920
  }
921
  }
922
  if (msg.ice) {
@@ -963,6 +970,7 @@
963
  localMicStream = null;
964
  }
965
  isMicMuted = true;
 
966
 
967
  if (peerConnection) peerConnection.close();
968
  if (dataChannel) dataChannel.close();
@@ -981,7 +989,7 @@
981
  function enableControls(enabled) {
982
  document.getElementById('btnPlaySound').disabled = !enabled;
983
  document.getElementById('muteBtn').disabled = !enabled;
984
- document.getElementById('micBtn').disabled = !enabled || !localMicStream;
985
  }
986
 
987
  function toggleMute() {
@@ -1035,17 +1043,17 @@
1035
  }
1036
  }
1037
 
1038
- function makeAudioBidirectional(sdp) {
1039
- // Change audio section direction from sendonly to sendrecv
1040
- // so the browser can send microphone audio to the robot
1041
  const lines = sdp.split('\r\n');
1042
  let inAudioSection = false;
1043
- return lines.map(line => {
1044
  if (line.startsWith('m=audio')) inAudioSection = true;
1045
  else if (line.startsWith('m=')) inAudioSection = false;
1046
- if (inAudioSection && line === 'a=sendonly') return 'a=sendrecv';
1047
- return line;
1048
- }).join('\r\n');
1049
  }
1050
 
1051
  // ===================== Robot State =====================
 
638
  // Microphone state (for speaking through the robot)
639
  let localMicStream = null;
640
  let isMicMuted = true; // Default mic off
641
+ let robotSupportsMic = false; // Whether robot's SDP offers sendrecv audio
642
 
643
  // Export functions
644
  window.loginToHuggingFace = loginToHuggingFace;
 
836
  isMuted = true;
837
  updateMuteButton();
838
 
839
+ // Capture microphone eagerly (for permission prompt), but do NOT add
840
+ // the track to the PeerConnection yet. We only add it after seeing
841
+ // the robot's SDP offer to confirm it supports bidirectional audio.
842
  try {
843
  localMicStream = await navigator.mediaDevices.getUserMedia({ audio: true });
844
  localMicStream.getAudioTracks().forEach(t => t.enabled = false); // Start muted
845
  isMicMuted = true;
 
846
  } catch (e) {
847
  console.warn('Microphone not available, speak-through-robot disabled:', e);
848
  localMicStream = null;
849
  }
850
 
851
+ robotSupportsMic = false;
852
+
853
  peerConnection = new RTCPeerConnection({
854
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
855
  });
856
 
 
 
 
 
 
 
 
857
  peerConnection.ontrack = (e) => {
858
  if (e.track.kind === 'video') {
859
  const video = document.getElementById('remoteVideo');
 
904
  if (!peerConnection) return;
905
  try {
906
  if (msg.sdp) {
907
+ const sdp = msg.sdp;
908
+
 
 
 
 
909
  if (sdp.type === 'offer') {
910
+ // Check if robot supports bidirectional audio (sendrecv)
911
+ robotSupportsMic = sdpHasAudioSendRecv(sdp.sdp);
912
+
913
+ // Add mic track BEFORE setRemoteDescription so the
914
+ // answer naturally includes sendrecv for audio.
915
+ if (robotSupportsMic && localMicStream) {
916
+ for (const track of localMicStream.getAudioTracks()) {
917
+ peerConnection.addTrack(track, localMicStream);
918
+ }
919
+ }
920
+
921
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(sdp));
922
  const answer = await peerConnection.createAnswer();
923
  await peerConnection.setLocalDescription(answer);
924
  await sendToServer({ type: 'peer', sessionId: currentSessionId, sdp: { type: 'answer', sdp: answer.sdp } });
925
+ } else {
926
+ await peerConnection.setRemoteDescription(new RTCSessionDescription(sdp));
927
  }
928
  }
929
  if (msg.ice) {
 
970
  localMicStream = null;
971
  }
972
  isMicMuted = true;
973
+ robotSupportsMic = false;
974
 
975
  if (peerConnection) peerConnection.close();
976
  if (dataChannel) dataChannel.close();
 
989
  function enableControls(enabled) {
990
  document.getElementById('btnPlaySound').disabled = !enabled;
991
  document.getElementById('muteBtn').disabled = !enabled;
992
+ document.getElementById('micBtn').disabled = !enabled || !localMicStream || !robotSupportsMic;
993
  }
994
 
995
  function toggleMute() {
 
1043
  }
1044
  }
1045
 
1046
+ function sdpHasAudioSendRecv(sdp) {
1047
+ // Check whether the robot's SDP offer has sendrecv for audio,
1048
+ // meaning it supports bidirectional audio (updated daemon).
1049
  const lines = sdp.split('\r\n');
1050
  let inAudioSection = false;
1051
+ for (const line of lines) {
1052
  if (line.startsWith('m=audio')) inAudioSection = true;
1053
  else if (line.startsWith('m=')) inAudioSection = false;
1054
+ if (inAudioSection && line === 'a=sendrecv') return true;
1055
+ }
1056
+ return false;
1057
  }
1058
 
1059
  // ===================== Robot State =====================