# connectStream

Important!
This feature is in closed beta - Please, contact Sinch sales for more details.

Determines how to route a call to a Stream/websocket server.

Available to use in a response to an [Incoming Call Event](/docs/voice/api-reference/voice/callbacks/ice) callback.

## Use cases

* Connect inbound calls via one of the standard voice channels (PSTN, SIP or IN-App) to the new Stream channel
  - Reply ICE with connectStream() action.
* Connect outbound calls via one of the standard voice channels into a conference room, and add a stream channel into the same conference, to combine 2 or more outbound calls with a stream outbound call.
  - Initiate a conferenceCallout to connect a standard voice channel (PSTN, SIP or In-App) into a conference room
  - Initiate a customCallout to connect a stream outbound call leg.


**ConnectStream Action example code**

```Json

{
  "action": {
    "name": "connectStream",
    "destination": {
      "type": "Websocket",
      "endpoint": "wss://yourcompany.com/websocket-server"
    },
    "streamingOptions": {
      "version": 1,
      "sampleRate": 44100
    },
    "maxDuration": 3000,
    "callHeaders": [
      {
        "key": "foo",
        "value": "bar"
      },
      {
        "key": "baz",
        "value": "qux"
      }
    ]
  }
}
```

**Schema**

```json
{
  "$ref": "#/components/schemas/svaml.action.connectStream",
  "components": {
    "schemas": {
      "destinationWebSocket": {
        "type": "object",
        "description": "Specifies where to route the Stream call.",
        "required": [
          "type",
          "endpoint"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "This attribute defines the streaming protocol - currently only `Websocket` is supported.",
            "enum": [
              "Websocket"
            ],
            "x-enumDescriptions": {
              "Websocket": "Use websocket stream protocol"
            },
            "example": "Websocket"
          },
          "endpoint": {
            "type": "string",
            "description": "The Stream/Websocket server address.",
            "example": "wss://yourcompany.com/websocket-server"
          }
        }
      },
      "callHeader": {
        "type": "object",
        "description": "Call Headers can be used to pass custom data from a Sinch SDK client to another, or specified in an ICE response to be made available to the receiving client. Further, if Call Headers is specified they will be available in ICE and DICE events.",
        "properties": {
          "key": {
            "type": "string",
            "description": "The call header key of the key value pair."
          },
          "value": {
            "type": "string",
            "description": "The call header value of the key value pair."
          }
        }
      },
      "svaml.action.connectStream": {
        "type": "object",
        "description": "Determines how to route a call to a Stream/websocket server. Available to use in a response to an [Incoming Call Event](https://developers.sinch.com/docs/voice/api-reference/voice/callbacks/ice) callback.",
        "required": [
          "name",
          "destination"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "The name property. Must have the value `connectStream`.",
            "x-enumDescriptions": {
              "connectStream": "The `connectStream` action."
            },
            "enum": [
              "connectStream"
            ],
            "default": "connectStream"
          },
          "destination": {
            "$ref": "#/components/schemas/destinationWebSocket"
          },
          "streamingOptions": {
            "type": "object",
            "description": "Optional parameters for the WebSocket stream.",
            "properties": {
              "version": {
                "type": "integer",
                "description": "The version of the streaming feature.",
                "example": 1
              },
              "sampleRate": {
                "type": "integer",
                "description": "The sample rate for the audio stream in Hz.",
                "example": 44100
              }
            }
          },
          "maxDuration": {
            "type": "integer",
            "description": "The max duration of the call in seconds (max 14400 seconds). If the call is still connected at that time, it will be automatically disconnected.",
            "example": 3600
          },
          "callHeaders": {
            "type": "array",
            "description": "These custom parameters (headers/messages) are sent to your WebSocket server in the initial message when the ConnectStream is established.",
            "items": {
              "$ref": "#/components/schemas/callHeader"
            }
          }
        }
      }
    }
  }
}
```

