Skip to content

Commit d279fc6

Browse files
Changes for implementing server calling APIs (#21029)
* Call automation and recording APIs implementation * Changes to call recording APIs * Recording download live test - Sync * Resolving lint warnings * Changing from AsyncHttpReponse to HttpReponse in sync files * Removing convertor for StartCallRecording and fix for CI build failure * Fixing CI build issues with importing urlparse * Updating recording file for recording download parallel * skipping test_download_content_to_stream_on_chunks_parallel as it's failing with 401 and needs investigation * Resolving lint errors
1 parent f688888 commit d279fc6

18 files changed

+1540
-44
lines changed

sdk/communication/azure-communication-callingserver/azure/communication/callingserver/__init__.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@
1414
CreateCallRequest, PhoneNumberIdentifierModel,
1515
PlayAudioRequest, PlayAudioResult,
1616
MediaType, EventSubscriptionType,
17-
OperationStatus)
17+
OperationStatus, CallConnectionStateChangedEvent,
18+
ToneReceivedEvent, ToneInfo,
19+
PlayAudioResultEvent, CommunicationIdentifierModel,
20+
CommunicationUserIdentifierModel, AddParticipantResultEvent,
21+
CallConnectionState, ToneValue)
1822
from ._models import (
1923
CreateCallOptions,
2024
JoinCallOptions,
2125
PlayAudioOptions,
2226
CallLocator,
2327
GroupCallLocator,
24-
ServerCallLocator
28+
ServerCallLocator,
29+
CallingServerEventType
2530
)
2631
from ._shared.models import CommunicationIdentifier, CommunicationUserIdentifier, PhoneNumberIdentifier
2732

@@ -46,6 +51,16 @@
4651
'PlayAudioResult',
4752
'CallLocator',
4853
'GroupCallLocator',
49-
'ServerCallLocator'
54+
'ServerCallLocator',
55+
'CallConnectionStateChangedEvent',
56+
'ToneReceivedEvent',
57+
'ToneInfo',
58+
'PlayAudioResultEvent',
59+
'CommunicationIdentifierModel',
60+
'CommunicationUserIdentifierModel',
61+
'AddParticipantResultEvent',
62+
'CallConnectionState',
63+
'ToneValue',
64+
'CallingServerEventType'
5065
]
5166
__version__ = VERSION

sdk/communication/azure-communication-callingserver/azure/communication/callingserver/_call_connection.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@
33
# Licensed under the MIT License. See License.txt in the project root for
44
# license information.
55
# --------------------------------------------------------------------------
6-
76
from typing import TYPE_CHECKING, Any, Optional # pylint: disable=unused-import
8-
97
from azure.core.tracing.decorator import distributed_trace
10-
8+
from .utils._utils import CallingServerUtils
119
from ._communication_identifier_serializer import serialize_identifier
1210
from ._converters import (
1311
AddParticipantRequestConverter,
1412
RemoveParticipantRequestConverter,
1513
CancelAllMediaOperationsConverter,
1614
TransferCallRequestConverter,
17-
CancelMediaOperationRequestConverter,
1815
CancelParticipantMediaOperationRequestConverter,
1916
PlayAudioRequestConverter,
2017
PlayAudioToParticipantRequestConverter
@@ -76,9 +73,18 @@ def play_audio(
7673
if not audio_file_uri:
7774
raise ValueError("audio_file_uri can not be None")
7875

76+
if not CallingServerUtils.is_valid_url(audio_file_uri):
77+
raise ValueError("audio_file_uri is invalid")
78+
7979
if not play_audio_options:
8080
raise ValueError("options can not be None")
8181

82+
if not play_audio_options.audio_file_id:
83+
raise ValueError("audio_file_id can not be None")
84+
85+
if not CallingServerUtils.is_valid_url(play_audio_options.callback_uri):
86+
raise ValueError("callback_uri is invalid")
87+
8288
play_audio_request = PlayAudioRequestConverter.convert(audio_file_uri, play_audio_options)
8389

8490
return self._call_connection_client.play_audio(
@@ -147,9 +153,15 @@ def play_audio_to_participant(
147153
if not audio_file_uri:
148154
raise ValueError("audio_file_uri can not be None")
149155

156+
if not CallingServerUtils.is_valid_url(audio_file_uri):
157+
raise ValueError("audio_file_uri is invalid")
158+
150159
if not play_audio_options:
151160
raise ValueError("play_audio_options can not be None")
152161

162+
if not CallingServerUtils.is_valid_url(play_audio_options.callback_uri):
163+
raise ValueError("callback_uri is invalid")
164+
153165
play_audio_to_participant_request = PlayAudioToParticipantRequestConverter.convert(
154166
identifier=serialize_identifier(participant),
155167
audio_file_uri=audio_file_uri,

sdk/communication/azure-communication-callingserver/azure/communication/callingserver/_callingserver_client.py

Lines changed: 165 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
# --------------------------------------------------------------------------
66

77
from typing import TYPE_CHECKING, Any, List, Optional # pylint: disable=unused-import
8-
98
from azure.core.tracing.decorator import distributed_trace
10-
9+
from azure.core.pipeline.transport import HttpResponse
10+
from .utils._utils import CallingServerUtils
11+
from ._content_downloader import ContentDownloader
12+
from ._download import ContentStreamDownloader
1113
from ._communication_identifier_serializer import serialize_identifier
1214
from ._communication_call_locator_serializer import serialize_call_locator
1315
from ._generated._azure_communication_calling_server_service import \
@@ -16,10 +18,13 @@
1618
CreateCallRequest,
1719
PhoneNumberIdentifierModel,
1820
PlayAudioResult,
19-
AddParticipantResult
21+
AddParticipantResult,
22+
StartCallRecordingResult,
23+
CallRecordingProperties,
24+
StartCallRecordingRequest,
25+
StartCallRecordingWithCallLocatorRequest
2026
)
2127
from ._shared.models import CommunicationIdentifier
22-
from ._models import CallLocator
2328
from ._call_connection import CallConnection
2429
from ._converters import (
2530
JoinCallRequestConverter,
@@ -35,7 +40,13 @@
3540

3641
if TYPE_CHECKING:
3742
from azure.core.credentials import TokenCredential
38-
from ._models import CreateCallOptions, JoinCallOptions, PlayAudioOptions
43+
from ._models import (
44+
CreateCallOptions,
45+
JoinCallOptions,
46+
PlayAudioOptions,
47+
ParallelDownloadOptions,
48+
CallLocator
49+
)
3950

4051
class CallingServerClient(object):
4152
"""A client to interact with the AzureCommunicationService Calling Server.
@@ -196,9 +207,9 @@ def join_call(
196207
raise ValueError("call_options can not be None")
197208

198209
join_call_request = JoinCallRequestConverter.convert(
199-
serialize_call_locator(call_locator),
200-
serialize_identifier(source),
201-
call_options
210+
call_locator=serialize_call_locator(call_locator),
211+
source=serialize_identifier(source),
212+
join_call_options=call_options
202213
)
203214

204215
join_call_response = self._server_call_client.join_call(
@@ -224,13 +235,17 @@ def play_audio(
224235
raise ValueError("call_locator can not be None")
225236
if not audio_file_uri:
226237
raise ValueError("audio_file_uri can not be None")
238+
if not CallingServerUtils.is_valid_url(audio_file_uri):
239+
raise ValueError("audio_file_uri is invalid")
227240
if not play_audio_options:
228241
raise ValueError("options can not be None")
242+
if not CallingServerUtils.is_valid_url(play_audio_options.callback_uri):
243+
raise ValueError("callback_uri is invalid")
229244

230245
play_audio_request = PlayAudioWithCallLocatorRequestConverter.convert(
231-
serialize_call_locator(call_locator),
232-
audio_file_uri,
233-
play_audio_options
246+
call_locator=serialize_call_locator(call_locator),
247+
audio_file_uri=audio_file_uri,
248+
play_audio_options=play_audio_options
234249
)
235250

236251
return self._server_call_client.play_audio(
@@ -254,14 +269,18 @@ def play_audio_to_participant(
254269
raise ValueError("participant can not be None")
255270
if not audio_file_uri:
256271
raise ValueError("audio_file_uri can not be None")
272+
if not CallingServerUtils.is_valid_url(audio_file_uri):
273+
raise ValueError("audio_file_uri is invalid")
257274
if not play_audio_options:
258275
raise ValueError("play_audio_options can not be None")
276+
if not CallingServerUtils.is_valid_url(play_audio_options.callback_uri):
277+
raise ValueError("callback_uri is invalid")
259278

260279
play_audio_to_participant_request = PlayAudioToParticipantWithCallLocatorRequestConverter.convert(
261-
serialize_call_locator(call_locator),
262-
serialize_identifier(participant),
263-
audio_file_uri,
264-
play_audio_options
280+
call_locator=serialize_call_locator(call_locator),
281+
identifier=serialize_identifier(participant),
282+
audio_file_uri=audio_file_uri,
283+
play_audio_options=play_audio_options
265284
)
266285

267286
return self._server_call_client.participant_play_audio(
@@ -359,7 +378,8 @@ def cancel_participant_media_operation(
359378
if not media_operation_id:
360379
raise ValueError("media_operation_id can not be None")
361380

362-
cancel_participant_media_operation_request = CancelParticipantMediaOperationWithCallLocatorRequestConverter.convert(
381+
cancel_participant_media_operation_request = \
382+
CancelParticipantMediaOperationWithCallLocatorRequestConverter.convert(
363383
serialize_call_locator(call_locator),
364384
serialize_identifier(participant),
365385
media_operation_id=media_operation_id
@@ -368,4 +388,132 @@ def cancel_participant_media_operation(
368388
return self._server_call_client.cancel_participant_media_operation(
369389
cancel_participant_media_operation_request=cancel_participant_media_operation_request,
370390
**kwargs
371-
)
391+
)
392+
393+
@distributed_trace()
394+
def start_recording(
395+
self,
396+
call_locator, # type: CallLocator
397+
recording_state_callback_uri, # type: str
398+
**kwargs # type: Any
399+
): # type: (...) -> StartCallRecordingResult
400+
401+
if not call_locator:
402+
raise ValueError("call_locator cannot be None")
403+
if not CallingServerUtils.is_valid_url(recording_state_callback_uri):
404+
raise ValueError("recording_state_callback_uri is invalid")
405+
406+
start_call_recording_request = StartCallRecordingRequest(
407+
recording_state_callback_uri=recording_state_callback_uri,
408+
**kwargs
409+
)
410+
411+
start_call_recording_with_calllocator_request = StartCallRecordingWithCallLocatorRequest(
412+
call_locator=serialize_call_locator(call_locator),
413+
start_call_recording_request=start_call_recording_request
414+
)
415+
416+
return self._server_call_client.start_recording(
417+
start_call_recording_with_call_locator_request=start_call_recording_with_calllocator_request,
418+
**kwargs
419+
)
420+
421+
@distributed_trace()
422+
def pause_recording(
423+
self,
424+
recording_id, # type: str
425+
**kwargs # type: Any
426+
): # type: (...) -> HttpResponse
427+
428+
if not recording_id:
429+
raise ValueError("recording_id cannot be None")
430+
431+
return self._server_call_client.pause_recording(
432+
recording_id=recording_id,
433+
**kwargs
434+
)
435+
436+
@distributed_trace()
437+
def resume_recording(
438+
self,
439+
recording_id, # type: str
440+
**kwargs # type: Any
441+
): # type: (...) -> HttpResponse
442+
443+
if not recording_id:
444+
raise ValueError("recording_id cannot be None")
445+
446+
return self._server_call_client.resume_recording(
447+
recording_id=recording_id,
448+
**kwargs
449+
)
450+
451+
@distributed_trace()
452+
def stop_recording(
453+
self,
454+
recording_id, # type: str
455+
**kwargs # type: Any
456+
): # type: (...) -> HttpResponse
457+
458+
if not recording_id:
459+
raise ValueError("recording_id cannot be None")
460+
461+
return self._server_call_client.stop_recording(
462+
recording_id=recording_id,
463+
**kwargs
464+
)
465+
466+
@distributed_trace()
467+
def get_recording_properities(
468+
self,
469+
recording_id, # type: str
470+
**kwargs # type: Any
471+
): # type: (...) -> CallRecordingProperties
472+
473+
if not recording_id:
474+
raise ValueError("recording_id cannot be None")
475+
476+
return self._server_call_client.get_recording_properties(
477+
recording_id=recording_id,
478+
**kwargs
479+
)
480+
481+
@distributed_trace()
482+
def download(
483+
self,
484+
content_url, # type: str
485+
start_range=None, # type: int
486+
end_range=None, # type: int
487+
parallel_download_options=None, # type: ParallelDownloadOptions
488+
**kwargs # type: Any
489+
): # type: (...) -> ContentStreamDownloader
490+
"""Download using content url.
491+
492+
:param str content_url:
493+
The content url.
494+
:returns: ContentStreamDownloader for a successful download request.
495+
:rtype: ~ContentStreamDownloader
496+
"""
497+
if not content_url:
498+
raise ValueError("content_url can not be None")
499+
500+
if not CallingServerUtils.is_valid_url(content_url):
501+
raise ValueError("content_url is invalid")
502+
503+
content_downloader = ContentDownloader(
504+
self._callingserver_service_client._client, # pylint:disable=protected-access
505+
self._callingserver_service_client._serialize, # pylint:disable=protected-access
506+
self._callingserver_service_client._deserialize, # pylint:disable=protected-access
507+
self._callingserver_service_client._config) # pylint:disable=protected-access
508+
stream_downloader = ContentStreamDownloader(
509+
content_downloader,
510+
self._callingserver_service_client._config, # pylint:disable=protected-access
511+
start_range,
512+
end_range,
513+
endpoint=content_url,
514+
parallel_download_options=parallel_download_options,
515+
**kwargs
516+
)
517+
stream_downloader._setup() # pylint:disable=protected-access
518+
519+
return stream_downloader

0 commit comments

Comments
 (0)