From 2184bd165542727d5dc4a264f0b928ba4d88dd14 Mon Sep 17 00:00:00 2001 From: Tevis Money <51972499+tmoney-bw@users.noreply.github.com> Date: Fri, 19 Aug 2022 15:51:02 -0400 Subject: [PATCH] VAPI 1094 Media Streaming api (#625) Add documentation for Programmable Voice Media Streaming Feature Co-authored-by: Catherine <31828886+CatexB@users.noreply.github.com> Co-authored-by: Marcelo Hossomi <49161852+mhossomi@users.noreply.github.com> Co-authored-by: Nick Ashley --- site/docs/voice/bxml/about.mdx | 5 + site/docs/voice/bxml/startStream.mdx | 419 ++++++++++++++++++ site/docs/voice/bxml/stopStream.mdx | 152 +++++++ site/docs/voice/webhooks/about.mdx | 3 + .../voice/webhooks/mediaStreamRejected.mdx | 109 +++++ .../voice/webhooks/mediaStreamStarted.mdx | 81 ++++ .../voice/webhooks/mediaStreamStopped.mdx | 95 ++++ site/sidebar.js | 5 + 8 files changed, 869 insertions(+) create mode 100644 site/docs/voice/bxml/startStream.mdx create mode 100644 site/docs/voice/bxml/stopStream.mdx create mode 100644 site/docs/voice/webhooks/mediaStreamRejected.mdx create mode 100644 site/docs/voice/webhooks/mediaStreamStarted.mdx create mode 100644 site/docs/voice/webhooks/mediaStreamStopped.mdx diff --git a/site/docs/voice/bxml/about.mdx b/site/docs/voice/bxml/about.mdx index d0d4d9bf7..c2c224474 100644 --- a/site/docs/voice/bxml/about.mdx +++ b/site/docs/voice/bxml/about.mdx @@ -76,6 +76,8 @@ If BXML execution ends without performing a webhook, there is an implicit ``](/docs/voice/bxml/gather) | The Gather verb is used to collect DTMF digits. | | [``](/docs/voice/bxml/startGather) | The StartGather verb is used to collect DTMF digits during the execution of other verbs. | | [``](/docs/voice/bxml/stopGather) | The StopGather verb stops the DTMF collection initiated by ``. | +| [``](/docs/voice/bxml/startStream) | The StartStream verb allows a segment of a call to be streamed to an external destination. | +| [``](/docs/voice/bxml/stopStream) | The StopStream verb is used to stop a stream previously started by a `` verb. | | [``](/docs/voice/bxml/sendDtmf) | The SendDtmf verb is used to play DTMF digits in the call. | | [``](/docs/voice/bxml/tag) | The Tag verb is used to set a new tag value without executing a webhook. | @@ -106,6 +108,9 @@ BXML webhooks are HTTP messages that are sent to your application server to noti | [Conference Recording Available](/docs/voice/webhooks/conferenceRecordingAvailable) | Bandwidth API sends this when a recording started by a ``in a conference is available for download. | | [Disconnect](/docs/voice/webhooks/disconnect) | Bandwidth API sends this when a call ends. | | [DTMF](/docs/voice/webhooks/dtmf) | Bandwidth API sends this for every digit detected after a `` is executed. | +| [MediaStreamStarted](/docs/voice/webhooks/mediaStreamStarted) | Bandwidth API sends this after the stream requested in a `` is started. | +| [MediaStreamRejected](/docs/voice/webhooks/mediaStreamRejected) | Bandwidth API sends this if a stream requested in a `` can not be started. | +| [MediaStreamStopped](/docs/voice/webhooks/mediaStreamStopped) | Bandwidth API sends this when a stream requested in a `` ends. | | [Recording Available](/docs/voice/webhooks/recordingAvailable) | Bandwidth API sends this when a recording started by either a `` or a `` verb in a call is available for download. | | [Transfer Disconnect](/docs/voice/webhooks/transferDisconnect) | Bandwidth API sends this when any leg of a `` ends. | | [Transcription Available](/docs/voice/webhooks/transcriptionAvailable) | Bandwidth API sends this when the transcription of a recording is available for download. | diff --git a/site/docs/voice/bxml/startStream.mdx b/site/docs/voice/bxml/startStream.mdx new file mode 100644 index 000000000..d942fe7ed --- /dev/null +++ b/site/docs/voice/bxml/startStream.mdx @@ -0,0 +1,419 @@ +--- +id: startStream +title: Start Stream +slug: /voice/bxml/startStream +description: A general overview of Bandwidth's StartStream BXML Verb +keywords: + - bandwidth + - voice + - bxml + - start + - streaming +hide_title: false +image: ../../static/img/bandwidth-logo.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The StartStream verb allows a segment of a call to be sent off to another destination for additional processing. + +When used on a call, audio from one or both sides (tracks) of the call will be sent to the specified destination. The stream will continue until the call ends or the [``][1] verb is used. A total of 4 concurrent track streams are allowed on a call. A `` request that uses `both` tracks will count as 2 concurrent streams. +A call has only two tracks, which are named after the direction of the media from the perspective of the Programmable Voice platform: +- `inbound`: media received by Programmable Voice from the call executing the BXML; +- `outbound`: media sent by Programmable Voice to the call executing the BXML. + +Note that this has no correlation to the direction of the call itself. For example, if either an inbound or outbound call is being streamed and executes a ``, the `inbound` track will be the callee's audio and the `outbound` track will be the text-to-speech audio. +## Text Content + +There is no text content available to be set for the `` verb. + +## Attributes + +| Attribute | Description | +|:-------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | (optional) A name to refer to this stream by. Used when sending [``][1]. If not provided, it will default to the generated stream id as sent in the [`Media Stream Started`][2] webhook. | +| tracks | (optional) The part of the call to send a stream from. `inbound`, `outbound` or `both`. Default is `inbound`. | +| destination | (required) A websocket URI to send the stream to. The audio from the specified tracks will be sent via websocket to this URL as base64-encoded PCMU/G711 audio. See below for more details on the websocket packet format. | +| streamEventUrl | (optional) URL to send the associated Webhook events to during this stream's lifetime. Does not accept BXML. May be a relative URL. | +| streamEventMethod | (optional) The HTTP method to use for the request to `streamEventUrl`. GET or POST. Default value is POST. | +| username | (optional) The username to send in the HTTP request to `streamEventUrl`. If specified, the URLs must be TLS-encrypted (i.e., `https`). | +| password | (optional) The password to send in the HTTP request to `streamEventUrl`. If specified, the URLs must be TLS-encrypted (i.e., `https`). | + +If the `streamEventUrl` attribute is specified, then the [Media Stream Started][2], [Media Stream Rejected][3] and [Media Stream Stopped][4] events will be sent to the URL when the stream starts, if there is an error starting the stream and when the stream ends respectively. BXML returned in response to this callback will be ignored. + +:::note +While multiple streams for the same call are allowed, each stream MUST have a unique name. Attempting to start a stream on the same call with the name of an already existing stream will result in a [Media Stream Rejected][3] event. +::: + +## Webhooks Received + +| Webhooks | Can reply with more BXML | +|:---------------------------|:-------------------------| +| [Media Stream Started][2] | No | +| [Media Stream Rejected][3] | No | +| [Media Stream Stopped][4] | No | + +## Nested Tags + +You may specify up to 12 `` elements nested within a `` tag. These elements define optional user specified parameters that will be sent to the destination URL when the stream is first started. + +### StreamParam Attributes + +| Attribute | Description | +|:----------|:---------------------------------------------------------------| +| name | (required) The name of this parameter, up to 256 characters. | +| value | (required) The value of this parameter, up to 2048 characters. | + +## Websocket Packet Format + +At the destination end, the websocket will receive messages containing JSON for the duration of the stream. There will be an initial `start` message when the connection is first established. This will be followed by zero or more `media` messages containing the encoded audio for the tracks being streamed. Finally, when a stream is stopped, a `stop` message will be sent. + +### Start and Stop Message Parameters + +| Parameter | Description | +|:-------------|:------------| +| eventType | What type of message this is, one of `start`, or `stop` | +| metadata | Details about the stream this message is for. See further details below. | +| streamParams | (optional) (`start` message only) If any `` elements were specified in the `` request, they will be copied here as a map of `name : value` pairs | + +#### Metadata Parameters + +| Parameter | Description | +|:------------------------------|:------------| +| accountId | The user account associated with the call | +| callId | The call id associated with the stream | +| streamId | The unique id of the stream | +| streamName | The user supplied name of the stream | +| tracks | A list of one or more tracks being sent in this stream | +| tracks.name | The name of the track being sent, will be used to identify which media messages belong to which track | +| tracks.mediaFormat | The format the media will take for this track | +| tracks.mediaFormat.encoding | The encoding of the media for this track; currently only `audio/PCMU` is supported | +| tracks.mediaFormat.sampleRate | The sample rate of the media for this track, currently only `8000` is supported | + +### Media Message Parameters + +| Parameter | Description | +|:----------|:-----------------------| +| eventType | Will always be `media` | +| track | The name of the track this media packet is for, will be one of the names specified in the `start` message | +| payload | A base64 encoded string of actual media. The encoding of the media itself is as specified in the `start` message | + +## Examples + +### Stream Both Legs of A Call + + + + +```xml + + + This call is being streamed to a live studio audience. + + + + This will now be streamed to the destination as well as played to the call participants. + +``` + + + + +```java +SpeakSentence speakSentenceStart = SpeakSentence.builder() + .text("This call is being streamed to a live studio audience.") + .voice("bridget") + .build(); + +StreamParam streamParam = StreamParam.builder() + .name("internal_id") + .value("call_ABC") + .build(); + +StartStream startStream = StartStream.builder() + .name("live_audience") + .tracks("both") + .destination("wss://live-studio-audience.myapp.example.com") + .streamEventUrl("https://myapp.example.com/noBXML") + .streamParams(streamParam) + .build(); + +SpeakSentence speakSentenceEnd = SpeakSentence.builder() + .text("This will now be streamed to the destination as well as played to the call participants.") + .voice("bridget") + .build(); + +Response response = Response.builder().build() + .add(speakSentenceStart) + .add(startStream) + .add(speakSentenceEnd); + +System.out.println(response.toBXML()); +``` + + + + +```csharp +SpeakSentence speakSentenceStart = new SpeakSentence +{ + Sentence = "This call is being streamed to a live studio audience.", + Voice = "bridget" +}; + +StreamParam streamParam = new StreamParam +{ + Name = "internal_id", + Value = "call_ABC", +}; + +StartStream startStream = new StartStream +{ + Name = "live_audience", + Tracks = "both", + Destination = "wss://live-studio-audience.myapp.example.com", + StreamEventUrl = "https://myapp.example.com/noBXML", + StreamParams = new StreamParams[] { streamParam } +}; + +SpeakSentence speakSentenceEnd = new SpeakSentence +{ + Sentence = "This will now be streamed to the destination as well as played to the call participants.", + Voice = "bridget" +}; + +Response response = new Response(); +response.Add(speakSentenceStart); +response.Add(startStream); +response.Add(speakSentenceEnd); + +Console.WriteLine(response.ToBXML()); +``` + + + + +```ruby +speak_sentence_start = Bandwidth::Voice::SpeakSentence.new({ + :sentence => "This call is being streamed to a live studio audience.", + :voice => "bridget" +}) + +stream_param = Bandwidth::Voice::StreamParam.new({ + :name => "internal_id", + :value => "call_ABC" +}) + +start_stream = Bandwidth::Voice::StartStream.new({ + :name => "live_audience", + :tracks => "both", + :destination => "wss://live-studio-audience.myapp.example.com", + :stream_events_url = "https://myapp.example.com/noBXML" + :stream_params => [stream_param] +}) + +speak_sentence_end = Bandwidth::Voice::SpeakSentence.new({ + :sentence => "This will now be streamed to the destination as well as played to the call participants.", + :voice => "bridget" +}) + +response = Bandwidth::Voice::Response.new() +response.push(speak_sentence_start) +response.push(start_stream) +response.push(speak_sentence_end) + +puts response.to_bxml() +``` + + + + +```js +const speakSentenceStart = new SpeakSentence({ + sentence: "This call is being streamed to a live studio audience.", + voice: "bridget" +}); + +const streamParam = new StreamParam({ + name: "internal_id", + value: "call_ABC" +}); + +const startStream = new StartStream({ + name: "live_audience", + tracks: "both", + destination: "wss://live-studio-audience.myapp.example.com", + streamEventUrl: "https://myapp.example.com/noBXML", + streamParams: [streamParam] +}); + +const speakSentenceEnd = new SpeakSentence({ + sentence: "This will now be streamed to the destination as well as played to the call participants.", + voice: "bridget" +}); + +const response = new Response(speakSentenceStart, startStream, speakSentenceEnd); + +console.log(response.toBxml()); +``` + + + + +```python +speak_sentence_start = SpeakSentence( + sentence="This call is being streamed to a live studio audience.", + voice="bridget" +) + +stream_param = StreamParam( + name="internal_id", + value="call_ABC" +) + +start_stream = StartStream( + name="live_audience", + tracks="both", + destination="wss://live-studio-audience.myapp.example.com", + stream_events_url="https://myapp.example.com/noBXML", + stream_params=[stream_param] +) + +speak_sentence_end = SpeakSentence( + sentence="This will now be streamed to the destination as well as played to the call participants.", + voice="bridget" +) + +response = Response() +response.add_verb(speak_sentence_start) +response.add_verb(start_stream) +response.add_verb(speak_sentence_end) + +print(response.to_bxml()) +``` + + + + +```php +$speakSentenceStart = new BandwidthLib\Voice\Bxml\SpeakSentence("This call is being recorded. Please wait while we transfer you."); +$speakSentenceStart->voice("bridget"); + +$startRecording = new BandwidthLib\Voice\Bxml\StartRecording(); +$startRecording->recordingAvailableUrl("https://myapp.com/noBXML"); + +$streamParam = new BandwidthLib\Voice\Bxml\StreamParam(); +$streamParam->name("internal_id"); +$streamParam->value("call_ABC"); + +$startStream = new BandwidthLib\Voice\Bxml\StartStream("wss://live-studio-audience.myapp.example.com"); +$startStream->name("live_audience"); +$startStream->tracks("both") +$startStream->streamEventUrl("https://myapp.example.com/noBXML") +$startStream->streamParams(array($streamParam)); + +$speakSentenceEnd = new BandwidthLib\Voice\Bxml\SpeakSentence("This will now be streamed to the destination as well as played to the call participants."); +$speakSentenceEnd->voice("bridget"); + +$response = new BandwidthLib\Voice\Bxml\Response(); +$response->addVerb($speakSentenceStart); +$response->addVerb($startStream); +$response->addVerb($speakSentenceEnd); + +echo $response->toBxml(); +``` + + + + +### A `start` Websocket Message + +```json +{ + "eventType": "start", + "metadata": { + "accountId": "5555555", + "callId": "c-2a913f94-7fa91773-a426-4118-8b8b-b691ab0a0ae1", + "streamId": "s-2a913f94-93e372e2-60da-4c89-beb0-0d3a219b287c", + "streamName": "live_audience", + "tracks": [ + { + "name": "inbound", + "mediaFormat": { + "encoding": "PCMU", + "sampleRate": 8000 + } + }, + { + "name": "outbound", + "mediaFormat": { + "encoding": "PCMU", + "sampleRate": 8000 + } + } + ] + }, + "streamParams": { + "foo": "bar", + "foos": "bars" + } +} +``` + +### A `media` Websocket Message + +```json +{ + "eventType": "media", + "track": "inbound", + "payload": "3Ob2dV1NRUpSXfTy69bHvbzD09PL0trpaWZMTV5PT05DRUpNYeLyb+jc1tPW3tfN1/r4cFZd5PxXXGjo2M/M0NTU0Nvi31ZFTFhLQERKT19safHd18zIycjHyc3Z4+7s609GSktMS1hmVFBm3eZk2tB4ffJ17/5r5dLb5uLd1c3UdmZnc/jt3eH9a3H06dvV3WNPYXxjS0BJT05VXm53+A==" +} +``` + +### A `stop` Websocket Message + +```json +{ + "eventType": "stop", + "metadata": { + "accountId": "5555555", + "callId": "c-2a913f94-7fa91773-a426-4118-8b8b-b691ab0a0ae1", + "streamId": "s-2a913f94-93e372e2-60da-4c89-beb0-0d3a219b287c", + "streamName": "live_audience", + "tracks": [ + { + "name": "inbound", + "mediaFormat": { + "encoding": "PCMU", + "sampleRate": 8000 + } + }, + { + "name": "outbound", + "mediaFormat": { + "encoding": "PCMU", + "sampleRate": 8000 + } + } + ] + } +} +``` + +[1]: /docs/voice/bxml/stopStream +[2]: /docs/voice/webhooks/mediaStreamStarted +[3]: /docs/voice/webhooks/mediaStreamRejected +[4]: /docs/voice/webhooks/mediaStreamStopped diff --git a/site/docs/voice/bxml/stopStream.mdx b/site/docs/voice/bxml/stopStream.mdx new file mode 100644 index 000000000..26118f565 --- /dev/null +++ b/site/docs/voice/bxml/stopStream.mdx @@ -0,0 +1,152 @@ +--- +id: stopStream +title: Stop Stream +slug: /voice/bxml/stopStream +description: A general overview of Bandwidth's StopStream BXML Verb +keywords: + - bandwidth + - voice + - bxml + - stop + - streaming +hide_title: false +image: ../../static/img/bandwidth-logo.png +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +The StopStream verb is used to stop a stream that was started with a previous [``][1] verb. + +If there is no stream with the given name on the call, this verb has no effect. + +## Text Content + +There is no text content available to be set for the `` verb. + +## Attributes + +| Attribute | Description | +|:-------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| name | (required) The name of the stream to stop. This is either the user selected name when sending the [``][1] verb, or the system generated name returned in the [Media Stream Started][2] webhook if `` was sent with no `name` attribute. | + +## Webhooks Received + +| Webhooks | Can reply with more BXML | +|:---------------------------|:-------------------------| +| [Media Stream Stopped][3] | No | + +## Examples + +### Stopping a media stream + + + + +```xml + + + + +``` + + + + +```java +StopStream stopStream = StopStream.builder() + .name("live_audience") + .build(); + +Response response = Response.builder().build() + .add(stopStream); + +System.out.println(response.toBXML()); +``` + + + + +```csharp +StopStream stopStream = new StopStream +{ + Name = "live_audience", +}; + +Response response = new Response(); +response.Add(stopStream); + +Console.WriteLine(response.ToBXML()); +``` + + + + +```ruby +stop_stream = Bandwidth::Voice::StopStream.new({ + :name => "live_audience", +}) + +response = Bandwidth::Voice::Response.new() +response.push(stop_stream) + +puts response.to_bxml() +``` + + + + +```js +const stopStream = new StopStream({ + name: "live_audience", +}); + +const response = new Response(stopStream); + +console.log(response.toBxml()); +``` + + + + +```python +stop_stream = StopStream( + name="live_audience", +) + +response = Response() +response.add_verb(stop_stream) + +print(response.to_bxml()) +``` + + + + +```php +$stopStream = new BandwidthLib\Voice\Bxml\StopStream("live_audience"); + +$response = new BandwidthLib\Voice\Bxml\Response(); +$response->addVerb($stopStream); + +echo $response->toBxml(); +``` + + + + +[1]: /docs/voice/bxml/startStream +[2]: /docs/voice/webhooks/mediaStreamStarted +[3]: /docs/voice/webhooks/mediaStreamStopped diff --git a/site/docs/voice/webhooks/about.mdx b/site/docs/voice/webhooks/about.mdx index 555ef059e..e7a861b95 100644 --- a/site/docs/voice/webhooks/about.mdx +++ b/site/docs/voice/webhooks/about.mdx @@ -75,6 +75,9 @@ HTTP GET requests may be used for webhook | [Disconnect](/docs/voice/webhooks/disconnect) | Bandwidth API sends this when a call ends. | | [DTMF](/docs/voice/webhooks/dtmf) | Bandwidth API sends this for every digit detected after a `` is executed. | | [Machine Detection Complete](/docs/voice/webhooks/machineDetectionComplete) | Bandwidth API sends this when the result of a machine detection request is available.| +| [MediaStreamStarted](/docs/voice/webhooks/mediaStreamStarted) | Bandwidth API sends this after the stream requested in a `` is started. | +| [MediaStreamRejected](/docs/voice/webhooks/mediaStreamRejected) | Bandwidth API sends this if a stream requested in a `` can not be started. | +| [MediaStreamStopped](/docs/voice/webhooks/mediaStreamStopped) | Bandwidth API send this when a stream requested in a `` ends. | | [Recording Available](/docs/voice/webhooks/recordingAvailable) | Bandwidth API sends this when a recording started by either a `` or a `` verb in a call is available for download. | | [Transfer Disconnect](/docs/voice/webhooks/transferDisconnect) | Bandwidth API sends this when any leg of a `` ends. | | [Transcription Available](/docs/voice/webhooks/transcriptionAvailable) | Bandwidth API sends this when the transcription of a recording is available for download. | diff --git a/site/docs/voice/webhooks/mediaStreamRejected.mdx b/site/docs/voice/webhooks/mediaStreamRejected.mdx new file mode 100644 index 000000000..a1a4c8a32 --- /dev/null +++ b/site/docs/voice/webhooks/mediaStreamRejected.mdx @@ -0,0 +1,109 @@ +--- +id: mediaStreamRejected +title: Media Stream Rejected +slug: /voice/webhooks/mediaStreamRejected +description: A general overview of Bandwidth's Media Stream Rejected Webhook +keywords: + - bandwidth + - voice + - webhook + - streaming + - rejected +hide_title: false +image: ../../static/img/bandwidth-logo.png +--- + +This event may be sent to the url specified when sending a [``][1] verb. This event will be sent if the stream requested in the `` verb was not started. + +## Request Parameters + +| Property | Description | +|:--------------------------------|:-------------| +| accountId | The user account associated with the call | +| answerTime | Time the call was answered, in ISO 8601 format | +| applicationId | The id of the application associated with the call | +| callId | The call id associated with the event | +| callUrl | The URL of the call associated with the event | +| cause | The reason the stream was rejected, can be one of `connection-error`, `duplicate`, `error` or `track-limit` | +| direction | The direction of the call. Either `inbound` or `outbound`. The direction of a call never changes. | +| enqueuedTime | (optional) If [call queueing](/apis/voice#operation/createCall) is enabled and this is an outbound call, time the call was queued, in ISO 8601 format. | +| errorMessage | Detailed information about the `cause` | +| eventTime | The approximate UTC date and time when the event was generated by the Bandwidth server, in ISO 8601 format. This may not be exactly the time of event execution. | +| eventType | The event type, value is `mediaStreamStarted` | +| from | The provided identifier of the caller: can be a phone number in E.164 format (e.g. +15555555555) or one of `Private`, `Restricted`, `Unavailable`, or `Anonymous`. | +| mediaStream | Details about the rejected stream | +| mediaStream.destination | The destination URL to which the rejected stream was going to send media | +| mediaStream.name | The name of the rejected stream | +| mediaStream.startTime | The approximate UTC date and time the rejected stream was started | +| mediaStream.id | The unique id of the rejected stream | +| mediaStream.tracks | The segments of the call that were going to be sent in the rejected stream, values will be one or both of `inbound` and `outbound` | +| mediaStream.type | The type of stream that was rejected. Currently the only supported type is `WebSocket` | +| originalMediaStream | (optional) Details about the original stream if this rejection is due to requesting a duplicate stream name | +| originalMediaStream.destination | The destination URL to which the original stream is sending media | +| originalMediaStream.name | The name of the original stream | +| originalMediaStream.id | The unique id of the original stream | +| originalMediaStream.startTime | The approximate UTC date and time the original stream was started | +| originalMediaStream.tracks | The segments of the call that are being sent in the original stream, values will be one or both of `inbound` and `outbound` | +| originalMediaStream.type | The type of original stream being sent. Currently the only supported type is `WebSocket` | +| startTime | Time the call was started, in ISO 8601 format. | +| to | The phone number that received the call, in E.164 format (e.g. +15555555555). | +| tag | (optional) The `tag` specified on call creation. If no `tag` was specified or it was previously cleared, this field will not be present. | + +### Possible `cause` Values + +| Value | Meaning | +|:-----------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| connection-error | There was a problem communicating with the destination supplied in the [``][2] request. For example connecting to the websocket timed out, or the websocket closed abnormally, etc. | +| duplicate | The stream was a duplicate of another existing stream | +| error | There was an internal error other than a problem communicating with the destination | +| track-limit | The requested stream exceeded the maximum number of tracks that may be streamed on a single call | + +## Expected Response + +```http +HTTP/1.1 204 +``` + +## Examples + +### Media Stream Rejected Event for Duplicate Stream with Enqueued Time + +```json +POST http://myapp.example/mediaStreamEvents +Content-Type: application/json + +{ + "accountId" : "55555555", + "answerTime" : "2022-06-30T18:55:02.080Z", + "applicationId" : "7fc9698a-b04a-468b-9e8f-91238c0d0086", + "callId" : "c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "callUrl" : "https://voice.bandwidth.com/api/v2/accounts/55555555/calls/c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "cause" : "duplicate", + "direction" : "outbound", + "enqueuedTime" : "2022-06-30T18:54:59.172Z", + "errorMessage" : "A stream with the name example_stream already exists", + "eventTime" : "2022-06-30T18:55:02.489Z", + "eventType" : "mediaStreamRejected", + "from" : "+15551112222", + "mediaStream" : { + "destination" : "wss://duplicate.websocket.myapp.example", + "name" : "example_stream", + "id" : "s-95ac90b3-a2b4fd9b-579c-4cc7-898e-3d257c7a042b", + "startTime" : "2022-06-30T18:55:02.489Z", + "tracks" : ["outbound"], + "type" : "WebSocket" + }, + "originalMediaStream" : { + "destination" : "wss://websocket.myapp.example", + "name" : "example_stream", + "id" : "s-95ac90b3-e9cd80fa-fca7-4d12-9109-2990afe4d8c5", + "startTime" : "2022-06-30T18:55:02.489Z", + "tracks" : ["inbound", "outbound"], + "type" : "WebSocket" + }, + "startTime" : "2022-06-30T18:54:59.175Z", + "to" : "+15553334444" +} +``` + +[1]: /docs/voice/bxml/startStream diff --git a/site/docs/voice/webhooks/mediaStreamStarted.mdx b/site/docs/voice/webhooks/mediaStreamStarted.mdx new file mode 100644 index 000000000..fd23ea55d --- /dev/null +++ b/site/docs/voice/webhooks/mediaStreamStarted.mdx @@ -0,0 +1,81 @@ +--- +id: mediaStreamStarted +title: Media Stream Started +slug: /voice/webhooks/mediaStreamStarted +description: A general overview of Bandwidth's Media Stream Started Webhook +keywords: + - bandwidth + - voice + - webhook + - streaming + - start +hide_title: false +image: ../../static/img/bandwidth-logo.png +--- + +This event may be sent to the url specified when sending a [``][1] verb. + +## Request Parameters + +| Property | Description | +|:------------------------|:-------------| +| accountId | The user account associated with the call. | +| answerTime | Time the call was answered, in ISO 8601 format. | +| applicationId | The id of the application associated with the call. | +| callId | The call id associated with the event. | +| callUrl | The URL of the call associated with the event. | +| direction | The direction of the call. Either `inbound` or `outbound`. The direction of a call never changes. | +| enqueuedTime | (optional) If [call queueing](/apis/voice#operation/createCall) is enabled and this is an outbound call, time the call was queued, in ISO 8601 format. | +| eventTime | The approximate UTC date and time when the event was generated by the Bandwidth server, in ISO 8601 format. This may not be exactly the time of event execution. | +| eventType | The event type, value is `mediaStreamStarted` | +| from | The provided identifier of the caller: can be a phone number in E.164 format (e.g. +15555555555) or one of `Private`, `Restricted`, `Unavailable`, or `Anonymous`. | +| mediaStream | Details about the stream that was started | +| mediaStream.destination | The destination URL to which the stream is sending media | +| mediaStream.id | The unique id of the stream | +| mediaStream.name | The name of this stream. If the `name` attribute was specified in the [`StartStream`][1] verb, then this will be the value of that attribute, otherwise it will default to the stream id. +| mediaStream.startTime | The approximate UTC date and time the stream was started | +| mediaStream.tracks | The segments of the call that are being sent in the stream, values will be one or both of `inbound` and `outbound` | +| mediaStream.type | The type of stream being sent. Currently the only supported type is `WebSocket` | +| startTime | Time the call was started, in ISO 8601 format. | +| to | The phone number that received the call, in E.164 format (e.g. +15555555555). | +| tag | (optional) The `tag` specified on call creation. If no `tag` was specified or it was previously cleared, this field will not be present. | + +## Expected Response + +```http +HTTP/1.1 204 +``` + +## Examples + +### Media Stream Started Event with Enqueued Time + +```json +POST http://myapp.example/mediaStreamEvents +Content-Type: application/json + +{ + "accountId" : "55555555", + "answerTime" : "2022-06-30T18:55:02.080Z", + "applicationId" : "7fc9698a-b04a-468b-9e8f-91238c0d0086", + "callId" : "c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "callUrl" : "https://voice.bandwidth.com/api/v2/accounts/55555555/calls/c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "direction" : "outbound", + "enqueuedTime" : "2022-06-30T18:54:59.172Z", + "eventTime" : "2022-06-30T18:55:02.489Z", + "eventType" : "mediaStreamStarted", + "from" : "+15551112222", + "mediaStream" : { + "destination" : "wss://websocket.myapp.example", + "id" : "s-95ac90b3-bfc81595-35fc-4b64-8265-fab6855b74a2", + "name" : "example_stream", + "startTime" : "2022-06-30T18:55:02.489Z", + "tracks" : ["inbound", "outbound"], + "type" : "WebSocket" + }, + "startTime" : "2022-06-30T18:54:59.175Z", + "to" : "+15553334444" +} +``` + +[1]: /docs/voice/bxml/startStream diff --git a/site/docs/voice/webhooks/mediaStreamStopped.mdx b/site/docs/voice/webhooks/mediaStreamStopped.mdx new file mode 100644 index 000000000..04bdee356 --- /dev/null +++ b/site/docs/voice/webhooks/mediaStreamStopped.mdx @@ -0,0 +1,95 @@ +--- +id: mediaStreamStopped +title: Media Stream Stopped +slug: /voice/webhooks/mediaStreamStopped +description: A general overview of Bandwidth's Media Stream Stopped Webhook +keywords: + - bandwidth + - voice + - webhook + - streaming + - stop +hide_title: false +image: ../../static/img/bandwidth-logo.png +--- + +This event may be sent to the url specified when sending a [``][1] verb, or if the stream is stopped for another reason such as the call being hungup. + +## Request Parameters + +| Property | Description | +|:------------------------|:-------------| +| accountId | The user account associated with the call. | +| answerTime | Time the call was answered, in ISO 8601 format. | +| applicationId | The id of the application associated with the call. | +| callId | The call id associated with the event. | +| callUrl | The URL of the call associated with the event. | +| cause | The reason the stream was stopped. This can be one of `closed`, `connection-error`, or `error`. | +| direction | The direction of the call. Either `inbound` or `outbound`. The direction of a call never changes. | +| enqueuedTime | (optional) If [call queueing](/apis/voice#operation/createCall) is enabled and this is an outbound call, time the call was queued, in ISO 8601 format. | +| errorMessage | (optional) If the `cause` value was anything other than `closed`, this will contain details about what went wrong. | +| eventTime | The approximate UTC date and time when the event was generated by the Bandwidth server, in ISO 8601 format. This may not be exactly the time of event execution. | +| eventType | The event type, value is `mediaStreamStarted` | +| from | The provided identifier of the caller: can be a phone number in E.164 format (e.g. +15555555555) or one of `Private`, `Restricted`, `Unavailable`, or `Anonymous`. | +| mediaStream | Details about the stream that was stopped | +| mediaStream.destination | The destination URL to which the stream sent media | +| mediaStream.duration | The duration of time the stream was active | +| mediaStream.id | The unique id of this stream that was stopped | +| mediaStream.name | The name of this stream that was stopped | +| mediaStream.startTime | The approximate UTC date and time the stream was started | +| mediaStream.tracks | The segments of the call that were sent in the stream, values will be one or both of `inbound` and `outbound` | +| mediaStream.type | The type of stream that was sent. Currently the only supported type is `WebSocket` | +| startTime | Time the call was started, in ISO 8601 format. | +| to | The phone number that received the call, in E.164 format (e.g. +15555555555). | +| tag | (optional) The `tag` specified on call creation. If no `tag` was specified or it was previously cleared, this field will not be present. | + +### Possible `cause` Values + +| Value | Meaning | +|:-----------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| closed | The media stream was closed intentionally, either because a [``][1] request was sent, or the call ended | +| connection-error | There was a problem communicating with the destination supplied in the [``][2] request. For example connecting to the websocket timed out, or the websocket closed abnormally, etc. | +| error | There was an internal error other than a problem communicating with the destination | + +## Expected Response + +```http +HTTP/1.1 204 +``` + +## Examples + +### Media Stream Stopped Event with Enqueued Time + +```json +POST http://myapp.example/mediaStreamEvents +Content-Type: application/json + +{ + "accountId" : "55555555", + "answerTime" : "2022-06-30T18:55:02.080Z", + "applicationId" : "7fc9698a-b04a-468b-9e8f-91238c0d0086", + "callId" : "c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "callUrl" : "https://voice.bandwidth.com/api/v2/accounts/55555555/calls/c-95ac912f-68aacdd7-4a8e-4223-a7fd-020e02fa6bf2", + "cause" : "closed", + "direction" : "outbound", + "enqueuedTime" : "2022-06-30T18:54:59.172Z", + "eventTime" : "2022-06-30T18:55:02.489Z", + "eventType" : "mediaStreamStopped", + "from" : "+15551112222", + "mediaStream" : { + "destination" : "wss://websocket.myapp.example", + "duration" : "PT1M52.217257456S", + "id" : "s-95ac90b3-e9cd80fa-fca7-4d12-9109-2990afe4d8c5", + "name" : "example_stream", + "startTime" : "2022-06-30T18:55:02.489Z", + "tracks" : ["inbound", "outbound"], + "type" : "WebSocket" + }, + "startTime" : "2022-06-30T18:54:59.175Z", + "to" : "+15553334444" +} +``` + +[1]: /docs/voice/bxml/stopStream +[2]: /docs/voice/bxml/startStream diff --git a/site/sidebar.js b/site/sidebar.js index 1077fde9e..13ce61230 100644 --- a/site/sidebar.js +++ b/site/sidebar.js @@ -90,6 +90,9 @@ module.exports = { "voice/webhooks/gather", "voice/webhooks/initiate", "voice/webhooks/machineDetectionComplete", + "voice/webhooks/mediaStreamStarted", + "voice/webhooks/mediaStreamRejected", + "voice/webhooks/mediaStreamStopped", "voice/webhooks/recordComplete", "voice/webhooks/recordingAvailable", "voice/webhooks/redirect", @@ -123,6 +126,8 @@ module.exports = { "voice/bxml/startGather", "voice/bxml/stopGather", "voice/bxml/sendDtmf", + "voice/bxml/startStream", + "voice/bxml/stopStream", "voice/bxml/tag", ], },