Skip to content

Commit 0a75436

Browse files
authored
Merge pull request #360 from Vonage/feat-add-base64-audio-config-audio-connector
feat: Add Base64 Audio Config to Audio Connector
2 parents 1d65f2e + 16a4882 commit 0a75436

4 files changed

Lines changed: 106 additions & 3 deletions

File tree

video/src/vonage_video/models/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
AudioConnectorData,
44
AudioConnectorOptions,
55
AudioConnectorWebSocket,
6+
AudioTransportConfiguration,
67
)
78
from .broadcast import (
89
Broadcast,
@@ -22,6 +23,8 @@
2223
ArchiveMode,
2324
ArchiveStatus,
2425
AudioSampleRate,
26+
AudioTransportEncoding,
27+
AudioTransportTransport,
2528
ExperienceComposerStatus,
2629
LanguageCode,
2730
LayoutType,
@@ -48,6 +51,9 @@
4851
"AudioConnectorData",
4952
"AudioConnectorOptions",
5053
"AudioConnectorWebSocket",
54+
"AudioTransportConfiguration",
55+
"AudioTransportEncoding",
56+
"AudioTransportTransport",
5157
"Archive",
5258
"ListArchivesFilter",
5359
"Transcription",

video/src/vonage_video/models/audio_connector.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,35 @@
11
from typing import Optional
22

3-
from pydantic import BaseModel, Field
4-
from vonage_video.models.enums import AudioSampleRate
3+
from pydantic import BaseModel, Field, model_validator
4+
from vonage_video.models.enums import (
5+
AudioSampleRate,
6+
AudioTransportEncoding,
7+
AudioTransportTransport,
8+
)
9+
10+
11+
class AudioTransportConfiguration(BaseModel):
12+
"""The audio transport configuration.
13+
14+
Args:
15+
transport (AudioTransportTransport): 'binary' (raw PCM16, the default) or 'json'.
16+
encoding (AudioTransportEncoding): Required when transport is 'json'. Set to 'base64'.
17+
audio_field (str): The JSON key for the outbound audio data. Defaults to 'audio'.
18+
receive_audio_field (str): The JSON key for inbound audio data (when bidirectional is enabled). Defaults to the same value as audio_field.
19+
static_fields (dict): A dictionary of extra key-value pairs included in every outbound JSON audio message.
20+
"""
21+
22+
transport: Optional[AudioTransportTransport] = None
23+
encoding: Optional[AudioTransportEncoding] = None
24+
audio_field: Optional[str] = None
25+
receive_audio_field: Optional[str] = None
26+
static_fields: Optional[dict] = None
27+
28+
@model_validator(mode='after')
29+
def encoding_must_be_specified_for_json_transport(self):
30+
if self.transport == AudioTransportTransport.JSON and not self.encoding:
31+
raise ValueError("encoding must be specified when transport is JSON")
32+
return self
533

634

735
class AudioConnectorWebSocket(BaseModel):
@@ -13,6 +41,7 @@ class AudioConnectorWebSocket(BaseModel):
1341
headers (dict): The headers to send to your WebSocket server.
1442
audio_rate (AudioSampleRate): The audio sample rate in Hertz.
1543
bidirectional (bool): Whether the websocket is bidirectional.
44+
audio_transport (AudioTransportConfiguration): The audio transport configuration. Configures how audio is serialized on the WebSocket wire. By default, audio is sent as raw binary PCM 16-bit frames.
1645
"""
1746

1847
uri: str
@@ -22,6 +51,9 @@ class AudioConnectorWebSocket(BaseModel):
2251
bidirectional: Optional[bool] = Field(
2352
None, description="Whether the websocket is bidirectional."
2453
)
54+
audio_transport: Optional[AudioTransportConfiguration] = Field(
55+
None, serialization_alias='audioTransport'
56+
)
2557

2658
def model_dump(self, *args, **kwargs):
2759
data = super().model_dump(*args, **kwargs)

video/src/vonage_video/models/enums.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ class AudioSampleRate(int, Enum):
5555
KHZ_16 = 16000
5656

5757

58+
class AudioTransportEncoding(str, Enum):
59+
"""Audio encoding type when using JSON transport."""
60+
61+
BASE64 = 'base64'
62+
63+
64+
class AudioTransportTransport(str, Enum):
65+
"""Audio transport type for the WebSocket connection."""
66+
67+
BINARY = 'binary'
68+
JSON = 'json'
69+
70+
5871
class VideoResolution(str, Enum):
5972
"""The resolution of the archive or broadcast.
6073

video/tests/test_audio_connector.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from os.path import abspath
22

3+
import pytest
34
import responses
5+
from pydantic import ValidationError
46
from vonage_http_client import HttpClient
57
from vonage_video import (
68
AudioConnectorOptions,
@@ -10,6 +12,8 @@
1012
TokenRole,
1113
Video,
1214
)
15+
from vonage_video.models.audio_connector import AudioTransportConfiguration
16+
from vonage_video.models.enums import AudioTransportEncoding, AudioTransportTransport
1317

1418
from testutils import build_response, get_mock_jwt_auth
1519

@@ -44,7 +48,7 @@ def test_audio_connector_options_model():
4448
),
4549
)
4650

47-
actual = options.model_dump(by_alias=True)
51+
actual = options.model_dump(by_alias=True, exclude_none=True)
4852
expected = {
4953
'sessionId': 'test_session_id',
5054
'token': 'test_token',
@@ -59,6 +63,54 @@ def test_audio_connector_options_model():
5963
assert actual == expected
6064

6165

66+
def test_audio_connector_options_model_with_audio_transport():
67+
options = AudioConnectorOptions(
68+
session_id='test_session_id',
69+
token='test_token',
70+
websocket=AudioConnectorWebSocket(
71+
uri='test_uri',
72+
streams=['test_stream_id'],
73+
headers={'test_header': 'test_value'},
74+
audio_rate=AudioSampleRate.KHZ_16,
75+
bidirectional=True,
76+
audio_transport=AudioTransportConfiguration(
77+
transport=AudioTransportTransport.JSON,
78+
encoding=AudioTransportEncoding.BASE64,
79+
audio_field='audio',
80+
receive_audio_field='audio',
81+
static_fields={'foo': 'bar'},
82+
),
83+
),
84+
)
85+
86+
actual = options.model_dump(by_alias=True, exclude_none=True)
87+
expected = {
88+
'sessionId': 'test_session_id',
89+
'token': 'test_token',
90+
'websocket': {
91+
'uri': 'test_uri',
92+
'streams': ['test_stream_id'],
93+
'headers': {'test_header': 'test_value'},
94+
'audioRate': 16000,
95+
'bidirectional': True,
96+
'audioTransport': {
97+
'transport': 'json',
98+
'encoding': 'base64',
99+
'audio_field': 'audio',
100+
'receive_audio_field': 'audio',
101+
'static_fields': {'foo': 'bar'},
102+
},
103+
},
104+
}
105+
assert actual == expected
106+
107+
108+
def test_audio_transport_configuration_model_with_json_transport_and_encoding_not_set():
109+
with pytest.raises(ValidationError) as err:
110+
config = AudioTransportConfiguration(transport=AudioTransportTransport.JSON)
111+
assert "encoding must be specified when transport is JSON" in str(err.value)
112+
113+
62114
@responses.activate
63115
def test_start_audio_connector():
64116
build_response(

0 commit comments

Comments
 (0)