Skip to content

Other Platforms

If das-Peak Streaming is used in a Genesys Cloud-based solution, the optimal approach is to send the audio using the AudioHook client provided by the Genesys Cloud platform. Conversely, if the solution is based on Twilio, the best solution is to send the audio using the Twilio Media Streams client provided by the Twilio platform. However, when a solution does not use either of these platforms, there is the possibility to easily send the audio to das-Peak Streaming.

For this purpose, das-Peak Streaming makes use of the Twilio Media Streams audio consumer it provides. This consumer is capable of understanding a subset of the Twilio Media Streams websocket specification, allowing audio to be sent to das-Peak Streaming with a minimal set of messages via websocket.

Below is a detailed specification of this subset. Please note that to use this audio consumer, as it is a subset of the Twilio Media Streams specification, the audio_protocol parameter must be specified as twilio during signalling.

Specification

Once a websocket connection is established with das-Peak Streaming twilio audio consumer, then following messages can be used to send audio.

Start message

This message contains call_id parameter that is necessary to identify which Session is the stream associated to. It is only sent once at the start of the Stream.

Parameter Description
event The value of start
start An object containing Stream metadata
start.callSid The call_id identifier from where the Stream was started.

Media message

This message encapsulates the raw audio data.

Parameter Description
event The value of media
media An object containing media payload
media.payload Raw audio encoded in base64

When enough audio is captured by das-Peak Streaming, it closes the websocket connection.

Example

Following python code shows an example of how to implement an audio client for sending an audio file to das-Peak Streaming using the above described specification.

# example.py

import asyncio
import json
import base64
import textwrap
import ssl

from websockets import client


URL = "wss://api.eu.veri-das.com/daspeak-stream/v1/twilio"
APIKEY = "*****"
CALL_ID = "4fd9e9af-dd71-4177-be31-0bc5041221be"
FILENAME = "audio.raw"


class Client:
    def __init__(self, url, apikey):
        self._url = url
        self._headers = {
            "apikey": apikey
        }
        self._loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self._loop)

    def run(self, call_id, filename):
        self._loop.run_until_complete(self._run(call_id, filename))

    async def _run(self, call_id, filename):
        websocket = await client.connect(self._url, extra_headers=self._headers)
        await self._send_start(websocket, call_id)
        await self._send_media(websocket, filename)
        await websocket.recv()

    async def _send_start(self, websocket, call_id):
        data = {
            'event': 'start',
            'start': {
                'callSid': call_id
            }
        }
        await websocket.send(json.dumps(data))

    async def _send_media(self, websocket, filename):
        audio_payload = self._get_audio(filename)
        audio_chunks = textwrap.wrap(audio_payload, 1024)
        for chunk in audio_chunks:
            data = {
                'event': 'media',
                'media': {
                    'payload': chunk
                }
            }
            await websocket.send(json.dumps(data))

    @staticmethod
    def _get_audio(filename):
        payload = None
        with open(filename, 'rb') as f:
            payload = base64.b64encode(f.read()).decode('UTF-8')
            f.close()

        return payload


client = Client(url=URL, apikey=APIKEY)
client.run(call_id=CALL_ID, filename=FILENAME)

Let's analyze last code.

URL = "wss://api.eu.veri-das.com/daspeak-stream/v1/twilio"
APIKEY = "*****"
CALL_ID = "4fd9e9af-dd71-4177-be31-0bc5041221be"
FILENAME = "audio.raw"

First, global variables are defined. This include das-Peak Streaming Twilio audio consumer URL and API Key, call_id identifier and audio file name.

class Client:
    def __init__(self, url, apikey):
        self._url = url
        self._headers = {
            "apikey": apikey
        }
        self._loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self._loop)

Then Client class is declared with an init method that assign class variables, creates headers to be sent during websocket initialization, and creates an asynchronous loop to execute websocket client using python websockets library.

def run(self, call_id, filename):
    self._loop.run_until_complete(self._run(call_id, filename))

Next, client run method is declared. This method executes the _run coroutine in an asynchronous loop.

async def _run(self, call_id, filename):
    websocket = await client.connect(self._url, extra_headers=self._headers)
    await self._send_start(websocket, call_id)
    await self._send_media(websocket, filename)
    await websocket.recv()

_run coroutine creates websocket connection and executes _send_start and _send_media methods. Afterwards it waits for connection closing using websockets recv method.

async def _send_start(self, websocket, call_id):
    data = {
        'event': 'start',
        'start': {
            'callSid': call_id
        }
    }
    await websocket.send(json.dumps(data))

_send_start coroutine sends start message with defined call_id parameter.

async def _send_media(self, websocket, filename):
    audio_payload = self._get_audio(filename)
    audio_chunks = textwrap.wrap(audio_payload, 1024)
    for chunk in audio_chunks:
        data = {
            'event': 'media',
            'media': {
                'payload': chunk
            }
        }
        await websocket.send(json.dumps(data))

_send_media coroutine sends media message. Audio payload is retrieved by calling _get_audio method and then audio is splitted in chunks of 1024 bytes size.

@staticmethod
def _get_audio(filename):
    payload = None
    with open(filename, 'rb') as f:
        payload = base64.b64encode(f.read()).decode('UTF-8')
        f.close()

    return payload

_get_audio method reads audio file, encodes it in base64 and returns the payload.

client = Client(url=URL, apikey=APIKEY)
client.run(call_id=CALL_ID, filename=FILENAME)

Lastly, client instance is created and run method is called.