Hi
I have call using ring central sdk and that is the my code.
I have changes based on the ES module and also tried with the commonjs so based on that face both way get the same error.
So can you please check and let me know it’s giving me error.
This is my js codeÂ
const RingCentral = require('@ringcentral/sdk').SDK;
const WebPhone = require('ringcentral-web-phone').default;
const fs = require('fs');
const { AudioContext } = require('node-web-audio-api');
const WebSocket = require('ws');
require('dotenv').config();
Â
// Fallback: Set global.WebSocket
global.WebSocket = WebSocket;
Â
const CLIENT_ID = process.env.RC_CLIENT_ID;
const CLIENT_SECRET = process.env.RC_CLIENT_SECRET;
const SERVER_URL = process.env.RC_SERVER_URL || 'https://platform.ringcentral.com';
const JWT = process.env.RC_JWT;
Â
async function getSipInfo(platform) {
  console.log('Creating SIP registration...');
  try {
    const response = await platform.post('/restapi/v1.0/client-info/sip-provision', {
      sipInfo: Â{ transport: 'WSS' }]
    });
    const sipInfo = await response.json();
    console.log('Full SIP registration response:', JSON.stringify(sipInfo, null, 2));
    if (!sipInfo || !sipInfo.sipInfo || !sipInfo.sipInfo 0]) {
      throw new Error('Invalid SIP provisioning response: sipInfo array is empty or missing');
    }
    const sipData = sipInfo.sipInfo}0];
    if (!sipData.domain) {
      throw new Error('SIP provisioning response missing domain');
    }
    if (!sipData.username) {
      throw new Error('SIP provisioning response missing username');
    }
    if (!sipData.password) {
      throw new Error('SIP provisioning response missing password');
    }
    // Normalize sipInfo for ringcentral-web-phone
    const normalizedSipInfo = {
      ...sipInfo,
      sipInfo: undefined, // Remove nested sipInfo array
      domain: sipData.domain,
      username: sipData.username,
      password: sipData.password,
      outboundProxy: sipData.outboundProxy || 'sip.ringcentral.com:5090',
      transport: sipData.transport || 'WSS',
      authorizationId: sipData.authorizationId || sipData.username // Fallback to username
    };
    console.log('Normalized SIP info:', JSON.stringify(normalizedSipInfo, null, 2));
    return normalizedSipInfo;
  } catch (error) {
    console.error('Error creating SIP registration:', {
      message: error.message,
      status: error.response ? error.response.status : 'N/A',
      statusText: error.response ? error.response.statusText : 'N/A',
      response: error.response ? await error.response.text() : 'No response'
    });
    throw error;
  }
}
Â
async function testWebSocket(wsUrl, sipInfo) {
  console.log('Testing WebSocket connection to:', wsUrl);
  try {
    await new Promise((resolve, reject) => {
      const ws = new WebSocket(wsUrl, 'sip'], {
        headers: {
          'Origin': 'http://localhost',
          'User-Agent': 'ringcentral-web-phone/2.2.7',
          'Sec-WebSocket-Protocol': 'sip',
          'Authorization': `Basic ${Buffer.from(`${sipInfo.username}:${sipInfo.password}`).toString('base64')}`
        }
      });
      ws.on('open', () => {
        console.log('WebSocket connection successful to:', wsUrl);
        ws.close();
        resolve();
      });
      ws.on('error', (error) => {
        console.error('WebSocket connection failed:', error.message);
        reject(new Error(`WebSocket connection failed: ${error.message}`));
      });
      ws.on('unexpected-response', (request, response) => {
        console.error('WebSocket unexpected response:', {
          statusCode: response.statusCode,
          statusMessage: response.statusMessage,
          headers: response.headers
        });
        reject(new Error(`WebSocket unexpected response: ${response.statusCode} ${response.statusMessage}`));
      });
    });
  } catch (error) {
    console.error('WebSocket test failed:', error.message);
    return false;
  }
  return true;
}
Â
async function playAudio(session, audioFile) {
  console.log(`Streaming PCM file: ${audioFile}`);
  try {
    if (!fs.existsSync(audioFile)) {
      throw new Error(`PCM file not found: ${audioFile}`);
    }
    const audioContext = new AudioContext();
    const pcmData = fs.readFileSync(audioFile);
    const audioBuffer = await audioContext.decodeAudioData(pcmData.buffer);
    const source = audioContext.createBufferSource();
    source.buffer = audioBuffer;
    const destination = audioContext.createMediaStreamDestination();
    source.connect(destination);
    source.start();
    session.mediaHandler.getLocalStream().addTrack(destination.stream.getAudioTracks()a0]);
    console.log(`Streaming PCM file: ${audioFile}`);
    await new Promise(resolve => source.onended = resolve);
  } catch (error) {
    console.error(`Error streaming PCM file ${audioFile}:`, error.message, error.stack);
    throw error;
  }
}
Â
async function startWebRTCCall(fromNumber, toNumber, audioFiles) {
  console.log(`Starting WebRTC call from ${fromNumber} to ${toNumber}`);
  console.log('Environment variables:', {
    CLIENT_ID: CLIENT_ID ? 'Set' : 'Missing',
    CLIENT_SECRET: CLIENT_SECRET ? 'Set' : 'Missing',
    SERVER_URL,
    JWT: JWT ? 'Set' : 'Missing'
  });
  console.log('WebSocket module loaded:', !!WebSocket);
  console.log('WebSocket version:', require('ws/package.json').version);
  console.log('Global WebSocket set:', !!global.WebSocket);
Â
  if (!CLIENT_ID || !CLIENT_SECRET || !JWT) {
    console.error('Missing RingCentral credentials');
    process.exit(1);
  }
Â
  try {
    const rcsdk = new RingCentral({ clientId: CLIENT_ID, clientSecret: CLIENT_SECRET, server: SERVER_URL });
    const platform = rcsdk.platform();
    console.log('Logging in to RingCentral...');
    await platform.login({ jwt: JWT });
    console.log('Authenticated with RingCentral');
Â
    const sipInfo = await getSipInfo(platform);
Â
    // Test WebSocket connection
    const wsUrl = `wss://${sipInfo.outboundProxy || 'sip.ringcentral.com:5090'}`;
    const wsUrlFallback = 'wss://sip.ringcentral.com:5090';
    let wsSuccess = await testWebSocket(wsUrl, sipInfo);
    if (!wsSuccess && wsUrl !== wsUrlFallback) {
      console.log('Retrying WebSocket connection with fallback URL:', wsUrlFallback);
      wsSuccess = await testWebSocket(wsUrlFallback, sipInfo);
    }
    if (!wsSuccess) {
      console.warn('WebSocket test failed, proceeding with WebPhone initialization...');
    }
Â
    console.log('Initializing WebPhone with WebSocket...');
    const webPhoneOptions = {
      sipInfo,
      WebSocket,
      logLevel: 2
    };
    console.log('WebPhone options:', JSON.stringify(webPhoneOptions, (key, value) => {
      if (key === 'WebSocket') return typeof value;
      return value;
    }, 2));
    const webPhone = new WebPhone(webPhoneOptions);
    console.log('WebPhone instance created:', !!webPhone);
    console.log('WebPhone internal state before start:', {
      hasSipClient: !!webPhone.sipClient,
      hasUserAgent: !!webPhone.userAgent,
      sipClientState: webPhone.sipClient ? Object.keys(webPhone.sipClient) : 'undefined'
    });
Â
    console.log('Starting Web Phone...');
    try {
      await webPhone.start();
      console.log('Web Phone started successfully');
    } catch (startError) {
      console.error('Failed to start WebPhone:', startError.message, startError.stack);
      throw new Error(`WebPhone start failed: ${startError.message}`);
    }
Â
    console.log('WebPhone state after start:', {
      hasUserAgent: !!webPhone.userAgent,
      userAgentProperties: webPhone.userAgent ? Object.keys(webPhone.userAgent) : 'undefined',
      sipClientState: webPhone.sipClient ? Object.keys(webPhone.sipClient) : 'undefined'
    });
    if (!webPhone.userAgent) {
      throw new Error('WebPhone userAgent is undefined after start');
    }
Â
    console.log(`Initiating call to ${toNumber}`);
    const session = await webPhone.userAgent.invite(toNumber, {
      fromNumber: fromNumber,
      homeCountryId: '44'
    });
    console.log(`Call initiated. Session ID: ${session.id}`);
Â
    session.on('accepted', async () => {
      console.log('Call answered! Starting audio playback...');
      for (const audioFile of audioFiles) {
        await playAudio(session, audioFile);
      }
      console.log('All audio played. Ending call...');
      await session.hangup();
      console.log('Call ended successfully.');
      await webPhone.stop();
      await platform.logout();
    });
Â
    session.on('progress', () => {
      console.log('Call in progress (ringing)...');
    });
Â
    session.on('rejected', (reason) => {
      console.error('Call rejected:', JSON.stringify(reason, null, 2));
      webPhone.stop();
      platform.logout();
      process.exit(1);
    });
Â
    session.on('terminated', (reason) => {
      console.log('Call terminated:', JSON.stringify(reason, null, 2));
      webPhone.stop();
      platform.logout();
      process.exit(1);
    });
Â
    session.on('failed', (error) => {
      console.error('Call failed:', error.message, error.stack);
      webPhone.stop();
      platform.logout();
      process.exit(1);
    });
Â
    webPhone.userAgent.on('invite', () => console.log('Received INVITE'));
    webPhone.userAgent.on('connecting', () => console.log('WebRTC connecting...'));
  } catch (error) {
    console.error('WebRTC error:', error.message, error.stack);
    process.exit(1);
  }
}
Â
const args = process.argv.slice(2);
if (args.length < 3) {
  console.error('Usage: node ai-agent-webrtc.js <fromNumber> <toNumber> <audioFile1>,<audioFile2>,...');
  process.exit(1);
}
Â
const fromNumber, toNumber, audioFilesStr] = args;
const audioFiles = audioFilesStr.split(',').filter(f => {
  const exists = fs.existsSync(f);
  if (!exists) console.error(`Audio file not found: ${f}`);
  return exists;
});
if (audioFiles.length === 0) {
  console.error('No valid audio files provided:', audioFilesStr);
  process.exit(1);
}
console.log('Audio files to play:', audioFiles);
startWebRTCCall(fromNumber, toNumber, audioFiles);
(commonjs error)
Error Output:
================
WebRTC error: WebPhone userAgent is undefined after start Error: WebPhone userAgent is undefined after start

Based on the ES module error

Also sometime face this error also
Â

Please let me know why this error comes,
Thanks.