Note:
After the server response is received Sinch will start to send binary messages and expects to receive binary messages back, encoded with the same CODEC received.

## Voice API Websocket connection flow

```mermaid
sequenceDiagram
    autonumber
    participant sinch as Sinch Platform
    participant wss as Customer Websocket Server
    
    sinch --) wss: WS Connection request
    wss --) sinch: WS Accepted
    sinch -) wss: WS text message (command:connect)
    wss -) sinch: WS text message (command:answer)
    note over sinch,wss: Audio exchange
    sinch -) wss: WS binary message : audio
    wss -) sinch: WS binary message : audio
    note over sinch,wss: Message exchange
    rect rgba(255, 241, 38, 1)
        note right of wss: Clear buffer (VAD / barge-in)
    end
    wss -) sinch: WS text message (command:clear)

    rect rgba(255, 241, 38, 1)
        note right of wss: Send to keep channel open.  <br/>  ie: every 30 secs
    end
    wss -) sinch: WS text message (command:heartbeat)
```

The websocket connection request does not contain any headers. The client is expected to either accept the connection (200 OK) or decline (non-successful HTTP response). If declined, the call is hung up.

If the connection is accepted, the server immediately sends a connect command message, containing all the information.

The client is expected to send a command message back to indicate whether the call should be answered or hung up. If answered, the audio streams start.

This flow introduces an extra message with a payload that might be considered to be cleaner. Compared to the previous flow, the customer header names are preserved (not prepended with X-).

The websocket close message, sent from either side, indicates a hangup. This message can contain code and reason.

#### Connect message:

```Json
{
    "command": "connect",
    "CallId": "...",
    "ApplicationId": "...",
    "Headers": {
        "Header1": "Value1",
        "ApplicationId": "dsfkjhgdfkjghsdfkjg"
    }
}
```

#### Customer message:

```json
{
    "command": "answer"
}
-or-
{
    "command": "busy"
}
-or-
{
    "command": "reject"
}
```

Note:
Info about Close message and how audio is streamed if the Close message is sent.

```mermaid
sequenceDiagram
    participant sinch as Sinch Platform
    participant wss as Customer Websocket Server
    
    sinch --) wss: WS Connection request
    alt
        wss --) sinch: WS Accepted (200 ok)
    else Decline
        wss --) sinch: WS Respponse (Any other code)
        rect rgba(255, 0, 0, 1)
            note right of wss: Stream ended
        end
    end
    sinch -) wss: WS text message (command:connect)
    rect rgba(0, 247, 16, 1)
        note right of wss: Contains callHeaders, callId, AppKey, etc.
    end
    alt
        wss -) sinch: WS text message (command:answer)
    else Send BUSY signal
        wss -) sinch: WS text message (command:busy)
        rect rgba(255, 0, 0, 1)
            note right of wss: Stream ended
        end
    else Reject the call
        wss -) sinch: WS text message (command:reject)
        rect rgba(255, 0, 0, 1)
            note right of wss: Stream ended
        end
    end
    note over sinch,wss: Audio exchange
    sinch -) wss: WS binary message : audio
    wss -) sinch: WS binary message : audio
    note over sinch,wss: Message exchange
    rect rgb(255, 241, 38)
        note right of wss: Clear buffer (VAD / barge-in)
    end
    wss -) sinch: WS text message (command:clear)
    rect rgb(255, 241, 38)
        note right of wss: Send to keep channel open.  <br/> If no audio is sent on the channel<br/>  ie: every 30 secs
    end
    wss -) sinch: WS text message (command:heartbeat)
    note over sinch,wss: Ending the call
    alt Customer ends call
        wss --) sinch: Websocket close()
        rect rgba(255, 0, 0, 1)
            note right of wss: Stream ended
        end
    else Sinch ends call
        wss --) sinch: Websocket close()
        rect rgba(255, 0, 0, 1)
            note right of wss: Stream ended
        end
    end
```