From 0aa1ea1144c149aa1163622c756350504c5c0345 Mon Sep 17 00:00:00 2001 From: maxkahan Date: Fri, 27 Sep 2024 17:27:21 +0100 Subject: [PATCH] finish adding audio connector --- README.md | 1 + video/src/vonage_video/models/__init__.py | 33 ++++++++- .../vonage_video/models/audio_connector.py | 20 +++--- video/src/vonage_video/models/enums.py | 2 +- video/src/vonage_video/video.py | 3 +- video/tests/data/audio_connector.json | 4 ++ video/tests/test_audio_connector.py | 70 +++++++++++++++++++ 7 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 video/tests/data/audio_connector.json create mode 100644 video/tests/test_audio_connector.py diff --git a/README.md b/README.md index 9c5d8684..780929f7 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Build Status](https://github.com/Vonage/vonage-python-sdk/workflows/Build/badge.svg)](https://github.com/Vonage/vonage-python-sdk/actions) [![Python versions supported](https://img.shields.io/pypi/pyversions/vonage.svg)](https://pypi.python.org/pypi/vonage) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) +![Total lines](https://sloc.xyz/github/vonage/vonage-python-sdk) This is the Python server SDK for Vonage's API. To use it you'll need a Vonage account. Sign up [for free at vonage.com][signup]. diff --git a/video/src/vonage_video/models/__init__.py b/video/src/vonage_video/models/__init__.py index a63621f2..4fe171f2 100644 --- a/video/src/vonage_video/models/__init__.py +++ b/video/src/vonage_video/models/__init__.py @@ -1,12 +1,39 @@ -from .enums import ArchiveMode, MediaMode, TokenRole +from .audio_connector import ( + AudioConnectorData, + AudioConnectorOptions, + AudioConnectorWebSocket, +) +from .captions import CaptionsData, CaptionsOptions +from .enums import ( + ArchiveMode, + AudioSampleRate, + LanguageCode, + MediaMode, + P2pPreference, + TokenRole, +) from .session import SessionOptions, VideoSession +from .signal import SignalData +from .stream import StreamInfo, StreamLayout, StreamLayoutOptions from .token import TokenOptions __all__ = [ - 'MediaMode', + 'AudioConnectorData', + 'AudioConnectorOptions', + 'AudioConnectorWebSocket', + 'CaptionsData', + 'CaptionsOptions', 'ArchiveMode', + 'MediaMode', 'TokenRole', - 'TokenOptions', + 'P2pPreference', + 'LanguageCode', + 'AudioSampleRate', 'SessionOptions', 'VideoSession', + 'SignalData', + 'StreamInfo', + 'StreamLayoutOptions', + 'StreamLayout', + 'TokenOptions', ] diff --git a/video/src/vonage_video/models/audio_connector.py b/video/src/vonage_video/models/audio_connector.py index 469bedc3..ff272bc0 100644 --- a/video/src/vonage_video/models/audio_connector.py +++ b/video/src/vonage_video/models/audio_connector.py @@ -1,21 +1,21 @@ -from typing import Optional +from typing import List, Optional from pydantic import BaseModel, Field from vonage_video.models.enums import AudioSampleRate -class AudioConnectorWebsocket(BaseModel): +class AudioConnectorWebSocket(BaseModel): """The audio connector websocket options. Args: uri (str): The URI. - streams (list): The streams. - headers (dict): The headers. - audio_rate (AudioSampleRate): The audio sample rate. + streams (List[str]): Stream IDs to include. If not provided, all streams are included. + headers (dict): The headers to send to your WebSocket server. + audio_rate (AudioSampleRate): The audio sample rate in Hertz. """ uri: str - streams: Optional[list] = None + streams: Optional[List[str]] = None headers: Optional[dict] = None audio_rate: Optional[AudioSampleRate] = Field(None, serialization_alias='audioRate') @@ -26,16 +26,16 @@ class AudioConnectorOptions(BaseModel): Args: session_id (str): The session ID. token (str): The token. - websocket (AudioConnectorWebsocket): The audio connector websocket. + websocket (AudioConnectorWebSocket): The audio connector websocket. """ session_id: str = Field(..., serialization_alias='sessionId') token: str - websocket: AudioConnectorWebsocket + websocket: AudioConnectorWebSocket class AudioConnectorData(BaseModel): - """Class containing audio connector ID and audio captioning session ID.""" + """Class containing Audio Connector WebSocket ID and connection ID.""" id: Optional[str] = None - captions_id: Optional[str] = Field(None, serialization_alias='captionsId') + connection_id: Optional[str] = Field(None, validation_alias='connectionId') diff --git a/video/src/vonage_video/models/enums.py b/video/src/vonage_video/models/enums.py index 3326828a..6a0760ed 100644 --- a/video/src/vonage_video/models/enums.py +++ b/video/src/vonage_video/models/enums.py @@ -39,6 +39,6 @@ class LanguageCode(str, Enum): TH_TH = 'th-TH' -class AudioSampleRate(str, Enum): +class AudioSampleRate(int, Enum): KHZ_8 = 8000 KHZ_16 = 16000 diff --git a/video/src/vonage_video/video.py b/video/src/vonage_video/video.py index 81369c26..500afe09 100644 --- a/video/src/vonage_video/video.py +++ b/video/src/vonage_video/video.py @@ -2,6 +2,7 @@ from pydantic import validate_call from vonage_http_client.http_client import HttpClient +from vonage_video.models.audio_connector import AudioConnectorData, AudioConnectorOptions from vonage_video.models.captions import CaptionsData, CaptionsOptions from vonage_video.models.session import SessionOptions, VideoSession from vonage_video.models.signal import SignalData @@ -252,4 +253,4 @@ def start_audio_connector(self, options: AudioConnectorOptions) -> AudioConnecto options.model_dump(exclude_none=True, by_alias=True), ) - return AudioConnectorData(audio_connector_id=response['audioConnectorId']) + return AudioConnectorData(**response) diff --git a/video/tests/data/audio_connector.json b/video/tests/data/audio_connector.json new file mode 100644 index 00000000..e0cdc7b5 --- /dev/null +++ b/video/tests/data/audio_connector.json @@ -0,0 +1,4 @@ +{ + "id": "b3cd31f4-020e-4ba3-9a2a-12d98b8a184f", + "connectionId": "1bf530df-97f4-4437-b6c9-2a66200200c8" +} \ No newline at end of file diff --git a/video/tests/test_audio_connector.py b/video/tests/test_audio_connector.py new file mode 100644 index 00000000..0c9cce6b --- /dev/null +++ b/video/tests/test_audio_connector.py @@ -0,0 +1,70 @@ +from os.path import abspath + +import responses +from vonage_http_client import HttpClient +from vonage_video.models.audio_connector import ( + AudioConnectorOptions, + AudioConnectorWebSocket, +) +from vonage_video.models.enums import AudioSampleRate, TokenRole +from vonage_video.models.token import TokenOptions +from vonage_video.video import Video + +from testutils import build_response, get_mock_jwt_auth + +path = abspath(__file__) + + +video = Video(HttpClient(get_mock_jwt_auth())) + + +def test_audio_connector_options_model(): + options = AudioConnectorOptions( + session_id='test_session_id', + token='test_token', + websocket=AudioConnectorWebSocket( + uri='test_uri', + streams=['test_stream_id'], + headers={'test_header': 'test_value'}, + audio_rate=AudioSampleRate.KHZ_16, + ), + ) + + assert options.model_dump(by_alias=True) == { + 'sessionId': 'test_session_id', + 'token': 'test_token', + 'websocket': { + 'uri': 'test_uri', + 'streams': ['test_stream_id'], + 'headers': {'test_header': 'test_value'}, + 'audioRate': 16000, + }, + } + + +@responses.activate +def test_start_audio_connector(): + build_response( + path, + 'POST', + 'https://video.api.vonage.com/v2/project/test_application_id/connect', + 'audio_connector.json', + 200, + ) + + session_id = 'test_session_id' + options = AudioConnectorOptions( + session_id=session_id, + token=video.generate_client_token( + TokenOptions(session_id=session_id, role=TokenRole.MODERATOR) + ), + websocket=AudioConnectorWebSocket( + uri='wss://example.com/ws', + audio_rate=AudioSampleRate.KHZ_16, + ), + ) + + audio_connector = video.start_audio_connector(options) + + assert audio_connector.id == 'b3cd31f4-020e-4ba3-9a2a-12d98b8a184f' + assert audio_connector.connection_id == '1bf530df-97f4-4437-b6c9-2a66200200c8'