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.