Skip to content

Commit 9883e2f

Browse files
v-durgeshsVinothini Dharmaraj
andauthored
Added live test Media streaming and Transcription (#35960)
* Added live test Media streaming and Transcription * updating the live tests for media streaming and transcription --------- Co-authored-by: Vinothini Dharmaraj <[email protected]>
1 parent 21e28b2 commit 9883e2f

File tree

4 files changed

+208
-12
lines changed

4 files changed

+208
-12
lines changed

sdk/communication/azure-communication-callautomation/azure/communication/callautomation/_call_automation_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@ def create_call(
224224
targets = [serialize_identifier(p) for p in target_participant]
225225
except TypeError:
226226
targets = [serialize_identifier(target_participant)]
227-
media_config = media_streaming.to_generated() if media_streaming else None
228-
transcription_config = transcription.to_generated() if transcription else None
227+
media_config = media_streaming._to_generated() if media_streaming else None # pylint:disable=protected-access
228+
transcription_config = transcription._to_generated() if transcription else None # pylint:disable=protected-access
229229
create_call_request = CreateCallRequest(
230230
targets=targets,
231231
callback_uri=callback_url,
@@ -337,9 +337,9 @@ def answer_call(
337337
call_intelligence_options=call_intelligence_options,
338338
answered_by=serialize_communication_user_identifier(
339339
self.source) if self.source else None,
340-
media_streaming_options=media_streaming._to_generated(
341-
) if media_streaming else None,
342-
transcription_options=transcription._to_generated()
340+
media_streaming_options=media_streaming._to_generated() # pylint:disable=protected-access
341+
if media_streaming else None,
342+
transcription_options=transcription._to_generated() # pylint:disable=protected-access
343343
if transcription else None,
344344
operation_context=operation_context
345345
)

sdk/communication/azure-communication-callautomation/azure/communication/callautomation/aio/_call_automation_client_async.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ async def create_call(
210210
targets = [serialize_identifier(p) for p in target_participant]
211211
except TypeError:
212212
targets = [serialize_identifier(target_participant)]
213-
media_config = media_streaming.to_generated() if media_streaming else None
214-
transcription_config = transcription.to_generated() if transcription else None
213+
media_config = media_streaming._to_generated() if media_streaming else None # pylint:disable=protected-access
214+
transcription_config = transcription._to_generated() if transcription else None # pylint:disable=protected-access
215215
create_call_request = CreateCallRequest(
216216
targets=targets,
217217
callback_uri=callback_url,
@@ -320,9 +320,9 @@ async def answer_call(
320320
answer_call_request = AnswerCallRequest(
321321
incoming_call_context=incoming_call_context,
322322
callback_uri=callback_url,
323-
media_streaming_options=media_streaming.to_generated(
323+
media_streaming_options=media_streaming._to_generated( # pylint:disable=protected-access
324324
) if media_streaming else None,
325-
transcription_options=transcription.to_generated()
325+
transcription_options=transcription._to_generated() # pylint:disable=protected-access
326326
if transcription else None,
327327
answered_by=serialize_communication_user_identifier(
328328
self.source) if self.source else None,

sdk/communication/azure-communication-callautomation/tests/callautomation_test_case.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,16 @@ def setup_class(cls):
3737
cls.servicebus_connection_str = os.environ.get('SERVICEBUS_STRING')
3838
cls.dispatcher_endpoint = os.environ.get('DISPATCHER_ENDPOINT')
3939
cls.file_source_url = os.environ.get('FILE_SOURCE_URL')
40+
cls.cognitive_service_endpoint = os.environ.get('COGNITIVE_SERVICE_ENDPOINT')
41+
cls.transport_url = os.environ.get('TRANSPORT_URL')
4042
else:
4143
print("Recorded Test")
4244
cls.connection_str = "endpoint=https://someEndpoint/;accesskey=someAccessKeyw=="
4345
cls.servicebus_connection_str = "Endpoint=sb://someEndpoint/;SharedAccessKeyName=somekey;SharedAccessKey=someAccessKey="
4446
cls.dispatcher_endpoint = "https://REDACTED.azurewebsites.net"
4547
cls.file_source_url = "https://REDACTED/prompt.wav"
48+
cls.cognitive_service_endpoint = "https://REDACTED.cognitiveservices.azure.com"
49+
cls.transport_url ="wss://REDACTED"
4650

4751
cls.dispatcher_callback = cls.dispatcher_endpoint + '/api/servicebuscallback/events'
4852
cls.identity_client = CommunicationIdentityClient.from_connection_string(cls.connection_str)
@@ -266,4 +270,55 @@ def terminate_call(self, unique_id) -> None:
266270
raise ValueError("Receiver CallDisconnected event is None")
267271
finally:
268272
while unique_id in self.wait_for_event_flags: self.wait_for_event_flags.remove(unique_id)
269-
pass
273+
pass
274+
275+
def establish_callconnection_voip_with_streaming_options(self, caller, target, options, is_transcription) -> tuple:
276+
call_automation_client_caller = CallAutomationClient.from_connection_string(self.connection_str, source=caller) # for creating call
277+
call_automation_client_target = CallAutomationClient.from_connection_string(self.connection_str, source=target) # answering call, all other actions
278+
279+
unique_id = self._unique_key_gen(caller, target)
280+
if is_live():
281+
dispatcher_url = f"{self.dispatcher_endpoint}/api/servicebuscallback/subscribe?q={unique_id}"
282+
response = requests.post(dispatcher_url)
283+
284+
if response is None:
285+
raise ValueError("Response cannot be None")
286+
287+
print(f"Subscription to dispatcher of {unique_id}: {response.status_code}")
288+
289+
self.wait_for_event_flags.append(unique_id)
290+
thread = threading.Thread(target=self._message_awaiter, args=(unique_id,))
291+
thread.start()
292+
293+
# create a call with options either media streaming or transcription.
294+
create_call_result = call_automation_client_caller.create_call(
295+
target_participant=target,
296+
callback_url=(self.dispatcher_callback + "?q={}".format(unique_id)),
297+
media_streaming=options if not is_transcription else None,
298+
transcription=options if is_transcription else None,
299+
cognitive_services_endpoint=self.cognitive_service_endpoint if is_transcription else None
300+
)
301+
302+
if create_call_result is None:
303+
raise ValueError("Invalid create_call_result")
304+
305+
caller_connection_id = create_call_result.call_connection_id
306+
if caller_connection_id is None:
307+
raise ValueError("Caller connection ID is None")
308+
309+
# wait for incomingCallContext
310+
incoming_call_event = self.check_for_event('IncomingCall', unique_id, timedelta(seconds=30))
311+
if incoming_call_event is None:
312+
raise ValueError("incoming_call_event is None")
313+
incoming_call_context = incoming_call_event["incomingCallContext"]
314+
315+
# answer the call
316+
answer_call_result = call_automation_client_target.answer_call(incoming_call_context=incoming_call_context, callback_url=self.dispatcher_callback)
317+
if answer_call_result is None:
318+
raise ValueError("Invalid answer_call result")
319+
320+
call_connection_caller = CallConnectionClient.from_connection_string(self.connection_str, caller_connection_id)
321+
call_connection_target = CallConnectionClient.from_connection_string(self.connection_str, answer_call_result.call_connection_id)
322+
self.open_call_connections[unique_id] = call_connection_caller
323+
324+
return unique_id, call_connection_caller, call_connection_target

sdk/communication/azure-communication-callautomation/tests/test_e2e_media_client.py

Lines changed: 143 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
from azure.communication.callautomation import (
1313
FileSource,
1414
DtmfTone,
15-
PhoneNumberIdentifier
15+
PhoneNumberIdentifier,
16+
MediaStreamingOptions,
17+
MediaStreamingContentType,
18+
MediaStreamingTransportType,
19+
MediaStreamingAudioChannelType,
20+
TranscriptionOptions,
21+
TranscriptionTransportType
1622
)
1723
from callautomation_test_case import CallAutomationRecordedTestCase
1824
from azure.communication.callautomation._shared.models import identifier_from_raw_id
@@ -178,4 +184,139 @@ def test_add_and_hold_unhold_participant_in_a_call(self):
178184
raise ValueError("Failed to unhold participant")
179185

180186
self.terminate_call(unique_id)
181-
return
187+
return
188+
189+
@recorded_by_proxy
190+
def test_start_stop_media_streaming_in_a_call(self):
191+
192+
# try to establish the call
193+
caller = self.identity_client.create_user()
194+
target = self.identity_client.create_user()
195+
196+
media_streaming_options=MediaStreamingOptions(
197+
transport_url=self.transport_url,
198+
transport_type=MediaStreamingTransportType.WEBSOCKET,
199+
content_type=MediaStreamingContentType.AUDIO,
200+
audio_channel_type=MediaStreamingAudioChannelType.MIXED,
201+
start_media_streaming=False
202+
)
203+
204+
unique_id, call_connection, _ = self.establish_callconnection_voip_with_streaming_options(caller, target, media_streaming_options, False)
205+
206+
# check returned events
207+
connected_event = self.check_for_event('CallConnected', call_connection._call_connection_id, timedelta(seconds=15))
208+
participant_updated_event = self.check_for_event('ParticipantsUpdated', call_connection._call_connection_id, timedelta(seconds=15))
209+
210+
if connected_event is None:
211+
raise ValueError("Caller CallConnected event is None")
212+
if participant_updated_event is None:
213+
raise ValueError("Caller ParticipantsUpdated event is None")
214+
215+
# start media streaming.
216+
call_connection.start_media_streaming()
217+
218+
# check for MediaStreamingStarted event
219+
media_streaming_started = self.check_for_event('MediaStreamingStarted', call_connection._call_connection_id, timedelta(seconds=30))
220+
if media_streaming_started is None:
221+
raise ValueError("MediaStreamingStarted event is None")
222+
223+
time.sleep(3)
224+
225+
# check for media streaming subscription from call connection properties for media streaming started event
226+
call_connection_properties=call_connection.get_call_properties()
227+
if call_connection_properties is None:
228+
raise ValueError("call_connection_properties is None")
229+
if call_connection_properties.media_streaming_subscription is None:
230+
raise ValueError("call_connection_properties.media_streaming_subscription is None")
231+
if call_connection_properties.media_streaming_subscription.state!='active':
232+
raise ValueError("media streaming state is invalid for MediaStreamingStarted event")
233+
234+
# stop media streaming.
235+
call_connection.stop_media_streaming()
236+
237+
# check for MediaStreamingStopped event
238+
media_streaming_stopped = self.check_for_event('MediaStreamingStopped', call_connection._call_connection_id, timedelta(seconds=30))
239+
if media_streaming_stopped is None:
240+
raise ValueError("MediaStreamingStopped event is None")
241+
242+
# check for media streaming subscription from call connection properties for media streaming stopped event
243+
call_connection_properties=call_connection.get_call_properties()
244+
if call_connection_properties is None:
245+
raise ValueError("call_connection_properties is None")
246+
if call_connection_properties.media_streaming_subscription is None:
247+
raise ValueError("call_connection_properties.media_streaming_subscription is None")
248+
if call_connection_properties.media_streaming_subscription.state!='inactive':
249+
raise ValueError("media streaming state is invalid for MediaStreamingStopped event")
250+
251+
self.terminate_call(unique_id)
252+
return
253+
254+
@recorded_by_proxy
255+
def test_start_stop_transcription_in_call(self):
256+
# try to establish the call
257+
caller = self.identity_client.create_user()
258+
target = self.identity_client.create_user()
259+
260+
transcription_options=TranscriptionOptions(
261+
transport_url=self.transport_url,
262+
transport_type=TranscriptionTransportType.WEBSOCKET,
263+
locale="en-US",
264+
start_transcription=False)
265+
266+
unique_id, call_connection, _ = self.establish_callconnection_voip_with_streaming_options(caller, target, transcription_options, True)
267+
268+
# check returned events
269+
connected_event = self.check_for_event('CallConnected', call_connection._call_connection_id, timedelta(seconds=15))
270+
participant_updated_event = self.check_for_event('ParticipantsUpdated', call_connection._call_connection_id, timedelta(seconds=15))
271+
272+
if connected_event is None:
273+
raise ValueError("Caller CallConnected event is None")
274+
if participant_updated_event is None:
275+
raise ValueError("Caller ParticipantsUpdated event is None")
276+
277+
# start transcription
278+
call_connection.start_transcription(locale="en-ca")
279+
280+
# check for TranscriptionStarted event
281+
transcription_started = self.check_for_event('TranscriptionStarted', call_connection._call_connection_id, timedelta(seconds=30))
282+
if transcription_started is None:
283+
raise ValueError("TranscriptionStarted event is None")
284+
285+
# check for transcription subscription from call connection properties for transcription started event
286+
call_connection_properties=call_connection.get_call_properties()
287+
if call_connection_properties is None:
288+
raise ValueError("call_connection_properties is None")
289+
if call_connection_properties.transcription_subscription is None:
290+
raise ValueError("call_connection_properties.transcription_subscription is None")
291+
if call_connection_properties.transcription_subscription.state!='active':
292+
raise ValueError("transcription subscription state is invalid for TranscriptionStarted event")
293+
294+
time.sleep(3)
295+
call_connection.update_transcription(locale="en-gb")
296+
297+
# check for TranscriptionUpdated event
298+
transcription_updated = self.check_for_event('TranscriptionUpdated', call_connection._call_connection_id, timedelta(seconds=30))
299+
if transcription_updated is None:
300+
raise ValueError("TranscriptionUpdated event is None")
301+
302+
time.sleep(3)
303+
304+
# stop transcription
305+
call_connection.stop_transcription()
306+
307+
# check for TranscriptionStopped event
308+
transcription_stopped = self.check_for_event('TranscriptionStopped', call_connection._call_connection_id, timedelta(seconds=30))
309+
if transcription_stopped is None:
310+
raise ValueError("TranscriptionStopped event is None")
311+
312+
# check for transcription subscription from call connection properties for transcription stopped event
313+
call_connection_properties=call_connection.get_call_properties()
314+
if call_connection_properties is None:
315+
raise ValueError("call_connection_properties is None")
316+
if call_connection_properties.transcription_subscription is None:
317+
raise ValueError("call_connection_properties.transcription_subscription is None")
318+
if call_connection_properties.transcription_subscription.state!='inactive':
319+
raise ValueError("transcription subscription state is invalid for TranscriptionStopped event")
320+
321+
self.terminate_call(unique_id)
322+
return

0 commit comments

Comments
 (0)