Advertisement
phucbienvan

WebRTC_voice

Apr 9th, 2025
283
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Set the basic API address for communication with the backend server
  2. // const baseUrl = "http://0.0.0.0:8005";
  3. const baseUrl = "https://voice-ai-rtc.creativelink.ai";
  4. // Flag indicating whether WebRTC is active, controls the enabling and disabling of connections
  5. let isWebRTCActive = false;
  6. // Create variables related to the WebRTC connection
  7. let peerConnection;
  8. let dataChannel;
  9. // Define an object that contains multiple functions; methods in fns will be called
  10. const fns = {
  11.     // Get the HTML content of the current page
  12.     getPageHTML: () => {
  13.         return {
  14.             success: true,
  15.             html: document.documentElement.outerHTML
  16.         }; // Return the entire page's HTML
  17.     },
  18.     // Change the background color of the webpage
  19.     changeBackgroundColor: ({ color }) => {
  20.         document.body.style.backgroundColor = color; // Change the page's background color
  21.         return { success: true, color }; // Return the changed color
  22.     },
  23.     // Change the text color of the webpage
  24.     changeTextColor: ({ color }) => {
  25.         document.body.style.color = color; // Change the page's text color
  26.         return { success: true, color }; // Return the changed color
  27.     },
  28.     // Change the button's style (size and color)
  29.     changeButtonStyle: ({ size, color }) => {
  30.         const button = document.querySelector('button'); // Get the first button on the page (modify selector if there are multiple buttons)
  31.         if (button) {
  32.             // Change the button's size
  33.             if (size) {
  34.                 button.style.fontSize = size; // Set font size
  35.             }
  36.             // Change the button's color
  37.             if (color) {
  38.                 button.style.backgroundColor = color; // Set button background color
  39.             }
  40.             return { success: true, size, color }; // Return modified button style
  41.         } else {
  42.             return { success: false, message: 'Button element not found' }; // Return failure if no button is found
  43.         }
  44.     },
  45. };
  46.  
  47. // When an audio stream is received, add it to the page and play it
  48. function handleTrack(event) {
  49.     const el = document.createElement('audio'); // Create an audio element
  50.     el.srcObject = event.streams[0]; // Set the audio stream as the element's source
  51.     el.autoplay = el.controls = true; // Autoplay and display audio controls
  52.     document.body.appendChild(el); // Add the audio element to the page
  53. }
  54.  
  55. // Create a data channel for transmitting control messages (such as function calls)
  56. function createDataChannel() {
  57.     // Create a data channel named 'response'
  58.     dataChannel = peerConnection.createDataChannel('response');
  59.     // Configure data channel events
  60.     dataChannel.addEventListener('open', () => {
  61.         console.log('Data channel opened');
  62.         configureData(); // Configure data channel functions
  63.     });
  64.     dataChannel.addEventListener('message', async (ev) => {
  65.         const msg = JSON.parse(ev.data); // Parse the received message
  66.         // If the message type is 'response.function_call_arguments.done', it indicates a function call request
  67.         if (msg.type === 'response.function_call_arguments.done') {
  68.             const fn = fns[msg.name]; // Get the corresponding function by name
  69.             if (fn !== undefined) {
  70.                 console.log(`Calling local function ${msg.name}, parameters ${msg.arguments}`);
  71.                 const args = JSON.parse(msg.arguments); // Parse function parameters
  72.                 const result = await fn(args); // Call the local function and wait for the result
  73.                 console.log('Result', result); // Log the result of the function
  74.                 // Send the result of the function execution back to the other party
  75.                 const event = {
  76.                     type: 'conversation.item.create', // Create conversation item event
  77.                     item: {
  78.                         type: 'function_call_output', // Function call output
  79.                         call_id: msg.call_id, // Passed call_id
  80.                         output: JSON.stringify(result), // JSON string of the function execution result
  81.                     },
  82.                 };
  83.                 dataChannel.send(JSON.stringify(event)); // Send the result back to the remote side
  84.             }
  85.         }
  86.     });
  87. }
  88.  
  89. // Configure data channel functions and tools
  90. function configureData() {
  91.     console.log('Configuring data channel');
  92.     const event = {
  93.         type: 'session.update', // Session update event
  94.         session: {
  95.             modalities: ['text', 'audio'], // Supported interaction modes: text and audio
  96.             // Provide functional tools, pay attention to the names of these tools corresponding to the keys in the above fns object
  97.             tools: [
  98.                 {
  99.                     type: 'function', // Tool type is function
  100.                     name: 'changeBackgroundColor', // Function name
  101.                     description: 'Change the background color of the webpage', // Description
  102.                     parameters: { // Parameter description
  103.                         type: 'object',
  104.                         properties: {
  105.                             color: {
  106.                                 type: 'string',
  107.                                 description: 'Hexadecimal value of the color'
  108.                             }, // Color parameter
  109.                         },
  110.                     },
  111.                 },
  112.                 {
  113.                     type: 'function',
  114.                     name: 'changeTextColor',
  115.                     description: 'Change the text color of the webpage',
  116.                     parameters: {
  117.                         type: 'object',
  118.                         properties: {
  119.                             color: {
  120.                                 type: 'string',
  121.                                 description: 'Hexadecimal value of the color'
  122.                             },
  123.                         },
  124.                     },
  125.                 },
  126.                 {
  127.                     type: 'function',
  128.                     name: 'getPageHTML',
  129.                     description: 'Get the HTML content of the current page',
  130.                 },
  131.                 {
  132.                     type: 'function', // Tool type is function
  133.                     name: 'changeButtonStyle', // New function name
  134.                     description: 'Change the size and color of the button', // Description
  135.                     parameters: { // Parameter description
  136.                         type: 'object',
  137.                         properties: {
  138.                             size: {
  139.                                 type: 'string',
  140.                                 description: 'Font size of the button (e.g., "16px" or "1em")'
  141.                             }, // Button size
  142.                             color: {
  143.                                 type: 'string',
  144.                                 description: 'Background color of the button (e.g., "#ff0000" or "red")'
  145.                             }, // Button color
  146.                         },
  147.                     },
  148.                 },
  149.             ],
  150.         },
  151.     };
  152.     dataChannel.send(JSON.stringify(event)); // Send the configured event data
  153. }
  154.  
  155. // Get the control button element
  156. const toggleButton = document.getElementById('toggleWebRTCButton');
  157. // Add a click event listener to the button to toggle the WebRTC connection state
  158. toggleButton.addEventListener('click', () => {
  159.     // If WebRTC is active, stop the connection; otherwise, start WebRTC
  160.     if (isWebRTCActive) {
  161.         stopWebRTC(); // Stop WebRTC
  162.         toggleButton.textContent = 'start'; // Update button text
  163.     } else {
  164.         startWebRTC(); // Start WebRTC
  165.         toggleButton.textContent = 'stop'; // Update button text
  166.     }
  167. });
  168.  
  169. // Capture microphone input stream and initiate WebRTC connection
  170. function startWebRTC() {
  171.     // If WebRTC is already active, return directly
  172.     if (isWebRTCActive) return;
  173.     // Create a new peerConnection object to establish a WebRTC connection
  174.     peerConnection = new RTCPeerConnection();
  175.     peerConnection.ontrack = handleTrack; // Bind audio stream processing function
  176.     createDataChannel(); // Create data channel
  177.     // Request user's audio stream
  178.     navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
  179.         // Add each track from the audio stream to the peerConnection
  180.         stream.getTracks().forEach((track) => peerConnection.addTransceiver(track, { direction: 'sendrecv' }));
  181.         // Create an offer for the local connection
  182.         peerConnection.createOffer().then((offer) => {
  183.             peerConnection.setLocalDescription(offer); // Set local description (offer)
  184.             console.log(offer.sdp);
  185.  
  186.             // Send the offer to the backend for signaling exchange
  187.             fetch(baseUrl + '/api/rtc-connect', {
  188.                 method: 'POST',
  189.                 body: offer.sdp, // Send the SDP of the offer to the backend
  190.                 headers: {
  191.                     'Content-Type': 'application/sdp',
  192.                 },
  193.             })
  194.             .then((r) => r.text())
  195.             .then((answer) => {
  196.                 // Get the answer returned by the backend and set it as the remote description
  197.                 peerConnection.setRemoteDescription({ sdp: answer, type: 'answer' });
  198.             });
  199.         });
  200.     });
  201.     // Mark WebRTC as active
  202.     isWebRTCActive = true;
  203. }
  204.  
  205. // Stop the WebRTC connection and clean up all resources
  206. function stopWebRTC() {
  207.     // If WebRTC is not active, return directly
  208.     if (!isWebRTCActive) return;
  209.     // Stop the received audio tracks
  210.     const tracks = peerConnection.getReceivers().map(receiver => receiver.track);
  211.     tracks.forEach(track => track.stop());
  212.     // Close the data channel and WebRTC connection
  213.     if (dataChannel) dataChannel.close();
  214.     if (peerConnection) peerConnection.close();
  215.     // Reset connection and channel objects
  216.     peerConnection = null;
  217.     dataChannel = null;
  218.     // Mark WebRTC as not active
  219.     isWebRTCActive = false;
  220. }
  221.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement