Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Voice JavaScript SDK: Twilio.PreflightTest


A Twilio.PreflightTest object represents a test call to Twilio which provides information to help troubleshoot call-related issues when using the Voice JavaScript SDK.

You will never instantiate a PreflightTest instance directly, but it's returned when you call Device.runPreflight(token, options).

Example:


_11
import { Device } from '@twilio/voice-sdk';
_11
_11
const preflightTest = Device.runPreflight(token, options);
_11
_11
preflightTest.on('completed', (report) => {
_11
console.log(report);
_11
});
_11
_11
preflightTest.on('failed', (error) => {
_11
console.log(error);
_11
});


Running PreflightTest

running-preflighttest page anchor

You will need an Access Token to initiate the test call. The Access Token will be associated with a TwiML application.

You likely already have a TwiML app with a Voice Request URL configured to send an HTTP POST request to an endpoint on your project's backend.

For the best test results, the endpoint with which you've configured your TwiML App should be able to record audio from a microphone and play it back to the browser.

Your backend application can be modified to handle this behavior, but you can also set up a new TwiML Application configured with TwiML bins specifically for PreflightTests. See the TwiML Apps for PreflightTest section below for more information.


preflightTest.stop()

preflightteststop page anchor

Calling this method from the PreflightTest object will stop the existing test and will raise a failed event with an error code 31008 indicating that the call has been cancelled.


Raised when PreflightTest.status has transitioned to PreflightTest.Status.Completed. During this time, the report is available and ready to be inspected. This will not trigger if a fatal error is encountered during the test.

Passes the report object to the completed event handler.


_10
preflightTest.on('completed', handler(report));

See the Report section below to view an example of this report.

Raised when PreflightTest.status has transitioned to PreflightTest.Status.Connected. This indicates that the connection to Twilio has been established.

Raised when PreflightTest.status has transitioned to PreflightTest.Status.Failed. This happens when establishing a connection to Twilio has failed or when a test call has encountered a fatal error. This is also raised if PreflightTest.stop is called while the test is in progress. The error emitted from this event is coming from Device.on('error') and uses the same error format.

Passes a TwilioError object or a DOMError object to the failed event handler.


_10
preflightTest.on('failed', handler(error));

Raised when the test Call gets a WebRTC sample object. The event is published every second.

Passes the RTCSample(link takes you to an external page) object to the sample event handler.


_10
preflightTest.on('sample', handler(sample));

Raised whenever the test Call encounters a warning.

Passes the name of the warning (string) and the Warning(link takes you to an external page) object to the warning event handler.


_10
preflightTest.on('warning', handler(name, warning));


The Call SID for the test call. This is set when the test Device instance has finished connecting to Twilio.

A timestamp in milliseconds of when the test ended. This is set when the test has completed and raised the completed event.

preflightTest.latestSample

preflighttestlatestsample page anchor

The latest WebRTC sample collected. This is set whenever the Call emits a sample.

Returns an RTCSample(link takes you to an external page) object or undefined.

The report for this test. This is set when the test has completed and raised the completed event.

See the Report section below for more information on the report object.

preflightTest.startTime

preflightteststarttime page anchor

A timestamp in milliseconds of when the test started. This is set right after calling Device.runPreflight(token, options).

The status of the test. Below are the possible values for this property.

ValueDescription
CompletedThe connection to Twilio has been disconnected and the test call has completed.
ConnectedThe connection to Twilio has been established.
ConnectingConnecting to Twilio has started.
FailedThe test has stopped and failed.

Below is an example report returned to the completed event handler or accessed via preflightTest.report.


_180
{
_180
"callSid": "CAa6a7a187a9cba2714d6fdccf472cc7b1",
_180
"edge": "ashburn",
_180
"iceCandidateStats": [...],
_180
"networkTiming": {
_180
"signaling": {
_180
"start": 1628271850137,
_180
"end": 1628271850958,
_180
"duration": 821
_180
},
_180
"dtls": {
_180
"start": 1628271851032,
_180
"end": 1628271851192,
_180
"duration": 160
_180
},
_180
"ice": {
_180
"start": 1628271850956,
_180
"end": 1628271851032,
_180
"duration": 76
_180
},
_180
"peerConnection": {
_180
"start": 1628271850965,
_180
"end": 1628271851193,
_180
"duration": 228
_180
}
_180
},
_180
"samples": [
_180
{
_180
"audioInputLevel": 10999,
_180
"audioOutputLevel": 1725,
_180
"bytesReceived": 2880,
_180
"bytesSent": 6080,
_180
"codecName": "PCMU",
_180
"jitter": 0,
_180
"mos": null,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 18,
_180
"packetsSent": 38,
_180
"rtt": 66,
_180
"timestamp": 1628271851961.724,
_180
"totals": {
_180
"bytesReceived": 2880,
_180
"bytesSent": 6080,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 18,
_180
"packetsSent": 38
_180
}
_180
}
_180
],
_180
"selectedEdge": "roaming",
_180
"stats": {
_180
"jitter": {
_180
"average": 1.2273,
_180
"max": 3,
_180
"min": 0
_180
},
_180
"mos": {
_180
"average": 4.4,
_180
"max": 4.406226172226452,
_180
"min": 4.390523592170177
_180
},
_180
"rtt": {
_180
"average": 69.045,
_180
"max": 84,
_180
"min": 59
_180
}
_180
},
_180
"testTiming": {
_180
"start": 1628271849623,
_180
"end": 1628271874932,
_180
"duration": 25309
_180
},
_180
"totals": {
_180
"bytesReceived": 109280,
_180
"bytesSent": 182080,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 683,
_180
"packetsSent": 1138
_180
},
_180
"warnings": [
_180
{
_180
"name": "low-bytes-received",
_180
"description": "Received an RTCWarning. See .rtcWarning for the RTCWarning",
_180
"rtcWarning": {
_180
"values": [
_180
0,
_180
0,
_180
0
_180
],
_180
"samples": [
_180
{
_180
"audioInputLevel": 11718,
_180
"audioOutputLevel": 0,
_180
"bytesReceived": 0,
_180
"bytesSent": 8000,
_180
"codecName": "PCMU",
_180
"jitter": 1,
_180
"mos": 4.404255907879351,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 0,
_180
"packetsSent": 50,
_180
"rtt": 61,
_180
"timestamp": 1628271856961.176,
_180
"totals": {
_180
"bytesReceived": 29920,
_180
"bytesSent": 46080,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 187,
_180
"packetsSent": 288
_180
}
_180
},
_180
{
_180
"audioInputLevel": 11261,
_180
"audioOutputLevel": 0,
_180
"bytesReceived": 0,
_180
"bytesSent": 8000,
_180
"codecName": "PCMU",
_180
"jitter": 1,
_180
"mos": 4.404255907879351,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 0,
_180
"packetsSent": 50,
_180
"rtt": 61,
_180
"timestamp": 1628271857960.764,
_180
"totals": {
_180
"bytesReceived": 29920,
_180
"bytesSent": 54080,
_180
"packetsLost": 0,
_180
"packetsLostFraction": 0,
_180
"packetsReceived": 187,
_180
"packetsSent": 338
_180
}
_180
},
_180
],
_180
"name": "bytesReceived",
_180
"threshold": {
_180
"name": "min",
_180
"value": 1
_180
}
_180
}
_180
}
_180
],
_180
"selectedIceCandidatePairStats": {
_180
"localCandidate": {
_180
"id": "RTCIceCandidate_XXXXXXXX",
_180
"timestamp": 1628271851961.724,
_180
"type": "local-candidate",
_180
"transportId": "RTCTransport_0_1",
_180
"isRemote": false,
_180
"networkType": "wifi",
_180
"ip": "xx.xx.x.xx",
_180
"address": "xx.xx.x.xx",
_180
"port": 44444,
_180
"protocol": "udp",
_180
"candidateType": "prflx",
_180
"priority": 1853759231
_180
},
_180
"remoteCandidate": {
_180
"id": "RTCIceCandidate_XXXXXXXX",
_180
"timestamp": 1628271851961.724,
_180
"type": "remote-candidate",
_180
"transportId": "RTCTransport_0_1",
_180
"isRemote": true,
_180
"ip": "xx.xxx.xxx.xxx",
_180
"address": "xx.xxx.xxx.xxx",
_180
"port": 11111,
_180
"protocol": "udp",
_180
"candidateType": "host",
_180
"priority": 2130706431
_180
}
_180
},
_180
"isTurnRequired": false,
_180
"callQuality": "excellent"
_180
}

Report Properties

Property: callSid

Description:

The Call SID for the test call.

Property: edge

Description:

The Edge location that the test call was connected to

Property: iceCandidateStats

Description:

An array of WebRTC stats for the ICE candidates gathered when connecting to media. Each item is an RTCIceCandidateStats(link takes you to an external page) object which provides information related to an ICE candidate.

Property: networkTiming

Description:

Measurements for establishing DTLS connection. Properties:

Property: samples

Description:

WebRTC samples collected during the test. See the object format on the RTCSample Interface reference page(link takes you to an external page).

Property: selectedEdge

Description:

The edge passed to Device.runPreflight

Property: stats

Description:

RTC-related stats that are extracted from WebRTC samples. This information includes maximum, minimum, and average values calculated for each statistic.

Property: testTiming

Description:

Timing measurement related to the test. Includes millisecond timestamps and duration.

Property: totals

Description:

Calculated totals in RTC statistics samples.

Property: warnings

Description:

PreflightTest.Warnings detected during the test

Property: selectedIceCandidatePairStats

Description:

A WebRTC stats object for the ICE candidate pair used to connect to media, if candidates were selected. Each item is an RTCIceCandidatePairStats(link takes you to an external page) object which provides information related to an ICE candidate.

Property: isTurnRequired

Description:

Whether a TURN server is required to connect to media. This is dependent on the selected ICE candidates, and will be true if either is of type "relay", false if both are of another type, or undefined if there are no selected ICE candidates. See PreflightTest.Options.iceServers(link takes you to an external page) for more details.

Property: callQuality

Description:

The quality of the call, determined by the MOS (Mean Opinion Score) of the audio stream. Possible values include:

  • Excellent - If the average mos is over 4.2
  • Great - If the average mos is between 4.1 and 4.2 both inclusive
  • Good - If the average mos is between 3.7 and 4.0 both inclusive
  • Fair - If the average mos is between 3.1 and 3.6 both inclusive
  • Degraded - If the average mos is 3.0 or below

TwiML Apps for PreflightTest

twiml-apps-for-preflighttest page anchor

Please see our example application(link takes you to an external page) if you don't want to set up the required TwiML Apps manually.

Twilio.Device.runPreflight(token, options) requires a Twilio Access Token to initiate the test call. This access token will be passed directly to the Device's constructor and will be used to connect to a TwiML app that you associated with your Twilio Access Token. In order to get better results, the TwiML app should be able to record audio from a microphone and play it back to the browser. Below are example TwiML Apps that you can use and some setup instructions.

If PreflightTest.Options.fakeMicInput is set to false, Device.runPreflight(token, options) API requires a token with a TwiML app that can record an audio from a microphone and the ability to play the recorded audio back to the browser. In order to achieve this, we need two TwiML endpoints: one to capture and record the audio, and another one to play the recorded audio.

In this example, we will use TwiML Bins for our TwiML app. Start by going to the TwiML Bin(link takes you to an external page) page in the Twilio Console.

Playback TwiML Bin

Create a new TwiML Bin with the plus button on that screen and use "Playback" as the friendly name.

Then use the following TwiML under the TwiML section.


_10
<?xml version="1.0" encoding="UTF-8"?>
_10
_10
<Response>
_10
<Say>You said:</Say>
_10
<Play loop="1">{{RecordingUrl}}</Play>
_10
<Say>Now waiting for a few seconds to gather audio performance metrics.</Say>
_10
<Pause length="3"/>
_10
<Say>Hanging up now.</Say>
_10
</Response>

Record TwiML Bin

Using the TwiML Bin(link takes you to an external page) page, let's create another TwiML Bin by clicking the plus button on that screen and use "Record" as the friendly name.

Then replace the action url in the following template with your "Playback" TwiML Bin's URL that you created previously:


_10
<?xml version="1.0" encoding="UTF-8"?>
_10
_10
<Response>
_10
<Say>Record a message in 3, 2, 1</Say>
_10
<Record maxLength="5" action="https://my-record-twimlBin-url"></Record>
_10
<Say>Did not detect a message to record</Say>
_10
</Response>

Creating the TwiML Application

Now that we have created our TwiML Bins, let's create our TwiML app by going to the TwiML Apps(link takes you to an external page) page.

  1. Click the plus button on that screen
  2. Enter a friendly name for the application like "PreflightTest".
  3. Under Voice request URL , enter your Record TwiML Bin's URL that you created in the previous section, and then click the Create button.
  4. On that same page, open the TwiML app that you just created by clicking on it and make note of the SID .

You can now use this TwiML app to generate your Access Token when calling Device.runPreflight(token, options).

If PreflightTest.Options.fakeMicInput is set to true, Device.runPreflight(token, options) API requires an Access Token with a TwiML app that can capture and play audio.

Following the previous steps, create a TwiML Bin using the following TwiML and create a new TwiML Application pointed to that TwiML Bin's URL.


_10
<?xml version="1.0" encoding="UTF-8"?>
_10
_10
<Response>
_10
<Echo/>
_10
</Response>


Rate this page: