Search code examples
azurevideo-conferencingvideocallazure-communication-services

Azure Communication Service for video call - Feature is not defined


With Azure communication Calling library I tried to get network quality.

const { CallClient, VideoStreamRenderer, LocalVideoStream } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential } = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");

I tried this 2 codes but I have the same error "feature is not defined".

EDIT : I put feature's code in the subscribeToCall function.

Did I forget to import something?

EDIT FOR MORE DETAILS :

My function to subscribe a call when start or accept.

subscribeToCall = (call) => {
    try {
        // Subscribe to call's 'stateChanged' event for value changes.
        call.on('stateChanged', async () => {
            // If ringing / Connected / Disconnected ...
        });

        call.on('isLocalVideoStartedChanged', () => {
            console.log(`------------- isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
        });
        call.localVideoStreams.forEach(async (lvs) => {
            localVideoStream = lvs;
            await displayLocalVideoStream();
        });
        call.on('localVideoStreamsUpdated', e => {
            e.added.forEach(async (lvs) => {
                localVideoStream = lvs;
                await displayLocalVideoStream();
            });
            e.removed.forEach(lvs => {
               removeLocalVideoStream();
            });
        });
        call.remoteParticipants.forEach(remoteParticipant => {
            subscribeToRemoteParticipant(remoteParticipant);
        });
        // Subscribe to the call's 'remoteParticipantsUpdated' event to be
        // notified when new participants are added to the call or removed from the call.
        call.on('remoteParticipantsUpdated', e => {
            // Subscribe to new remote participants that are added to the call.
            e.added.forEach(remoteParticipant => {
                subscribeToRemoteParticipant(remoteParticipant)
            });
            // Unsubscribe from participants that are removed from the call
            e.removed.forEach(remoteParticipant => {
                console.log('Remote participant removed from the call.');
            });
        });

        // CALL FEATURE TESTS ::::::::
        // First example
        /*const userFacingDiagnostics = call.feature(Features.UserFacingDiagnostics);

        userFacingDiagnostics.media.on("diagnosticChanged", (diagnosticInfo) => {
          console.log(diagnosticInfo);
        });

        userFacingDiagnostics.network.on("diagnosticChanged", (diagnosticInfo) => {
           console.log(diagnosticInfo);
        });*/

        // Second example

        /*call.feature(Features.UserFacingDiagnostics).network.on('diagnosticChanged', (diagnosticInfo) => {
            if (diagnosticInfo.diagnostic === 'networkReceiveQuality') {
                if (diagnosticInfo.value === DiagnosticQuality.Bad) {
                    console.log("Network quality = BAD");
                } else if (diagnosticInfo.value === DiagnosticQuality.Poor) {
                    console.log("Network quality = POOR");
                } else if (diagnosticInfo.value === DiagnosticQuality.Good) {
                    console.log("Network quality = GOOD");
                }
            }
        });*/


    } catch (error) {
        console.error(error);
    }
}

EDIT 2024/04/24

First example source link : Stackoverflow - Can't load Features.Diagnostics

Second example source link : networkReceiveQuality, UFD


Solution

  • The error "feature is not defined" indicates that the Features object is not recognized within the scope of your code.

    A features object should be used like this:

    const callQualityApi = call.api(Features.Diagnostics);
    callQualityApi.network.on('diagnosticChanged', diagnosticChangedListener);
    callQualityApi.media.on('diagnosticChanged', diagnosticChangedListener);
    

    To enable Call Diagnostics for your Azure Communication Services Resource, follow these steps:

    • Create an Azure Log Analytics workspace.
    • Add diagnostic settings for your resource. You can do this by following the instructions provided here. Make sure to enable logs via Diagnostic Settings in Azure Monitor.

    enter image description here

    • When adding a diagnostic setting choose "allLogs" to collect all logs and Metrics.
    • Select Destination Details as stream the logs to a Log Analytics workspace and save.

    enter image description here

    Once you've set up Diagnostic Settings, you can access Call Diagnostics from any Azure Communication Services Resource in your Azure portal.

    • Navigate to your Azure Communication Services Resource and locate the "Monitoring" section on the left side of the interface.
    • Select "Call Diagnostics" from the options available.

    The sample code below is Azure Communication Services calling SDK in Node.js to set up event handlers and listeners for various call and network diagnostic events. It checks for DiagnosticQuality.Bad, DiagnosticQuality.Poor, and DiagnosticQuality.Good.

    • The code for Azure Communication Services Call Diagnostics feature for web applications is taken from this reference doc
    const { CallClient, VideoStreamRenderer, LocalVideoStream, Features } = require('@azure/communication-calling');
    const { AzureCommunicationTokenCredential } = require('@azure/communication-common');
    const { AzureLogger, setLogLevel } = require("@azure/logger");
    
    
    const subscribeToCall = (call) => {
        try {
           
            call.on('stateChanged', async () => {
                // If ringing / Connected / Disconnected ...
            });
    
            call.on('isLocalVideoStartedChanged', () => {
                console.log(`------------- isLocalVideoStarted changed: ${call.isLocalVideoStarted}`);
            });
            call.localVideoStreams.forEach(async (lvs) => {
                localVideoStream = lvs;
                await displayLocalVideoStream();
            });
            call.on('localVideoStreamsUpdated', e => {
                e.added.forEach(async (lvs) => {
                    localVideoStream = lvs;
                    await displayLocalVideoStream();
                });
                e.removed.forEach(lvs => {
                   removeLocalVideoStream();
                });
            });
            call.remoteParticipants.forEach(remoteParticipant => {
                subscribeToRemoteParticipant(remoteParticipant);
            });
          
            call.on('remoteParticipantsUpdated', e => {
              
                e.added.forEach(remoteParticipant => {
                    subscribeToRemoteParticipant(remoteParticipant)
                });
               
                e.removed.forEach(remoteParticipant => {
                    console.log('Remote participant removed from the call.');
                });
            });
    
            
            call.api(Features.Diagnostics).network.on('diagnosticChanged', (diagnosticInfo) => {
                console.log(diagnosticInfo);
          
            });
    
          
            call.api(Features.UserFacingDiagnostics).network.on('diagnosticChanged', (diagnosticInfo) => {
                if (diagnosticInfo.diagnostic === 'networkReceiveQuality') {
                    if (diagnosticInfo.value === DiagnosticQuality.Bad) {
                        console.log("Network quality = BAD");
                    } else if (diagnosticInfo.value === DiagnosticQuality.Poor) {
                        console.log("Network quality = POOR");
                    } else if (diagnosticInfo.value === DiagnosticQuality.Good) {
                        console.log("Network quality = GOOD");
                    }
                }
            });
    
        } catch (error) {
            console.error(error);
        }
    }
    
    

    enter image description here

    enter image description here