diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 7374b9c4c4b21..5e19bc2a2e4e1 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -59,6 +59,7 @@ com.azure:azure-aot-graalvm-samples;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-aot-graalvm-perf;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-communication-chat;1.3.0;1.4.0-beta.1 com.azure:azure-communication-callingserver;1.0.0-beta.4;1.0.0-beta.5 +com.azure:azure-communication-callautomation;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-communication-common;1.2.0;1.3.0-beta.2 com.azure:azure-communication-common-perf;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-communication-sms;1.1.5;1.2.0-beta.1 diff --git a/sdk/communication/azure-communication-callautomation/CHANGELOG.md b/sdk/communication/azure-communication-callautomation/CHANGELOG.md new file mode 100644 index 0000000000000..7340778d85337 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/CHANGELOG.md @@ -0,0 +1,61 @@ +# Release History + +## 1.0.0-beta.5 (Unreleased) +This is the first version of the restart of Azure Communication Service Calling Server. For more information, please see the [README][read_me]. + +- Name changed to Azure Communication Service Call Automation. +- Feature re-designed. +- Added interfaces from `com.azure.core.client.traits` to `CallAutomationClientBuilder` +- Added `retryOptions` to `CallAutomationClientBuilder` + +### Features Added +- Create outbound call to an Azure Communication Service user or a phone number. +- Answer/Redirect/Reject incoming call from an Azure Communication Service user or a phone number. +- Hangup and terminate the existing call. +- Play audio in the call. +- Call recording. +- Get, add and remove participants from the call. +- Recording download apis. + +### Breaking Changes +- Incompatible with previous version of service + +## 1.0.0-beta.4 (2021-10-06) +### Features Added +- Add support for TokenCredential authentication with CallingServerClientBuilder. +- Added support for custom options(Recordingcontenttype, Recordingchanneltype, Recordingformattype) for Mixed Audio feature + +### Bugs Fixed +- Using released version of azure-communication-common. + +### Other Changes +#### Dependency updates +- Upgraded `azure-communication-common` to 1.0.4 + +## 1.0.0-beta.3 (2021-07-26) +### Features Added +- Added RedirectPolicy as a new HttpPolicy to redirect requests based on the HttpResponse. + +## 1.0.0-beta.2 (2021-06-25) +- Updated sdk and apis documentation. + +### Bug Fixes +- Fixed bug with AddParticipant api. + +## 1.0.0-beta.1 (2021-06-24) +This is the first release of Azure Communication Service Calling Server. For more information, please see the [README][read_me]. + +This is a Public Preview version, so breaking changes are possible in subsequent releases as we improve the product. To provide feedback, please submit an issue in our [Azure SDK for Java GitHub repo](https://github.com/Azure/azure-sdk-for-java/issues). + +### Features Added +- Create outbound call to an Azure Communication Service user or a phone number. +- Hangup and delete the existing call. +- Play audio in the call. +- Out-call apis for call recording including start, pause, resume stop and get state. +- Subscribe to and receive [DTMF][DTMF] tones via events. +- Add and remove participants from the call. +- Recording download apis. + + +[read_me]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/communication/azure-communication-callautomation/README.md +[DTMF]: https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling diff --git a/sdk/communication/azure-communication-callautomation/README.md b/sdk/communication/azure-communication-callautomation/README.md new file mode 100644 index 0000000000000..d7deda8e9f43a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/README.md @@ -0,0 +1,79 @@ +# Azure Communication CallingServer Service client library for Java + +This package contains a Java SDK for Azure Communication CallingServer Service. Server Test + +[Source code][source] | [Package (Maven)][package] | [API reference documentation][api_documentation] +| [Product documentation][product_docs] + +## Getting started + +### Prerequisites + +- An Azure account with an active subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). +- [Java Development Kit (JDK)](https://docs.microsoft.com/java/azure/jdk/?view=azure-java-stable) version 8 or above. +- [Apache Maven](https://maven.apache.org/download.cgi). +- A deployed Communication Services resource. You can use the [Azure Portal](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource?tabs=windows&pivots=platform-azp) or the [Azure PowerShell](https://docs.microsoft.com/powershell/module/az.communication/new-azcommunicationservice) to set it up. + +### Include the package + +[//]: # ({x-version-update-start;com.azure:azure-communication-callautomation;current}) +```xml + + com.azure + azure-communication-callautomation + 1.0.0-beta.5 + +``` +[//]: # ({x-version-update-end}) + +## Key concepts +This is the restart of CallingServer Service. It is renamed to Call Automation service and being more intuitive to use. + +`CallAutomationClient` provides the functionality to make call, answer/reject incoming call and redirect a call. + +`CallConnection` provides the functionality to perform actions in an established call connection such as adding participants and terminate the call. + +`CallMedia` introduces media related functionalities into the call. + +`CallRecording` provides the functionality of recording the call. + +`EventHandler` provides the functionality to handle events from the ACS resource. + +## Examples + +To be determined. + +## Troubleshooting + +If you recieve a CommunicationErrorException with the messagae: "Action is invalid when call is not in Established state." This usually means the call has ended. This can occur if the participants all leave +the call, or participants did not accept the call before the call timed out. + +If you fail to start a call because of an HMAC validation error, be sure your access key is correct, and +that you are passing in a valid conversation id. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a [Contributor License Agreement (CLA)][cla] declaring that you have the right to, and actually do, grant us the rights to use your contribution. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information see the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or comments. + +## Next steps + +- [Read more about CallingServer Call Automation in Azure Communication Services][call_automation_apis_overview] +- [Read more about CallingServer Call Recording in Azure Communication Services][call_recording_overview] +- For a basic guide on how to record and download calls with Event Grid please refer to the [Record and download calls with Event Grid][record_and_download_calls_with_event_grid]. + + +[cla]: https://cla.microsoft.com +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[coc_contact]: mailto:opencode@microsoft.com +[product_docs]: https://docs.microsoft.com/azure/communication-services/ +[package]: https://dev.azure.com/azure-sdk/public/_artifacts/feed/azure-sdk-for-java-communication-interaction +[api_documentation]: https://aka.ms/java-docs +[call_automation_apis_overview]:https://docs.microsoft.com/azure/communication-services/concepts/voice-video-calling/call-automation-apis +[call_recording_overview]:https://docs.microsoft.com/azure/communication-services/concepts/voice-video-calling/call-recording +[record_and_download_calls_with_event_grid]:https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/download-recording-file-sample +[source]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/communication/azure-communication-callautomation/src diff --git a/sdk/communication/azure-communication-callautomation/ci.yml b/sdk/communication/azure-communication-callautomation/ci.yml new file mode 100644 index 0000000000000..0edef595f5e8e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/ci.yml @@ -0,0 +1,36 @@ +# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. + +trigger: + branches: + include: + - main + - hotfix/* + - release/* + paths: + include: + - sdk/communication/azure-communication-callautomation + exclude: + - sdk/communication/azure-communication-callautomation/pom.xml + +pr: + branches: + include: + - main + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/communication/azure-communication-callautomation/ + exclude: + - sdk/communication/azure-communication-callautomation/pom.xml + +extends: + template: /eng/pipelines/templates/stages/archetype-sdk-client.yml + parameters: + ServiceDirectory: communication + Artifacts: + - name: azure-communication-callautomation + groupId: com.azure + safeName: azurecommunicationcallautomation + diff --git a/sdk/communication/azure-communication-callautomation/pom.xml b/sdk/communication/azure-communication-callautomation/pom.xml new file mode 100644 index 0000000000000..b95231d78dba6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/pom.xml @@ -0,0 +1,175 @@ + + + 4.0.0 + + + com.azure + azure-client-sdk-parent + 1.7.0 + ../../parents/azure-client-sdk-parent + + + com.azure + azure-communication-callautomation + jar + 1.0.0-beta.1 + + Microsoft Azure client library for CallingServer service + + This package contains clients and data structures used to make call with Azure Communication CallingServer Service. + For this release, see notes - https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/communication/azure-communication-callautomation/README.md and https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/communication/azure-communication-callautomation/CHANGELOG.md. + + https://github.com/Azure/azure-sdk-for-java + + + + azure-java-build-docs + ${site.url}/site/${project.artifactId} + + + + + https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + src/main + src/test + 0.75 + 0.65 + false + + + --add-opens com.azure.communication.callautomation/com.azure.communication.callautomation.implementation=ALL-UNNAMED + --add-opens com.azure.communication.common/com.azure.communication.common.implementation=ALL-UNNAMED + + + + + + com.azure + azure-core + 1.32.0 + + + com.azure + azure-communication-common + 1.3.0-beta.2 + + + com.azure + azure-communication-identity + 1.3.0 + test + + + com.azure + azure-core-test + 1.12.0 + test + + + com.nimbusds + nimbus-jose-jwt + 9.22 + test + + + org.junit.jupiter + junit-jupiter-api + 5.8.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.8.2 + test + + + org.junit.jupiter + junit-jupiter-params + 5.8.2 + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + org.mockito + mockito-core + 4.5.1 + test + + + io.projectreactor + reactor-test + 3.4.22 + test + + + com.azure + azure-core-http-okhttp + 1.11.2 + test + + + com.azure + azure-identity + 1.5.4 + test + + + org.jacoco + org.jacoco.agent + runtime + test + 0.8.8 + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.8 + + + com/azure/communication/callautomation/*.class + + + + + coverage-report + verify + + report + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0-M3 + + + + + com.azure:* + + + + + + + + diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationAsyncClient.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationAsyncClient.java new file mode 100644 index 0000000000000..d3a858b4665b0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationAsyncClient.java @@ -0,0 +1,354 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.AzureCommunicationCallAutomationServiceImpl; +import com.azure.communication.callautomation.implementation.CallConnectionsImpl; +import com.azure.communication.callautomation.implementation.ContentsImpl; +import com.azure.communication.callautomation.implementation.ServerCallingsImpl; +import com.azure.communication.callautomation.implementation.ServerCallsImpl; +import com.azure.communication.callautomation.implementation.accesshelpers.CallConnectionPropertiesConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CallSourceInternal; +import com.azure.communication.callautomation.implementation.models.MediaStreamingAudioChannelTypeInternal; +import com.azure.communication.callautomation.implementation.models.MediaStreamingConfigurationInternal; +import com.azure.communication.callautomation.implementation.models.MediaStreamingContentTypeInternal; +import com.azure.communication.callautomation.implementation.models.MediaStreamingTransportTypeInternal; +import com.azure.communication.callautomation.models.AnswerCallResult; +import com.azure.communication.callautomation.models.CallRejectReason; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.callautomation.implementation.models.CreateCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.AnswerCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.RedirectCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.RejectCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.CallRejectReasonInternal; +import com.azure.communication.callautomation.implementation.models.PhoneNumberIdentifierModel; +import com.azure.communication.callautomation.models.CreateCallOptions; +import com.azure.communication.callautomation.models.CreateCallResult; +import com.azure.communication.callautomation.models.MediaStreamingConfiguration; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.publisher.Mono; + + +import java.net.URISyntaxException; +import java.util.List; +import java.util.stream.Collectors; + +import static com.azure.core.util.FluxUtil.monoError; +import static com.azure.core.util.FluxUtil.withContext; + +/** + * Asynchronous client that supports calling server operations. + * + *

Instantiating a asynchronous CallingServer client

+ * + *

View {@link CallAutomationClientBuilder this} for additional ways to construct the client.

+ * + * @see CallAutomationClientBuilder + */ +@ServiceClient(builder = CallAutomationClientBuilder.class, isAsync = true) +public final class CallAutomationAsyncClient { + private final CallConnectionsImpl callConnectionInternal; + private final ServerCallingsImpl serverCallingInternal; + private final ServerCallsImpl serverCallsInternal; + private final ContentsImpl contentsInternal; + private final ClientLogger logger; + private final ContentDownloader contentDownloader; + private final HttpPipeline httpPipelineInternal; + private final String resourceEndpoint; + + CallAutomationAsyncClient(AzureCommunicationCallAutomationServiceImpl callServiceClient) { + this.callConnectionInternal = callServiceClient.getCallConnections(); + this.serverCallingInternal = callServiceClient.getServerCallings(); + this.serverCallsInternal = callServiceClient.getServerCalls(); + this.contentsInternal = callServiceClient.getContents(); + this.logger = new ClientLogger(CallAutomationAsyncClient.class); + this.contentDownloader = new ContentDownloader( + callServiceClient.getEndpoint(), + callServiceClient.getHttpPipeline()); + this.httpPipelineInternal = callServiceClient.getHttpPipeline(); + this.resourceEndpoint = callServiceClient.getEndpoint(); + } + + //region Pre-call Actions + /** + * Create a call connection request from a source identity to a target identity. + * + * @param createCallOptions Options bag for creating a new call. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createCall(CreateCallOptions createCallOptions) { + return createCallWithResponse(createCallOptions).flatMap(FluxUtil::toMono); + } + + /** + * Create a call connection request from a source identity to a target identity. + * + * @param createCallOptions Options bag for creating a new call. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createCallWithResponse(CreateCallOptions createCallOptions) { + return withContext(context -> createCallWithResponseInternal(createCallOptions, context)); + } + + Mono> createCallWithResponseInternal(CreateCallOptions createCallOptions, + Context context) { + try { + context = context == null ? Context.NONE : context; + CreateCallRequestInternal request = getCreateCallRequestInternal(createCallOptions); + + return serverCallingInternal.createCallWithResponseAsync(request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> { + try { + CallConnectionAsync callConnectionAsync = getCallConnectionAsync(response.getValue().getCallConnectionId()); + + return new SimpleResponse<>(response, + new CreateCallResult(CallConnectionPropertiesConstructorProxy.create(response.getValue()), + new CallConnection(callConnectionAsync), callConnectionAsync)); + } catch (URISyntaxException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + private CreateCallRequestInternal getCreateCallRequestInternal(CreateCallOptions createCallOptions) { + List targetsModel = createCallOptions.getTargets() + .stream().map(CommunicationIdentifierConverter::convert).collect(Collectors.toList()); + + CallSourceInternal callSourceDto = new CallSourceInternal().setIdentifier( + CommunicationIdentifierConverter.convert(createCallOptions.getSource())); + if (createCallOptions.getSourceCallerId() != null) { + callSourceDto.setCallerId(new PhoneNumberIdentifierModel().setValue(createCallOptions.getSourceCallerId())); + } + + CreateCallRequestInternal request = new CreateCallRequestInternal() + .setSource(callSourceDto) + .setTargets(targetsModel) + .setCallbackUri(createCallOptions.getCallbackUrl()) + .setSubject(createCallOptions.getSubject()); + + if (createCallOptions.getMediaStreamingConfiguration() != null) { + MediaStreamingConfigurationInternal streamingConfigurationInternal = + getMediaStreamingConfigurationInternal(createCallOptions.getMediaStreamingConfiguration()); + request.setMediaStreamingConfiguration(streamingConfigurationInternal); + } + return request; + } + + private MediaStreamingConfigurationInternal getMediaStreamingConfigurationInternal( + MediaStreamingConfiguration mediaStreamingConfiguration + ) { + return new MediaStreamingConfigurationInternal() + .setTransportUrl(mediaStreamingConfiguration.getTransportUrl()) + .setAudioChannelType( + MediaStreamingAudioChannelTypeInternal.fromString( + mediaStreamingConfiguration.getAudioChannelType().toString())) + .setContentType( + MediaStreamingContentTypeInternal.fromString( + mediaStreamingConfiguration.getContentType().toString())) + .setTransportType( + MediaStreamingTransportTypeInternal.fromString( + mediaStreamingConfiguration.getTransportType().toString())); + } + + /** + * Answer an incoming call + * + * @param incomingCallContext The incoming call context. + * @param callbackUrl The call back url. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono answerCall(String incomingCallContext, String callbackUrl) { + return answerCallWithResponse(incomingCallContext, callbackUrl, null).flatMap(FluxUtil::toMono); + } + + /** + * Create a call connection request from a source identity to a target identity. + * + * @param incomingCallContext The incoming call context. + * @param callbackUrl The call back url. + * @param mediaStreamingConfiguration The MediaStreamingConfiguration. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> answerCallWithResponse(String incomingCallContext, + String callbackUrl, MediaStreamingConfiguration mediaStreamingConfiguration) { + return withContext(context -> answerCallWithResponseInternal(incomingCallContext, callbackUrl, mediaStreamingConfiguration, context)); + } + + Mono> answerCallWithResponseInternal(String incomingCallContext, String callbackUrl, + MediaStreamingConfiguration mediaStreamingConfiguration, + Context context) { + try { + context = context == null ? Context.NONE : context; + + AnswerCallRequestInternal request = new AnswerCallRequestInternal() + .setIncomingCallContext(incomingCallContext) + .setCallbackUri(callbackUrl); + + if (mediaStreamingConfiguration != null) { + MediaStreamingConfigurationInternal mediaStreamingConfigurationInternal = + getMediaStreamingConfigurationInternal(mediaStreamingConfiguration); + + request.setMediaStreamingConfiguration(mediaStreamingConfigurationInternal); + } + + + return serverCallingInternal.answerCallWithResponseAsync(request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> { + try { + CallConnectionAsync callConnectionAsync = getCallConnectionAsync(response.getValue().getCallConnectionId()); + return new SimpleResponse<>(response, + new AnswerCallResult(CallConnectionPropertiesConstructorProxy.create(response.getValue()), + new CallConnection(callConnectionAsync), callConnectionAsync)); + } catch (URISyntaxException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Redirect a call + * + * @param incomingCallContext The incoming call context. + * @param target The target identity. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono redirectCall(String incomingCallContext, CommunicationIdentifier target) { + return redirectCallWithResponse(incomingCallContext, target).flatMap(FluxUtil::toMono); + } + + /** + * Redirect a call + * + * @param incomingCallContext The incoming call context. + * @param target The target identity. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> redirectCallWithResponse(String incomingCallContext, CommunicationIdentifier target) { + return withContext(context -> redirectCallWithResponseInternal(incomingCallContext, target, context)); + } + + Mono> redirectCallWithResponseInternal(String incomingCallContext, CommunicationIdentifier target, + Context context) { + try { + context = context == null ? Context.NONE : context; + + RedirectCallRequestInternal request = new RedirectCallRequestInternal() + .setIncomingCallContext(incomingCallContext) + .setTarget(CommunicationIdentifierConverter.convert(target)); + + return serverCallingInternal.redirectCallWithResponseAsync(request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Reject a call + * + * @param incomingCallContext The incoming call context. + * @param callRejectReason The reason why call is rejected. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono rejectCall(String incomingCallContext, CallRejectReason callRejectReason) { + return rejectCallWithResponse(incomingCallContext, callRejectReason).flatMap(FluxUtil::toMono); + } + + /** + * Reject a call + * + * @param incomingCallContext The incoming call context. + * @param callRejectReason The reason why call is rejected. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> rejectCallWithResponse(String incomingCallContext, CallRejectReason callRejectReason) { + return withContext(context -> rejectCallWithResponseInternal(incomingCallContext, callRejectReason, context)); + } + + Mono> rejectCallWithResponseInternal(String incomingCallContext, CallRejectReason callRejectReason, + Context context) { + try { + context = context == null ? Context.NONE : context; + + RejectCallRequestInternal request = new RejectCallRequestInternal() + .setIncomingCallContext(incomingCallContext) + .setCallRejectReason(CallRejectReasonInternal.fromString(callRejectReason.toString())); + + return serverCallingInternal.rejectCallWithResponseAsync(request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + //endregion + + //region Mid-call Actions + /*** + * Returns an object of CallConnectionAsync + * + * @param callConnectionId the id of the call connection + * @return a CallContentAsync. + */ + public CallConnectionAsync getCallConnectionAsync(String callConnectionId) { + return new CallConnectionAsync(callConnectionId, callConnectionInternal, contentsInternal); + } + //endregion + + //region Content management Actions + /*** + * Returns an object of CallRecordingAsync + * + * @return a CallRecordingAsync. + */ + public CallRecordingAsync getCallRecordingAsync() { + return new CallRecordingAsync(serverCallsInternal, contentsInternal, + contentDownloader, httpPipelineInternal, resourceEndpoint); + } + //endregion +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClient.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClient.java new file mode 100644 index 0000000000000..26abaeefa138d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClient.java @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + + +import com.azure.communication.callautomation.models.AnswerCallResult; +import com.azure.communication.callautomation.models.CallRejectReason; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.CreateCallOptions; +import com.azure.communication.callautomation.models.CreateCallResult; +import com.azure.communication.callautomation.models.MediaStreamingConfiguration; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; + +/** + * Synchronous client that supports calling server operations. + * + *

Instantiating a synchronous Calling Server Client

+ * + *

View {@link CallAutomationClientBuilder this} for additional ways to construct the client.

+ * + * @see CallAutomationClientBuilder + */ +@ServiceClient(builder = CallAutomationClientBuilder.class) +public final class CallAutomationClient { + private final CallAutomationAsyncClient callAutomationAsyncClient; + + CallAutomationClient(CallAutomationAsyncClient callAutomationAsyncClient) { + this.callAutomationAsyncClient = callAutomationAsyncClient; + } + + //region Pre-call Actions + /** + * Create a call connection request from a source identity to a target identity. + * + * @param createCallOptions Options bag for creating a new call. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A CallConnectionDelete object. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CreateCallResult createCall(CreateCallOptions createCallOptions) { + return callAutomationAsyncClient.createCall(createCallOptions).block(); + } + + /** + * Create a call connection request from a source identity to a target identity. + * + * @param createCallOptions Options bag for creating a new call. + * @param context The context to associate with this operation. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createCallWithResponse(CreateCallOptions createCallOptions, Context context) { + return callAutomationAsyncClient.createCallWithResponseInternal(createCallOptions, context).block(); + } + + /** + * Answer an incoming call + * + * @param incomingCallContext The incoming call context. + * @param callbackUrl The call back uri. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public AnswerCallResult answerCall(String incomingCallContext, String callbackUrl) { + return callAutomationAsyncClient.answerCall(incomingCallContext, callbackUrl).block(); + } + + /** + * Create a call connection request from a source identity to a target identity. + * + * @param incomingCallContext The incoming call context. + * @param callbackUrl The call back uri. + * @param mediaStreamingConfiguration The MediaStreamingConfiguration. Optional + * @param context The context to associate with this operation. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response answerCallWithResponse(String incomingCallContext, String callbackUrl, + MediaStreamingConfiguration mediaStreamingConfiguration, + Context context) { + return callAutomationAsyncClient.answerCallWithResponseInternal(incomingCallContext, callbackUrl, mediaStreamingConfiguration, context).block(); + } + + /** + * Redirect a call + * + * @param incomingCallContext The incoming call context. + * @param target The target identity. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Void redirectCall(String incomingCallContext, CommunicationIdentifier target) { + return callAutomationAsyncClient.redirectCall(incomingCallContext, target).block(); + } + + /** + * Redirect a call + * + * @param incomingCallContext The incoming call context. + * @param target The target identity. + * @param context The context to associate with this operation. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response redirectCallWithResponse(String incomingCallContext, CommunicationIdentifier target, Context context) { + return callAutomationAsyncClient.redirectCallWithResponseInternal(incomingCallContext, target, context).block(); + } + + /** + * Reject a call + * + * @param incomingCallContext The incoming call context. + * @param callRejectReason The reason why call is rejected. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Void rejectCall(String incomingCallContext, CallRejectReason callRejectReason) { + return callAutomationAsyncClient.rejectCall(incomingCallContext, callRejectReason).block(); + } + + /** + * Reject a call + * + * @param incomingCallContext The incoming call context. + * @param callRejectReason The reason why call is rejected. Optional + * @param context The context to associate with this operation. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful CreateCallConnection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response rejectCallWithResponse(String incomingCallContext, CallRejectReason callRejectReason, + Context context) { + return callAutomationAsyncClient.rejectCallWithResponseInternal(incomingCallContext, callRejectReason, context).block(); + } + //endregion + + //region Mid-call Actions + /*** + * Returns an object of CallConnection + * + * @param callConnectionId the id of the call connection + * @return a CallConnection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallConnection getCallConnection(String callConnectionId) { + return new CallConnection(callAutomationAsyncClient.getCallConnectionAsync(callConnectionId)); + } + //endregion + + //region Recording Management actions + /*** + * Returns an object of CallRecording + * + * @return a CallRecording. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallRecording getCallRecording() { + return new CallRecording(callAutomationAsyncClient.getCallRecordingAsync()); + } + //endregion +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClientBuilder.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClientBuilder.java new file mode 100644 index 0000000000000..e753e5d84bd41 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallAutomationClientBuilder.java @@ -0,0 +1,480 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.AzureCommunicationCallAutomationServiceImpl; +import com.azure.communication.callautomation.implementation.AzureCommunicationCallAutomationServiceImplBuilder; +import com.azure.communication.callautomation.implementation.CustomHmacAuthenticationPolicy; +import com.azure.communication.common.implementation.CommunicationConnectionString; +import com.azure.communication.common.implementation.HmacAuthenticationPolicy; +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.AzureKeyCredentialTrait; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.ConnectionStringTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.client.traits.TokenCredentialTrait; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.AddHeadersPolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.CookiePolicy; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RedirectPolicy; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.ClientOptions; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.builder.ClientBuilderUtil; +import com.azure.core.util.logging.ClientLogger; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + + +/** + * Client builder that creates CallAutomationAsyncClient and CallAutomationClient. + * + *

Instantiating synchronous and asynchronous Calling Server Clients

+ */ + +@ServiceClientBuilder(serviceClients = { CallAutomationClient.class, CallAutomationAsyncClient.class }) +public final class CallAutomationClientBuilder implements + AzureKeyCredentialTrait, + ConfigurationTrait, + ConnectionStringTrait, + EndpointTrait, + HttpTrait, + TokenCredentialTrait { + private static final String SDK_NAME = "name"; + private static final String SDK_VERSION = "version"; + private static final String APP_CONFIG_PROPERTIES = "azure-communication-callautomation.properties"; + + private final ClientLogger logger = new ClientLogger(CallAutomationClientBuilder.class); + private String connectionString; + private String endpoint; + private String hostName; + private AzureKeyCredential azureKeyCredential; + private TokenCredential tokenCredential; + private HttpClient httpClient; + private HttpLogOptions httpLogOptions = new HttpLogOptions(); + private HttpPipeline pipeline; + private Configuration configuration; + private final Map properties = CoreUtils.getProperties(APP_CONFIG_PROPERTIES); + private final List customPolicies = new ArrayList<>(); + private ClientOptions clientOptions; + private RetryPolicy retryPolicy; + private RetryOptions retryOptions; + + /** + * Public default constructor + */ + public CallAutomationClientBuilder() { + + } + + /** + * Set endpoint of the service. + * + * @param endpoint url of the service. + * @return CallAutomationClientBuilder object. + */ + @Override + public CallAutomationClientBuilder endpoint(String endpoint) { + this.endpoint = Objects.requireNonNull(endpoint, "'endpoint' cannot be null."); + return this; + } + + /** + * Sets the {@link HttpPipeline} to use for the service client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param pipeline {@link HttpPipeline} to use for sending service requests and receiving responses, + * if a pipeline is not supplied, the + * credential and httpClient fields must be set. + * @return CallAutomationClientBuilder object. + */ + @Override + public CallAutomationClientBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = Objects.requireNonNull(pipeline, "'pipeline' cannot be null."); + return this; + } + + /** + * Sets the {@link TokenCredential} used to authorize requests sent to the service. Refer to the Azure SDK for Java + * identity and authentication + * documentation for more details on proper usage of the {@link TokenCredential} type. + * + * @param tokenCredential {@link TokenCredential} used to authorize requests sent to the service. + * @return Updated {@link CallAutomationClientBuilder} object. + * @throws NullPointerException If {@code tokenCredential} is null. + */ + @Override + public CallAutomationClientBuilder credential(TokenCredential tokenCredential) { + this.tokenCredential = Objects.requireNonNull(tokenCredential, "'tokenCredential' cannot be null."); + return this; + } + + /** + * Sets the {@link AzureKeyCredential} used to authenticate HTTP requests. + * + * @param keyCredential The {@link AzureKeyCredential} used to authenticate HTTP + * requests. + * @return Updated {@link CallAutomationClientBuilder} object. + * @throws NullPointerException If {@code keyCredential} is null. + */ + @Override + public CallAutomationClientBuilder credential(AzureKeyCredential keyCredential) { + this.azureKeyCredential = Objects.requireNonNull(keyCredential, "'keyCredential' cannot be null."); + return this; + } + + /** + * Set connectionString to use. + * + * @param connectionString connection string to set. + * @return Updated {@link CallAutomationClientBuilder} object. + */ + @Override + public CallAutomationClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString, "'connectionString' cannot be null."); + this.connectionString = connectionString; + return this; + } + + /** + * Sets the retry policy to use (using the RetryPolicy type). + *

+ * Setting this is mutually exclusive with using {@link #retryOptions(RetryOptions)}. + * + * @param retryPolicy object to be applied + * @return Updated {@link CallAutomationClientBuilder} object. + */ + public CallAutomationClientBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = Objects.requireNonNull(retryPolicy, "'retryPolicy' cannot be null."); + return this; + } + + /** + * Sets the {@link RetryOptions} for all the requests made through the client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ *

+ * Setting this is mutually exclusive with using {@link #retryPolicy(RetryPolicy)}. + * + * @param retryOptions The {@link RetryOptions} to use for all the requests made through the client. + * @return Updated {@link CallAutomationClientBuilder} object. + */ + @Override + public CallAutomationClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * Sets the configuration object used to retrieve environment configuration + * values during building of the client. + * + * @param configuration Configuration store used to retrieve environment + * configurations. + * @return Updated {@link CallAutomationClientBuilder} object. + */ + @Override + public CallAutomationClientBuilder configuration(Configuration configuration) { + this.configuration = Objects.requireNonNull(configuration, "'configuration' cannot be null."); + return this; + } + + /** + * Sets the {@link HttpLogOptions logging configuration} to use when sending and receiving requests to and from + * the service. If a {@code logLevel} is not provided, default value of {@link HttpLogDetailLevel#NONE} is set. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param logOptions The {@link HttpLogOptions logging configuration} to use when sending and receiving requests to + * and from the service. + * @return The updated {@link CallAutomationClientBuilder} object. + */ + @Override + public CallAutomationClientBuilder httpLogOptions(HttpLogOptions logOptions) { + this.httpLogOptions = Objects.requireNonNull(logOptions, "'logOptions' cannot be null."); + return this; + } + + /** + * Sets the {@link CallingServerServiceVersion} that is used when making API requests. + *

+ * If a service version is not provided, the service version that will be used will be the latest known service + * version based on the version of the client library being used. If no service version is specified, updating to a + * newer version of the client library will have the result of potentially moving to a newer service version. + *

+ * Targeting a specific service version may also mean that the service will return an error for newer APIs. + * + * @param version {@link CallingServerServiceVersion} of the service to be used when making requests. + * @return Updated CallAutomationClientBuilder object + */ + public CallAutomationClientBuilder serviceVersion(CallingServerServiceVersion version) { + return this; + } + + /** + * Sets the {@link HttpClient} to use for sending and receiving requests to and from the service. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param httpClient The {@link HttpClient} to use for requests. + * @return Updated {@link CallAutomationClientBuilder} object. + */ + @Override + public CallAutomationClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = Objects.requireNonNull(httpClient, "'httpClient' cannot be null."); + return this; + } + + /** + * Adds a {@link HttpPipelinePolicy pipeline policy} to apply on each request sent. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param customPolicy A {@link HttpPipelinePolicy pipeline policy}. + * @return Updated {@link CallAutomationClientBuilder} object. + * @throws NullPointerException If {@code pipelinePolicy} is {@code null}. + */ + @Override + public CallAutomationClientBuilder addPolicy(HttpPipelinePolicy customPolicy) { + this.customPolicies.add(Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null.")); + return this; + } + + /** + * Create asynchronous client applying HMACAuthenticationPolicy, + * UserAgentPolicy, RetryPolicy, and CookiePolicy. Additional HttpPolicies + * specified by additionalPolicies will be applied after them + * + * @return The updated {@link CallAutomationClientBuilder} object. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. + */ + public CallAutomationAsyncClient buildAsyncClient() { + return new CallAutomationAsyncClient(createServiceImpl()); + } + + /** + * Create synchronous client applying HmacAuthenticationPolicy, UserAgentPolicy, + * RetryPolicy, and CookiePolicy. Additional HttpPolicies specified by + * additionalPolicies will be applied after them. + * + * @return Updated {@link CallAutomationClientBuilder} object. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. + */ + public CallAutomationClient buildClient() { + return new CallAutomationClient(buildAsyncClient()); + } + + private AzureCommunicationCallAutomationServiceImpl createServiceImpl() { + boolean isConnectionStringSet = connectionString != null && !connectionString.trim().isEmpty(); + boolean isEndpointSet = endpoint != null && !endpoint.trim().isEmpty(); + boolean isAzureKeyCredentialSet = azureKeyCredential != null; + boolean isTokenCredentialSet = tokenCredential != null; + boolean isCustomEndpointUsed; + + String customEndpointEnabled = Configuration.getGlobalConfiguration().get("COMMUNICATION_CUSTOM_ENDPOINT_ENABLED", + "false"); + isCustomEndpointUsed = Objects.equals(customEndpointEnabled, "true"); + + if (isConnectionStringSet && isEndpointSet && !isCustomEndpointUsed) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Both 'connectionString' and 'endpoint' are set. Just one may be used.")); + } + + if (((!isConnectionStringSet && !isTokenCredentialSet) || !isEndpointSet) && isCustomEndpointUsed) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Custom Endpoint mode requires 'ConnectionString/TokenCredential' and 'Endpoint' both to be set. Requirement is not fulfilled, changing back to normal mode.")); + } + + if (isConnectionStringSet && isAzureKeyCredentialSet) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Both 'connectionString' and 'keyCredential' are set. Just one may be used.")); + } + + if (isConnectionStringSet && isTokenCredentialSet) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Both 'connectionString' and 'tokenCredential' are set. Just one may be used.")); + } + + if (isAzureKeyCredentialSet && isTokenCredentialSet) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Both 'tokenCredential' and 'keyCredential' are set. Just one may be used.")); + } + + if (isCustomEndpointUsed && !isTokenCredentialSet) { + CommunicationConnectionString connectionStringObject = new CommunicationConnectionString(connectionString); + String accessKey = connectionStringObject.getAccessKey(); + credential(new AzureKeyCredential(accessKey)); + } else if (isConnectionStringSet) { + CommunicationConnectionString connectionStringObject = new CommunicationConnectionString(connectionString); + String endpoint = connectionStringObject.getEndpoint(); + String accessKey = connectionStringObject.getAccessKey(); + endpoint(endpoint).credential(new AzureKeyCredential(accessKey)); + } + + Objects.requireNonNull(endpoint); + if (isTokenCredentialSet) { + try { + hostName = getHostNameFromEndpoint(); + } catch (MalformedURLException e) { + throw logger.logExceptionAsError(new RuntimeException(e.getMessage())); + } + } + + HttpPipeline builderPipeline = pipeline; + if (pipeline == null) { + builderPipeline = createHttpPipeline(httpClient, isCustomEndpointUsed); + } + + AzureCommunicationCallAutomationServiceImplBuilder clientBuilder = new AzureCommunicationCallAutomationServiceImplBuilder(); + clientBuilder.endpoint(endpoint).pipeline(builderPipeline); + + return clientBuilder.buildClient(); + } + + /** + * Allows the user to set a variety of client-related options, such as + * user-agent string, headers, etc. + * + * @param clientOptions object to be applied. + * @return Updated {@link CallAutomationClientBuilder} object. + */ + public CallAutomationClientBuilder clientOptions(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + return this; + } + + private List createHttpPipelineAuthPolicies(boolean isCustomEndpointUsed) throws MalformedURLException { + if (tokenCredential != null && azureKeyCredential != null) { + throw logger.logExceptionAsError(new IllegalArgumentException( + "Both 'credential' and 'keyCredential' are set. Just one may be used.")); + } + + List pipelinePolicies = new ArrayList<>(); + if (tokenCredential != null) { + pipelinePolicies.add(new BearerTokenAuthenticationPolicy(tokenCredential, + "https://communication.azure.com//.default")); + Map httpHeaders = new HashMap<>(); + httpHeaders.put("x-ms-host", hostName); + pipelinePolicies.add(new AddHeadersPolicy(new HttpHeaders(httpHeaders))); + } else if (azureKeyCredential != null) { + if (isCustomEndpointUsed) { + String acsEndpoint = (new CommunicationConnectionString(connectionString)).getEndpoint(); + pipelinePolicies.add(new CustomHmacAuthenticationPolicy(azureKeyCredential, (new URL(acsEndpoint)).getHost())); + } else { + pipelinePolicies.add(new HmacAuthenticationPolicy(azureKeyCredential)); + } + } else { + throw logger.logExceptionAsError( + new IllegalArgumentException("Missing credential information while building a client.")); + } + + return pipelinePolicies; + } + + private HttpPipeline createHttpPipeline(HttpClient httpClient, boolean isCustomEndpointUsed) { + if (pipeline != null) { + return pipeline; + } + + List policyList = new ArrayList<>(); + + ClientOptions buildClientOptions = (clientOptions == null) ? new ClientOptions() : clientOptions; + HttpLogOptions buildLogOptions = (httpLogOptions == null) ? new HttpLogOptions() : httpLogOptions; + + String applicationId = null; + if (!CoreUtils.isNullOrEmpty(buildClientOptions.getApplicationId())) { + applicationId = buildClientOptions.getApplicationId(); + } else if (!CoreUtils.isNullOrEmpty(buildLogOptions.getApplicationId())) { + applicationId = buildLogOptions.getApplicationId(); + } + + // Add required policies + String clientName = properties.getOrDefault(SDK_NAME, "UnknownName"); + String clientVersion = properties.getOrDefault(SDK_VERSION, "UnknownVersion"); + policyList.add(new UserAgentPolicy(applicationId, clientName, clientVersion, configuration)); + policyList.add(new RequestIdPolicy()); + policyList.add(ClientBuilderUtil.validateAndGetRetryPolicy(retryPolicy, retryOptions)); + policyList.add(new RedirectPolicy()); + try { + policyList.addAll(createHttpPipelineAuthPolicies(isCustomEndpointUsed)); + } catch (Exception e) { + throw logger.logExceptionAsError( + new IllegalArgumentException("Invalid ACS Endpoint exception: " + e)); + } + + policyList.add(new CookiePolicy()); + + // Add additional policies + if (!customPolicies.isEmpty()) { + policyList.addAll(customPolicies); + } + + // Add logging policy + policyList.add(new HttpLoggingPolicy(getHttpLogOptions())); + + return new HttpPipelineBuilder().policies(policyList.toArray(new HttpPipelinePolicy[0])).httpClient(httpClient) + .build(); + } + + private HttpLogOptions getHttpLogOptions() { + if (httpLogOptions == null) { + httpLogOptions = new HttpLogOptions(); + } + + return httpLogOptions; + } + + private String getHostNameFromEndpoint() throws MalformedURLException { + return new URL(endpoint).getHost(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnection.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnection.java new file mode 100644 index 0000000000000..aa4c92cb37b44 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnection.java @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallParticipant; +import com.azure.communication.callautomation.models.AddParticipantsOptions; +import com.azure.communication.callautomation.models.AddParticipantsResult; +import com.azure.communication.callautomation.models.CallConnectionProperties; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.ListParticipantsResult; +import com.azure.communication.callautomation.models.RemoveParticipantsResult; +import com.azure.communication.callautomation.models.TransferCallResult; +import com.azure.communication.callautomation.models.TransferToParticipantCallOptions; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; + +import java.util.List; + +/** + * CallConnection for mid-call actions + */ +public class CallConnection { + private final CallConnectionAsync callConnectionAsync; + + CallConnection(CallConnectionAsync callConnectionAsync) { + this.callConnectionAsync = callConnectionAsync; + } + + /** + * Get call connection properties. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallConnectionProperties getCallProperties() { + return callConnectionAsync.getCallProperties().block(); + } + + /** + * Get call connection properties. + * + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getCallPropertiesWithResponse(Context context) { + return callConnectionAsync.getCallPropertiesWithResponseInternal(context).block(); + } + + /** + * Hangup a call. + * + * @param isForEveryone determine if the call is handed up for all participants. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful hangup request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Void hangUp(boolean isForEveryone) { + return callConnectionAsync.hangUp(isForEveryone).block(); + } + + /** + * Hangup a call. + * + * @param isForEveryone determine if the call is handed up for all participants. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful hangup request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response hangUpWithResponse(boolean isForEveryone, Context context) { + return callConnectionAsync.hangUpWithResponseInternal(isForEveryone, context).block(); + } + + /** + * Get a specific participant. + * + * @param participantMri The participant. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallParticipant getParticipant(String participantMri) { + return callConnectionAsync.getParticipant(participantMri).block(); + } + + /** + * Get all participants. + * + * @param participantMri The participant. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getParticipantWithResponse(String participantMri, Context context) { + return callConnectionAsync.getParticipantWithResponseInternal(participantMri, context).block(); + } + + /** + * Get all participants. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public ListParticipantsResult listParticipants() { + return callConnectionAsync.listParticipants().block(); + } + + /** + * Get all participants. + * + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response listParticipantsWithResponse(Context context) { + return callConnectionAsync.listParticipantsWithResponseInternal(context).block(); + } + + /** + * Transfer the call to a participant. + * + * @param transferToParticipantCallOptions Options bag for transferToParticipantCall + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful call termination request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public TransferCallResult transferToParticipantCall(TransferToParticipantCallOptions transferToParticipantCallOptions) { + return callConnectionAsync.transferToParticipantCall(transferToParticipantCallOptions).block(); + } + + /** + * Transfer the call to a participant. + * + * @param transferToParticipantCallOptions Options bag for transferToParticipantCall + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful call termination request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response transferToParticipantCallWithResponse( + TransferToParticipantCallOptions transferToParticipantCallOptions, Context context) { + return callConnectionAsync.transferToParticipantCallWithResponseInternal(transferToParticipantCallOptions, context).block(); + } + + /** + * Add a participant to the call. + * + * @param addParticipantsOptions Options bag for addParticipants + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public AddParticipantsResult addParticipants(AddParticipantsOptions addParticipantsOptions) { + return callConnectionAsync.addParticipants(addParticipantsOptions).block(); + } + + /** + * Add a participant to the call. + * + * @param addParticipantsOptions Options bag for addParticipants + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response addParticipantsWithResponse(AddParticipantsOptions addParticipantsOptions, + Context context) { + return callConnectionAsync.addParticipantsWithResponseInternal(addParticipantsOptions, context).block(); + } + + /** + * Remove a list of participants from the call. + * + * @param participantsToRemove The identifier list of the participant to be removed. + * @param operationContext The operation context. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RemoveParticipantsResult removeParticipants(List participantsToRemove, + String operationContext) { + return callConnectionAsync.removeParticipants(participantsToRemove, operationContext).block(); + } + + /** + * Remove a list of participant from the call. + * + * @param participantsToRemove The identifier list of the participant to be removed. + * @param operationContext The operation context. Optional + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response removeParticipantsWithResponse(List participantsToRemove, + String operationContext, Context context) { + return callConnectionAsync.removeParticipantsWithResponseInternal(participantsToRemove, operationContext, context).block(); + } + + //region Content management Actions + /*** + * Returns an object of CallContent + * + * @return a CallContentAsync. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallMedia getCallMedia() { + return new CallMedia(callConnectionAsync.getCallMediaAsync()); + } + + //endregion +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnectionAsync.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnectionAsync.java new file mode 100644 index 0000000000000..25c1cf961f672 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallConnectionAsync.java @@ -0,0 +1,382 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.CallConnectionsImpl; +import com.azure.communication.callautomation.implementation.ContentsImpl; +import com.azure.communication.callautomation.implementation.accesshelpers.AddParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.CallConnectionPropertiesConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.ListParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.RemoveParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.TransferCallResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CallParticipantConverter; +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.converters.PhoneNumberIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.AddParticipantsRequestInternal; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsRequestInternal; +import com.azure.communication.callautomation.implementation.models.TransferToParticipantRequestInternal; +import com.azure.communication.callautomation.models.AddParticipantsResult; +import com.azure.communication.callautomation.models.CallParticipant; +import com.azure.communication.callautomation.models.AddParticipantsOptions; +import com.azure.communication.callautomation.models.CallConnectionProperties; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.ListParticipantsResult; +import com.azure.communication.callautomation.models.RemoveParticipantsResult; +import com.azure.communication.callautomation.models.TransferCallResult; +import com.azure.communication.callautomation.models.TransferToParticipantCallOptions; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.publisher.Mono; + +import java.net.URISyntaxException; +import java.util.List; +import java.util.stream.Collectors; + +import static com.azure.core.util.FluxUtil.monoError; +import static com.azure.core.util.FluxUtil.withContext; + +/** + * CallConnectionAsync for mid-call actions + */ +public class CallConnectionAsync { + private final String callConnectionId; + private final CallConnectionsImpl callConnectionInternal; + private final ContentsImpl contentsInternal; + private final ClientLogger logger; + + CallConnectionAsync( + String callConnectionId, + CallConnectionsImpl callConnectionInternal, + ContentsImpl contentsInternal) { + this.callConnectionId = callConnectionId; + this.callConnectionInternal = callConnectionInternal; + this.contentsInternal = contentsInternal; + this.logger = new ClientLogger(CallConnectionAsync.class); + } + + /** + * Get call connection properties. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getCallProperties() { + return getCallPropertiesWithResponse().flatMap(FluxUtil::toMono); + } + + /** + * Get call connection properties. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getCallPropertiesWithResponse() { + return withContext(this::getCallPropertiesWithResponseInternal); + } + + Mono> getCallPropertiesWithResponseInternal(Context context) { + try { + context = context == null ? Context.NONE : context; + + return callConnectionInternal.getCallWithResponseAsync(callConnectionId, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> { + try { + return new SimpleResponse<>(response, CallConnectionPropertiesConstructorProxy.create(response.getValue())); + } catch (URISyntaxException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Hangup a call. + * + * @param isForEveryone determine if the call is handed up for all participants. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful hangup request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono hangUp(boolean isForEveryone) { + return hangUpWithResponse(isForEveryone).flatMap(FluxUtil::toMono); + } + + /** + * Hangup a call. + * + * @param isForEveryone determine if the call is handed up for all participants. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful hangup request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> hangUpWithResponse(boolean isForEveryone) { + return withContext(context -> hangUpWithResponseInternal(isForEveryone, context)); + } + + Mono> hangUpWithResponseInternal(boolean isForEveryone, Context context) { + try { + context = context == null ? Context.NONE : context; + + return (isForEveryone ? callConnectionInternal.terminateCallWithResponseAsync(callConnectionId, context) + : callConnectionInternal.hangupCallWithResponseAsync(callConnectionId, context)) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Get a specific participant. + * + * @param participantMri MRI of the participants to retrieve. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getParticipant(String participantMri) { + return getParticipantWithResponse(participantMri).flatMap(FluxUtil::toMono); + } + + /** + * Get a specific participant. + * + * @param participantMri MRI of the participants to retrieve. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getParticipantWithResponse(String participantMri) { + return withContext(context -> getParticipantWithResponseInternal(participantMri, context)); + } + + Mono> getParticipantWithResponseInternal(String participantMri, Context context) { + try { + context = context == null ? Context.NONE : context; + + return callConnectionInternal.getParticipantWithResponseAsync(callConnectionId, participantMri, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> + new SimpleResponse<>(response, CallParticipantConverter.convert(response.getValue()))); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Get all participants. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono listParticipants() { + return listParticipantsWithResponse().flatMap(FluxUtil::toMono); + } + + /** + * Get all participants. + * + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful get call connection request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> listParticipantsWithResponse() { + return withContext(this::listParticipantsWithResponseInternal); + } + + Mono> listParticipantsWithResponseInternal(Context context) { + try { + context = context == null ? Context.NONE : context; + + return callConnectionInternal.getParticipantsWithResponseAsync(callConnectionId, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> new SimpleResponse<>(response, + ListParticipantsResponseConstructorProxy.create(response.getValue()))); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Transfer the call to a participant. + * + * @param transferToParticipantCallOptions Options bag for transferToParticipantCall + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response payload for a successful call termination request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono transferToParticipantCall( + TransferToParticipantCallOptions transferToParticipantCallOptions) { + return transferToParticipantCallWithResponse(transferToParticipantCallOptions).flatMap(FluxUtil::toMono); + } + + /** + * Transfer the call to a participant. + * + * @param transferToParticipantCallOptions Options bag for transferToParticipantCall + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful call termination request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> transferToParticipantCallWithResponse( + TransferToParticipantCallOptions transferToParticipantCallOptions) { + return withContext(context -> transferToParticipantCallWithResponseInternal(transferToParticipantCallOptions, context)); + } + + Mono> transferToParticipantCallWithResponseInternal( + TransferToParticipantCallOptions transferToParticipantCallOptions, Context context) { + try { + context = context == null ? Context.NONE : context; + + TransferToParticipantRequestInternal request = new TransferToParticipantRequestInternal() + .setTargetParticipant(CommunicationIdentifierConverter.convert(transferToParticipantCallOptions.getTargetParticipant())) + .setTransfereeCallerId(PhoneNumberIdentifierConverter.convert(transferToParticipantCallOptions.getTransfereeCallerId())) + .setUserToUserInformation(transferToParticipantCallOptions.getUserToUserInformation()) + .setOperationContext(transferToParticipantCallOptions.getOperationContext()); + + return callConnectionInternal.transferToParticipantWithResponseAsync(callConnectionId, request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> + new SimpleResponse<>(response, TransferCallResponseConstructorProxy.create(response.getValue()))); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Add a participant to the call. + * + * @param addParticipantsOptions Options bag for addParticipants + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono addParticipants(AddParticipantsOptions addParticipantsOptions) { + return addParticipantsWithResponse(addParticipantsOptions).flatMap(FluxUtil::toMono); + } + + /** + * Add a participant to the call. + * + * @param addParticipantsOptions Options bag for addParticipants + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> addParticipantsWithResponse(AddParticipantsOptions addParticipantsOptions) { + return withContext(context -> addParticipantsWithResponseInternal(addParticipantsOptions, context)); + } + + Mono> addParticipantsWithResponseInternal(AddParticipantsOptions addParticipantsOptions, + Context context) { + try { + context = context == null ? Context.NONE : context; + List participantModels = addParticipantsOptions.getParticipants() + .stream().map(CommunicationIdentifierConverter::convert).collect(Collectors.toList()); + + AddParticipantsRequestInternal request = new AddParticipantsRequestInternal() + .setParticipantsToAdd(participantModels) + .setSourceCallerId(PhoneNumberIdentifierConverter.convert(addParticipantsOptions.getSourceCallerId())) + .setOperationContext(addParticipantsOptions.getOperationContext()); + + // Need to do a null check since it is optional; it might be a null and breaks the get function as well as type casting. + if (addParticipantsOptions.getInvitationTimeout() != null) { + request.setInvitationTimeoutInSeconds((int) addParticipantsOptions.getInvitationTimeout().getSeconds()); + } + + return callConnectionInternal.addParticipantWithResponseAsync(callConnectionId, request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> new SimpleResponse<>(response, AddParticipantsResponseConstructorProxy.create(response.getValue()))); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Remove a list of participants from the call. + * + * @param participantsToRemove The identifier list of the participant to be removed. + * @param operationContext The operation context. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono removeParticipants(List participantsToRemove, + String operationContext) { + return removeParticipantsWithResponse(participantsToRemove, operationContext).flatMap(FluxUtil::toMono); + } + + /** + * Remove a list of participants from the call. + * + * @param participantsToRemove The identifier list of the participant to be removed. + * @param operationContext The operation context. Optional + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful add participant request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> removeParticipantsWithResponse(List participantsToRemove, + String operationContext) { + return withContext(context -> removeParticipantsWithResponseInternal(participantsToRemove, operationContext, context)); + } + + Mono> removeParticipantsWithResponseInternal(List participantsToRemove, + String operationContext, Context context) { + try { + context = context == null ? Context.NONE : context; + List participantModels = participantsToRemove + .stream().map(CommunicationIdentifierConverter::convert).collect(Collectors.toList()); + + RemoveParticipantsRequestInternal request = new RemoveParticipantsRequestInternal() + .setParticipantsToRemove(participantModels) + .setOperationContext(operationContext); + + return callConnectionInternal.removeParticipantsWithResponseAsync(callConnectionId, request, context) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> new SimpleResponse<>(response, RemoveParticipantsResponseConstructorProxy.create(response.getValue()))); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + //region Content management Actions + /*** + * Returns an object of CallContentAsync + * + * @return a CallContentAsync. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallMediaAsync getCallMediaAsync() { + return new CallMediaAsync(callConnectionId, contentsInternal); + } + //endregion +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMedia.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMedia.java new file mode 100644 index 0000000000000..373f3aadb4fc1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMedia.java @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.PlayOptions; +import com.azure.communication.callautomation.models.PlaySource; +import com.azure.communication.callautomation.models.RecognizeOptions; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; + +import java.util.Collections; +import java.util.List; + +/** + * CallContent. + */ +public class CallMedia { + private final CallMediaAsync callMediaAsync; + + CallMedia(CallMediaAsync callMediaAsync) { + this.callMediaAsync = callMediaAsync; + } + + /** + * Play + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param playTo the targets to play to. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void play(PlaySource playSource, List playTo) { + callMediaAsync.play(playSource, playTo).block(); + } + + /** + * Play to all participants + * + * @param playSource A {@link PlaySource} representing the source to play. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void playToAll(PlaySource playSource) { + callMediaAsync.playToAll(playSource).block(); + } + + /** + * PlayWithResponse + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param playTo the targets to play to. + * @param options play options. + * @param context A {@link Context} representing the request context. + * @return Response for successful play request. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response playWithResponse(PlaySource playSource, List playTo, + PlayOptions options, Context context) { + return callMediaAsync.playWithResponseInternal(playSource, playTo, options, context).block(); + } + + /** + * PlayAllWithResponse + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param options play options. + * @param context A {@link Context} representing the request context. + * @return Response for successful playAll request. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response playToAllWithResponse(PlaySource playSource, PlayOptions options, Context context) { + return callMediaAsync + .playWithResponseInternal(playSource, Collections.emptyList(), options, context) + .block(); + } + + /** + * Recognize tones. + * @param recognizeOptions Optional elements for recognize. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void recognize(RecognizeOptions recognizeOptions) { + callMediaAsync.recognize(recognizeOptions).block(); + } + + /** + * Recognize tones. + * @param recognizeOptions Optional elements for recognize. + * @param context A {@link Context} representing the request context. + * @return Response for a successful recognize request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response recognizeWithResponse(RecognizeOptions recognizeOptions, Context context) { + return callMediaAsync + .recognizeWithResponseInternal(recognizeOptions, context) + .block(); + } + + /** + * Cancels all the queued media operations. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void cancelAllMediaOperations() { + cancelAllMediaOperationsWithResponse(null); + } + + /** + * Cancels all the queued media operations + * @param context A {@link Context} representing the request context. + * @return Response for successful playAll request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response cancelAllMediaOperationsWithResponse(Context context) { + return callMediaAsync.cancelAllMediaOperationsWithResponseInternal(context).block(); + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMediaAsync.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMediaAsync.java new file mode 100644 index 0000000000000..3cdaa19f0e016 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallMediaAsync.java @@ -0,0 +1,260 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.ContentsImpl; +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.DtmfConfigurationsInternal; +import com.azure.communication.callautomation.implementation.models.FileSourceInternal; +import com.azure.communication.callautomation.implementation.models.PlayOptionsInternal; +import com.azure.communication.callautomation.implementation.models.PlayRequest; +import com.azure.communication.callautomation.implementation.models.PlaySourceInternal; +import com.azure.communication.callautomation.implementation.models.PlaySourceTypeInternal; +import com.azure.communication.callautomation.implementation.models.RecognizeConfigurationsInternal; +import com.azure.communication.callautomation.implementation.models.RecognizeInputTypeInternal; +import com.azure.communication.callautomation.implementation.models.RecognizeRequest; +import com.azure.communication.callautomation.implementation.models.StopTonesInternal; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.DtmfConfigurations; +import com.azure.communication.callautomation.models.FileSource; +import com.azure.communication.callautomation.models.PlayOptions; +import com.azure.communication.callautomation.models.PlaySource; +import com.azure.communication.callautomation.models.RecognizeConfigurations; +import com.azure.communication.callautomation.models.RecognizeOptions; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.publisher.Mono; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static com.azure.core.util.FluxUtil.monoError; +import static com.azure.core.util.FluxUtil.withContext; + +/** + * CallContent. + */ +public class CallMediaAsync { + private final ContentsImpl contentsInternal; + private final String callConnectionId; + private final ClientLogger logger; + + CallMediaAsync(String callConnectionId, ContentsImpl contentsInternal) { + this.callConnectionId = callConnectionId; + this.contentsInternal = contentsInternal; + this.logger = new ClientLogger(CallMediaAsync.class); + } + + /** + * Play + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param playTo the targets to play to + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Void for successful play request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono play(PlaySource playSource, List playTo) { + return playWithResponse(playSource, playTo, null).flatMap(FluxUtil::toMono); + } + + /** + * Play to all participants + * + * @param playSource A {@link PlaySource} representing the source to play. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Void for successful playAll request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono playToAll(PlaySource playSource) { + return playToAllWithResponse(playSource, null).flatMap(FluxUtil::toMono); + } + + /** + * Play + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param playTo the targets to play to + * @param options play options. + * @return Response for successful play request. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> playWithResponse(PlaySource playSource, List playTo, + PlayOptions options) { + return playWithResponseInternal(playSource, playTo, options, null); + } + + /** + * Play to all participants + * + * @param playSource A {@link PlaySource} representing the source to play. + * @param options play options. + * @return Response for successful playAll request. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> playToAllWithResponse(PlaySource playSource, PlayOptions options) { + return playWithResponseInternal(playSource, Collections.emptyList(), options, null); + } + + /** + * Recognize operation. + * @param recognizeOptions Different attributes for recognize. + * @return Response for successful recognize request. + */ + public Mono recognize(RecognizeOptions recognizeOptions) { + return recognizeWithResponse(recognizeOptions).then(); + } + + /** + * Recognize operation + * @param recognizeOptions Different attributes for recognize. + * @return Response for successful recognize request. + */ + public Mono> recognizeWithResponse(RecognizeOptions recognizeOptions) { + return withContext(context -> recognizeWithResponseInternal(recognizeOptions, context)); + } + + Mono> recognizeWithResponseInternal(RecognizeOptions recognizeOptions, Context context) { + try { + context = context == null ? Context.NONE : context; + + RecognizeConfigurations recognizeConfigurations = recognizeOptions.getRecognizeConfiguration(); + DtmfConfigurationsInternal dtmfConfigurationsInternal = null; + if (recognizeConfigurations.getDtmfConfigurations() != null) { + DtmfConfigurations dtmfConfigurations = recognizeConfigurations.getDtmfConfigurations(); + dtmfConfigurationsInternal = new DtmfConfigurationsInternal() + .setMaxTonesToCollect(dtmfConfigurations.getMaxTonesToCollect()); + + if (dtmfConfigurations.getInterToneTimeoutInSeconds() != null) { + dtmfConfigurationsInternal.setInterToneTimeoutInSeconds((int) dtmfConfigurations.getInterToneTimeoutInSeconds().getSeconds()); + } + if (dtmfConfigurations.getStopTones() != null) { + dtmfConfigurationsInternal + .setStopTones(dtmfConfigurations.getStopTones().stream() + .map(stopTones -> StopTonesInternal.fromString(stopTones.toString())) + .collect(Collectors.toList())); + + } + } + RecognizeConfigurationsInternal recognizeConfigurationsInternal = new RecognizeConfigurationsInternal() + .setDtmfConfigurations(dtmfConfigurationsInternal) + .setInterruptPromptAndStartRecognition(recognizeConfigurations.isInterruptPromptAndStartRecognition()) + .setTargetParticipant(CommunicationIdentifierConverter.convert(recognizeConfigurations.getTargetParticipant())); + if (recognizeConfigurations.getInitialSilenceTimeoutInSeconds() != null) { + recognizeConfigurationsInternal.setInitialSilenceTimeoutInSeconds((int) recognizeConfigurations.getInitialSilenceTimeoutInSeconds().getSeconds()); + } + + PlaySourceInternal playSourceInternal = null; + if (recognizeOptions.getPlayPrompt() != null) { + PlaySource playSource = recognizeOptions.getPlayPrompt(); + if (playSource instanceof FileSource) { + playSourceInternal = getPlaySourceInternal((FileSource) playSource); + } + } + RecognizeRequest recognizeRequest = new RecognizeRequest() + .setRecognizeInputType(RecognizeInputTypeInternal.fromString(recognizeOptions.getRecognizeInputType().toString())) + .setRecognizeConfiguration(recognizeConfigurationsInternal) + .setStopCurrentOperations(recognizeOptions.isStopCurrentOperations()) + .setPlayPrompt(playSourceInternal) + .setOperationContext(recognizeOptions.getOperationContext()); + + return contentsInternal.recognizeWithResponseAsync(callConnectionId, recognizeRequest, context); + + } catch (RuntimeException e) { + return monoError(logger, e); + } + } + + /** + * Cancels all the queued media operations. + * @return Void + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono cancelAllMediaOperations() { + return cancelAllMediaOperationsWithResponse().then(); + } + + /** + * Cancels all the queued media operations + * @return Response for successful playAll request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> cancelAllMediaOperationsWithResponse() { + return cancelAllMediaOperationsWithResponseInternal(null); + } + + Mono> cancelAllMediaOperationsWithResponseInternal(Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return contentsInternal.cancelAllMediaOperationsWithResponseAsync(callConnectionId, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + }); + + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + Mono> playWithResponseInternal(PlaySource playSource, List playTo, + PlayOptions options, Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + PlayRequest request = getPlayRequest(playSource, playTo, options); + return contentsInternal.playWithResponseAsync(callConnectionId, request, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + }); + + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + PlayRequest getPlayRequest(PlaySource playSource, List playTo, PlayOptions options) { + if (playSource instanceof FileSource) { + PlaySourceInternal playSourceInternal = getPlaySourceInternal((FileSource) playSource); + + PlayRequest request = new PlayRequest() + .setPlaySourceInfo(playSourceInternal) + .setPlayTo( + playTo + .stream() + .map(CommunicationIdentifierConverter::convert) + .collect(Collectors.toList())); + + if (options != null) { + request.setPlayOptions(new PlayOptionsInternal().setLoop(options.isLoop())); + request.setOperationContext(options.getOperationContext()); + } + + return request; + } + + throw logger.logExceptionAsError(new IllegalArgumentException(playSource.getClass().getCanonicalName())); + } + + private PlaySourceInternal getPlaySourceInternal(FileSource fileSource) { + FileSourceInternal fileSourceInternal = new FileSourceInternal().setUri(fileSource.getUri()); + PlaySourceInternal playSourceInternal = new PlaySourceInternal() + .setSourceType(PlaySourceTypeInternal.FILE) + .setFileSource(fileSourceInternal) + .setPlaySourceId(fileSource.getPlaySourceId()); + return playSourceInternal; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecording.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecording.java new file mode 100644 index 0000000000000..2886c8f87bc0b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecording.java @@ -0,0 +1,284 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.DownloadToFileOptions; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.http.HttpRange; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import com.azure.core.util.Context; + +import java.io.OutputStream; +import java.nio.file.Path; +import java.security.InvalidParameterException; +import java.util.Objects; + +/** + * CallRecording. + */ +public class CallRecording { + private final CallRecordingAsync callRecordingAsync; + + CallRecording(CallRecordingAsync callRecordingAsync) { + this.callRecordingAsync = callRecordingAsync; + } + + /** + * Start recording of the call. + * + * @param options A {@link StartRecordingOptions} object containing different options for recording. + * @throws InvalidParameterException is recordingStateCallbackUri is absolute uri. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Result for a successful start recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RecordingStateResult startRecording(StartRecordingOptions options) { + return callRecordingAsync.startRecording(options).block(); + } + + /** + * Start recording of the call. + * + * @param options A {@link StartRecordingOptions} object containing different options for recording. + * @param context A {@link Context} representing the request context. + * @throws InvalidParameterException is recordingStateCallbackUri is absolute uri. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Result for a successful start recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response startRecordingWithResponse(StartRecordingOptions options, Context context) { + return callRecordingAsync.startRecordingWithResponseInternal(options, context).block(); + } + + /** + * Stop recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void stopRecording(String recordingId) { + callRecordingAsync.stopRecording(recordingId).block(); + } + + /** + * Stop recording of the call. + * + * @param recordingId Recording id to stop. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful stop recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response stopRecordingWithResponse(String recordingId, Context context) { + return callRecordingAsync.stopRecordingWithResponseInternal(recordingId, context).block(); + } + + /** + * Pause recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void pauseRecording(String recordingId) { + callRecordingAsync.pauseRecording(recordingId).block(); + } + + /** + * Pause recording of the call. + * + * @param recordingId Recording id to stop. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful pause recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pauseRecordingWithResponse(String recordingId, Context context) { + return callRecordingAsync.pauseRecordingWithResponseInternal(recordingId, context).block(); + } + + /** + * Resume recording of the call. + * + * @param recordingId The recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void resumeRecording(String recordingId) { + callRecordingAsync.resumeRecording(recordingId).block(); + } + + /** + * Resume recording of the call. + * + * @param recordingId The recording id to stop. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful resume recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response resumeRecordingWithResponse(String recordingId, final Context context) { + return callRecordingAsync.resumeRecordingWithResponseInternal(recordingId, context).block(); + } + + /** + * Get the current recording state by recording id. + * + * @param recordingId The recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful get recording state request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RecordingStateResult getRecordingState(String recordingId) { + return callRecordingAsync.getRecordingState(recordingId).block(); + } + + /** + * Get the current recording state by recording id. + * + * @param recordingId The recording id to stop. + * @param context A {@link Context} representing the request context. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful get recording state request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRecordingStateWithResponse(String recordingId, Context context) { + return callRecordingAsync.getRecordingStateWithResponseInternal(recordingId, context).block(); + } + + /** + * Download the recording content, e.g. Recording's metadata, Recording video, etc., from + * {@code endpoint} and write it in the {@link OutputStream} passed as parameter. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationStream - A stream where to write the downloaded content. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void downloadTo(String sourceEndpoint, OutputStream destinationStream) { + downloadToWithResponse(sourceEndpoint, destinationStream, null, null); + } + + /** + * Download the recording content, e.g. Recording's metadata, Recording video, etc., from + * {@code endpoint} and write it in the {@link OutputStream} passed as parameter. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationStream - A stream where to write the downloaded content. + * @param httpRange - An optional {@link HttpRange} value containing the range of bytes to download. If missing, + * the whole content will be downloaded. + * @param context A {@link Context} representing the request context. + * @return Response containing the http response information from the download. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response downloadToWithResponse(String sourceEndpoint, + OutputStream destinationStream, + HttpRange httpRange, + Context context) { + Objects.requireNonNull(sourceEndpoint, "'sourceEndpoint' cannot be null"); + Objects.requireNonNull(destinationStream, "'destinationStream' cannot be null"); + return callRecordingAsync + .downloadToWithResponse(sourceEndpoint, destinationStream, httpRange, context) + .block(); + } + + /** + * Downloads the entire content. + *

This method supports downloads up to 2GB of data. + * Use {@link #downloadTo(String, OutputStream)} to download larger blobs.

+ * + * @param sourceEndpoint - ACS URL where the content is located. + * @return The content of the blob. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public BinaryData downloadContent(String sourceEndpoint) { + return callRecordingAsync.downloadContent(sourceEndpoint).block(); + } + + /** + * Downloads the entire content. + *

This method supports downloads up to 2GB of data. + * Use {@link #downloadToWithResponse(String, OutputStream, HttpRange, Context)} to download larger blobs.

+ * + * @param sourceEndpoint ACS URL where the content is located. + * @param range An optional {@link HttpRange} value containing the range of bytes to download. If missing, + * the whole content will be downloaded. + * @param context A {@link Context} representing the request context. + * @return The content of the blob. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response downloadContentWithResponse(String sourceEndpoint, HttpRange range, Context context) { + return callRecordingAsync.downloadContentWithResponseInternal(sourceEndpoint, range, context).block(); + } + + /** + * Download the content located in {@code endpoint} into a file marked by {@code path}. + * This download will be done using parallel workers. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationPath - File location. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void downloadTo(String sourceEndpoint, + Path destinationPath) { + DownloadToFileOptions options = new DownloadToFileOptions(); + downloadToWithResponse(sourceEndpoint, destinationPath, options, null); + } + + /** + * Download the content located in {@code endpoint} into a file marked by {@code path}. + * This download will be done using parallel workers. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationPath - File location. + * @param options - an optional {@link DownloadToFileOptions} object to modify how the + * download will work. + * @param context A {@link Context} representing the request context. + * @return Response containing the http response information from the download. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response downloadToWithResponse(String sourceEndpoint, + Path destinationPath, + DownloadToFileOptions options, + final Context context) { + Objects.requireNonNull(sourceEndpoint, "'sourceEndpoint' cannot be null"); + Objects.requireNonNull(destinationPath, "'destinationPath' cannot be null"); + return callRecordingAsync.downloadToWithResponseInternal(sourceEndpoint, destinationPath, + options, context).block(); + } + + /** + * Delete the content located in the deleteEndpoint + * + * @param deleteEndpoint - ACS URL where the content is located. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRecording(String deleteEndpoint) { + deleteRecordingWithResponse(deleteEndpoint, null); + } + + /** + * Delete the content located in the deleteEndpoint + * + * @param deleteEndpoint - ACS URL where the content is located. + * @param context A {@link Context} representing the request context. + * @return Response for successful delete request.. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRecordingWithResponse(String deleteEndpoint, Context context) { + return callRecordingAsync.deleteRecordingWithResponseInternal(deleteEndpoint, context).block(); + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecordingAsync.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecordingAsync.java new file mode 100644 index 0000000000000..51989c18e90b1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallRecordingAsync.java @@ -0,0 +1,571 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.ContentsImpl; +import com.azure.communication.callautomation.implementation.ServerCallsImpl; +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.implementation.accesshelpers.RecordingStateResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CallLocatorInternal; +import com.azure.communication.callautomation.implementation.models.CallLocatorKindInternal; +import com.azure.communication.callautomation.implementation.models.ChannelAffinityInternal; +import com.azure.communication.callautomation.implementation.models.RecordingContentInternal; +import com.azure.communication.callautomation.implementation.models.RecordingFormatInternal; +import com.azure.communication.callautomation.implementation.models.RecordingChannelInternal; +import com.azure.communication.callautomation.implementation.models.StartCallRecordingRequestInternal; +import com.azure.communication.callautomation.models.CallLocator; +import com.azure.communication.callautomation.models.CallLocatorKind; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.DownloadToFileOptions; +import com.azure.communication.callautomation.models.GroupCallLocator; +import com.azure.communication.callautomation.models.ParallelDownloadOptions; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.ServerCallLocator; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpRange; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.BinaryData; +import com.azure.core.util.Context; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.InvalidParameterException; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.azure.core.util.FluxUtil.monoError; +import static com.azure.core.util.FluxUtil.withContext; + +/** + * CallRecordingAsync. + */ +public class CallRecordingAsync { + private final ServerCallsImpl serverCallsInternal; + private final ContentsImpl contentsInternal; + private final ClientLogger logger; + private final ContentDownloader contentDownloader; + private final HttpPipeline httpPipelineInternal; + private final String resourceEndpoint; + + CallRecordingAsync(ServerCallsImpl serverCallsInternal, ContentsImpl contentsInternal, + ContentDownloader contentDownloader, HttpPipeline httpPipelineInternal, String resourceEndpoint) { + this.serverCallsInternal = serverCallsInternal; + this.contentsInternal = contentsInternal; + this.contentDownloader = contentDownloader; + this.httpPipelineInternal = httpPipelineInternal; + this.resourceEndpoint = resourceEndpoint; + this.logger = new ClientLogger(CallRecordingAsync.class); + } + + /** + * Start recording of the call. + * + * @param options A {@link StartRecordingOptions} object containing different options for recording. + * @throws InvalidParameterException is recordingStateCallbackUri is absolute uri. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful start recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono startRecording(StartRecordingOptions options) { + return startRecordingWithResponse(options) + .flatMap(response -> Mono.just(response.getValue())); + } + + /** + * Start recording of the call. + * + * @param options A {@link StartRecordingOptions} object containing different options for recording. + * @throws InvalidParameterException is recordingStateCallbackUri is absolute uri. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful start recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> startRecordingWithResponse(StartRecordingOptions options) { + Objects.requireNonNull(options, "'options' cannot be null."); + + return startRecordingWithResponseInternal(options, null); + } + + Mono> startRecordingWithResponseInternal(StartRecordingOptions options, Context context) { + try { + String callbackUrl = options.getRecordingStateCallbackUrl(); + if (callbackUrl != null && !callbackUrl.isEmpty() && !Boolean.TRUE.equals(new URI(callbackUrl).isAbsolute())) { + throw logger.logExceptionAsError(new InvalidParameterException("'recordingStateCallbackUri' has to be an absolute Uri")); + } + StartCallRecordingRequestInternal request = getStartCallRecordingRequest(options); + + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return contentsInternal + .recordingWithResponseAsync(request, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> + new SimpleResponse<>(response, RecordingStateResponseConstructorProxy.create(response.getValue())) + ); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } catch (URISyntaxException ex) { + return monoError(logger, new RuntimeException(ex)); + } + } + + private StartCallRecordingRequestInternal getStartCallRecordingRequest(StartRecordingOptions options) { + CallLocator callLocator = options.getCallLocator(); + CallLocatorInternal callLocatorInternal = new CallLocatorInternal() + .setKind(CallLocatorKindInternal.fromString(callLocator.getKind().toString())); + + if (callLocator.getKind() == CallLocatorKind.GROUP_CALL_LOCATOR) { + callLocatorInternal.setGroupCallId(((GroupCallLocator) callLocator).getGroupCallId()); + } else if (callLocator.getKind() == CallLocatorKind.SERVER_CALL_LOCATOR) { + callLocatorInternal.setServerCallId(((ServerCallLocator) callLocator).getServerCallId()); + } else { + throw logger.logExceptionAsError(new InvalidParameterException("callLocator has invalid kind.")); + } + + StartCallRecordingRequestInternal request = new StartCallRecordingRequestInternal() + .setCallLocator(callLocatorInternal); + + if (options.getRecordingContent() != null) { + request.setRecordingContentType(RecordingContentInternal.fromString(options.getRecordingContent().toString())); + } + if (options.getRecordingFormat() != null) { + request.setRecordingFormatType(RecordingFormatInternal.fromString(options.getRecordingFormat().toString())); + } + if (options.getRecordingChannel() != null) { + request.setRecordingChannelType(RecordingChannelInternal.fromString(options.getRecordingChannel().toString())); + } + if (options.getRecordingStateCallbackUrl() != null) { + request.setRecordingStateCallbackUri(options.getRecordingStateCallbackUrl()); + } + if (options.getChannelAffinity() != null) { + List channelAffinityInternal = options.getChannelAffinity() + .stream() + .map(c -> new ChannelAffinityInternal() + .setChannel(c.getChannel()) + .setParticipant(CommunicationIdentifierConverter.convert(c.getParticipant()))) + .collect(Collectors.toList()); + request.setChannelAffinity(channelAffinityInternal); + } + + return request; + } + + /** + * Stop recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful stop recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono stopRecording(String recordingId) { + return stopRecordingWithResponse(recordingId).then(); + } + + /** + * Stop recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful stop recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> stopRecordingWithResponse(String recordingId) { + return stopRecordingWithResponseInternal(recordingId, null); + } + + Mono> stopRecordingWithResponseInternal(String recordingId, Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return serverCallsInternal + .stopRecordingWithResponseAsync(recordingId, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Pause recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful pause recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono pauseRecording(String recordingId) { + return pauseRecordingWithResponse(recordingId).then(); + } + + /** + * Pause recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful pause recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> pauseRecordingWithResponse(String recordingId) { + return pauseRecordingWithResponseInternal(recordingId, null); + } + + Mono> pauseRecordingWithResponseInternal(String recordingId, Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return serverCallsInternal + .pauseRecordingWithResponseAsync(recordingId, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Resume recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return response for a successful resume recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono resumeRecording(String recordingId) { + return resumeRecordingWithResponse(recordingId).then(); + } + + /** + * Resume recording of the call. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return response for a successful resume recording request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> resumeRecordingWithResponse(String recordingId) { + return resumeRecordingWithResponseInternal(recordingId, null); + } + + Mono> resumeRecordingWithResponseInternal(String recordingId, Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return serverCallsInternal + .resumeRecordingWithResponseAsync(recordingId, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Get current recording state by recording id. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful get recording state request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getRecordingState(String recordingId) { + return getRecordingStateWithResponse(recordingId).flatMap(response -> Mono.just(response.getValue())); + } + + /** + * Get current recording state by recording id. + * + * @param recordingId Recording id to stop. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for a successful get recording state request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRecordingStateWithResponse(String recordingId) { + return getRecordingStateWithResponseInternal(recordingId, null); + } + + Mono> getRecordingStateWithResponseInternal(String recordingId, Context context) { + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return serverCallsInternal + .getRecordingPropertiesWithResponseAsync(recordingId, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> + new SimpleResponse<>(response, RecordingStateResponseConstructorProxy.create(response.getValue()))); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Download the recording content, e.g. Recording's metadata, Recording video, from the ACS endpoint + * passed as parameter. + * @param sourceEndpoint - URL where the content is located. + * @return A {@link Flux} object containing the byte stream of the content requested. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public Flux downloadStream(String sourceEndpoint) { + return downloadStreamWithResponse(sourceEndpoint, null) + .map(Response::getValue) + .flux() + .flatMap(flux -> flux); + } + + /** + * Download the recording content, (e.g. Recording's metadata, Recording video, etc.) from the {@code endpoint}. + * @param sourceEndpoint - URL where the content is located. + * @param range - An optional {@link HttpRange} value containing the range of bytes to download. If missing, + * the whole content will be downloaded. + * @return A {@link Mono} object containing a {@link Response} with the byte stream of the content requested. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono>> downloadStreamWithResponse(String sourceEndpoint, HttpRange range) { + return downloadStreamWithResponseInternal(sourceEndpoint, range, null); + } + + Mono>> downloadStreamWithResponseInternal(String sourceEndpoint, HttpRange range, Context context) { + try { + Objects.requireNonNull(sourceEndpoint, "'sourceEndpoint' cannot be null"); + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return contentDownloader.downloadStreamWithResponse(sourceEndpoint, range, contextValue); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Reads the entire content. + * + *

Code Samples

+ * + *

This method supports downloads up to 2GB of data. + * Use {@link #downloadStream(String)} ()} to download larger blobs.

+ * + * @param sourceEndpoint - URL where the content is located. + * @return A reactive response containing the content data. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono downloadContent(String sourceEndpoint) { + return downloadStreamWithResponse(sourceEndpoint, null) + .flatMap(response -> BinaryData.fromFlux(response.getValue())); + } + + /** + * Reads a range of bytes from a content. + * + *

This method supports downloads up to 2GB of data. + * Use {@link #downloadStreamWithResponse(String, HttpRange)} + * to download larger blobs.

+ * + * @param sourceEndpoint - URL where the content is located. + * @param range - An optional {@link HttpRange} value containing the range of bytes to download. If missing, + * the whole content will be downloaded. + * @return A reactive response containing the blob data. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> downloadContentWithResponse(String sourceEndpoint, HttpRange range) { + return downloadContentWithResponseInternal(sourceEndpoint, range, null); + } + + Mono> downloadContentWithResponseInternal(String sourceEndpoint, HttpRange range, Context context) { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return downloadStreamWithResponseInternal(sourceEndpoint, range, contextValue) + .flatMap(response -> BinaryData.fromFlux(response.getValue()) + .map(data -> new SimpleResponse<>(response.getRequest(), response.getStatusCode(), + response.getHeaders(), data))); + }); + } + + /** + * Download the content located in {@code endpoint} into a file marked by {@code path}. + * This download will be done using parallel workers. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationPath - File location. + * @return Response for a successful downloadTo request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono downloadTo( + String sourceEndpoint, + Path destinationPath) { + try { + DownloadToFileOptions options = new DownloadToFileOptions(); + return downloadToWithResponse(sourceEndpoint, destinationPath, options).then(); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Download the content located in {@code endpoint} into a file marked by {@code path}. + * This download will be done using parallel workers. + * @param sourceEndpoint - ACS URL where the content is located. + * @param destinationPath - File location. + * @param options - an optional {@link DownloadToFileOptions} object to modify how the + * download will work. + * @return Response containing the http response information from the download. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> downloadToWithResponse( + String sourceEndpoint, + Path destinationPath, + DownloadToFileOptions options) { + return downloadToWithResponseInternal(sourceEndpoint, destinationPath, options, null); + } + + Mono> downloadToWithResponseInternal( + String sourceEndpoint, + Path destinationPath, + DownloadToFileOptions options, + Context context) { + Objects.requireNonNull(sourceEndpoint, "'sourceEndpoint' cannot be null"); + Objects.requireNonNull(destinationPath, "'destinationPath' cannot be null"); + + Set openOptions = new HashSet<>(); + + if (options.isOverwrite()) { + openOptions.add(StandardOpenOption.CREATE); + } else { + openOptions.add(StandardOpenOption.CREATE_NEW); + } + openOptions.add(StandardOpenOption.WRITE); + + try { + AsynchronousFileChannel file = AsynchronousFileChannel.open(destinationPath, openOptions, null); + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + return downloadToWithResponse(sourceEndpoint, destinationPath, file, options, contextValue); + }); + } catch (IOException ex) { + return monoError(logger, new RuntimeException(ex)); + } + } + + Mono> downloadToWithResponse( + String sourceEndpoint, + OutputStream destinationStream, + HttpRange httpRange, + Context context) { + + return contentDownloader.downloadToStreamWithResponse(sourceEndpoint, destinationStream, httpRange, context); + } + + Mono> downloadToWithResponse( + String sourceEndpoint, + Path destinationPath, + AsynchronousFileChannel fileChannel, + DownloadToFileOptions options, + Context context + ) { + ParallelDownloadOptions finalParallelDownloadOptions = + options.getParallelDownloadOptions() == null + ? new ParallelDownloadOptions() + : options.getParallelDownloadOptions(); + + return Mono.just(fileChannel).flatMap( + c -> contentDownloader.downloadToFileWithResponse(sourceEndpoint, c, finalParallelDownloadOptions, context)) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .doFinally(signalType -> contentDownloader.downloadToFileCleanup(fileChannel, destinationPath, signalType)); + } + + /** + * Delete the content located at the deleteEndpoint + * @param deleteEndpoint - ACS URL where the content is located. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return Response for successful delete request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRecording(String deleteEndpoint) { + try { + return deleteRecordingWithResponseInternal(deleteEndpoint, null) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .then(); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + /** + * Delete the content located at the deleteEndpoint + * Recording deletion will be done using parallel workers. + * @param deleteEndpoint - ACS URL where the content is located. + * @throws CallingServerErrorException thrown if the request is rejected by server. + * @return Response for successful delete request. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRecordingWithResponse(String deleteEndpoint) { + return deleteRecordingWithResponseInternal(deleteEndpoint, null); + } + + Mono> deleteRecordingWithResponseInternal(String deleteEndpoint, Context context) { + HttpRequest request = new HttpRequest(HttpMethod.DELETE, deleteEndpoint); + URL urlToSignWith = getUrlToSignRequestWith(deleteEndpoint); + try { + return withContext(contextValue -> { + contextValue = context == null ? contextValue : context; + contextValue = contextValue.addData("hmacSignatureURL", urlToSignWith); + return httpPipelineInternal + .send(request, contextValue) + .onErrorMap(HttpResponseException.class, ErrorConstructorProxy::create) + .map(response -> new SimpleResponse<>(response.getRequest(), response.getStatusCode(), response.getHeaders(), null)); + }); + } catch (RuntimeException ex) { + return monoError(logger, ex); + } + } + + private URL getUrlToSignRequestWith(String endpoint) { + try { + String path = new URL(endpoint).getPath(); + + if (path.startsWith("/")) { + path = path.substring(1); + } + + return new URL(resourceEndpoint + path); + } catch (MalformedURLException ex) { + throw logger.logExceptionAsError(new IllegalArgumentException(ex)); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallingServerServiceVersion.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallingServerServiceVersion.java new file mode 100644 index 0000000000000..1d8a42397f9b0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/CallingServerServiceVersion.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.core.util.ServiceVersion; + +/** + * Versions of CallingServer service supported by this client library. + */ +public enum CallingServerServiceVersion implements ServiceVersion { + /** + * Service version {@code 2022-04-07-preview}. + */ + V2022_04_07_PREVIEW("2022-04-07-preview"), + /** + * Service version {@code 2021-11-15-preview}. + */ + V2021_11_15_PREVIEW("2021-11-15-preview"); + + private final String version; + + CallingServerServiceVersion(String version) { + this.version = version; + } + + /** + * {@inheritDoc} + */ + @Override + public String getVersion() { + return this.version; + } + + /** + * Gets the latest service version supported by this client library + * + * @return The latest {@link CallingServerServiceVersion} object. + */ + public static CallingServerServiceVersion getLatest() { + return V2022_04_07_PREVIEW; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/ContentDownloader.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/ContentDownloader.java new file mode 100644 index 0000000000000..9b82a58660461 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/ContentDownloader.java @@ -0,0 +1,300 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.Constants; +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.ParallelDownloadOptions; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpMethod; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpRange; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.SimpleResponse; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.core.util.ProgressListener; +import com.azure.core.util.ProgressReporter; +import com.azure.core.util.logging.ClientLogger; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.publisher.SignalType; +import reactor.core.scheduler.Schedulers; +import reactor.util.function.Tuple2; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.function.Function; + +import static java.lang.StrictMath.toIntExact; + +class ContentDownloader { + private final String resourceEndpoint; + private final HttpPipeline httpPipeline; + private final ClientLogger logger = new ClientLogger(ContentDownloader.class); + + ContentDownloader(String resourceEndpoint, HttpPipeline httpPipeline) { + this.resourceEndpoint = resourceEndpoint; + this.httpPipeline = httpPipeline; + } + + Mono> downloadToStreamWithResponse( + String sourceEndpoint, + OutputStream destinationStream, + HttpRange httpRange, + Context context) { + return downloadStreamWithResponse(sourceEndpoint, httpRange, context) + .flatMap(response -> FluxUtil.writeToOutputStream(response.getValue(), destinationStream) + .thenReturn(new SimpleResponse<>(response.getRequest(), response.getStatusCode(), + response.getHeaders(), null))); + } + + Mono>> downloadStreamWithResponse( + String sourceEndpoint, + HttpRange httpRange, + Context context) { + Mono httpResponse = makeDownloadRequest(sourceEndpoint, httpRange, context); + return httpResponse.map(response -> { + Flux result = getFluxStream(response, sourceEndpoint, httpRange, context); + return new SimpleResponse<>(response.getRequest(), response.getStatusCode(), + response.getHeaders(), result); + }); + } + + Mono> downloadToFileWithResponse( + String sourceEndpoint, + AsynchronousFileChannel destinationFile, + ParallelDownloadOptions parallelDownloadOptions, + Context context) { + + Function>>> downloadFunc = + range -> downloadStreamWithResponse(sourceEndpoint, range, context); + + return downloadFirstChunk(parallelDownloadOptions, downloadFunc) + .flatMap(setupTuple2 -> { + long newCount = setupTuple2.getT1(); + int numChunks = calculateNumBlocks(newCount, parallelDownloadOptions.getBlockSize()); + + // In case it is an empty blob, this ensures we still actually perform a download operation. + numChunks = numChunks == 0 ? 1 : numChunks; + + Response> initialResponse = setupTuple2.getT2(); + ProgressListener progressListener = parallelDownloadOptions.getProgressListener(); + ProgressReporter progressReporter = + progressListener == null + ? null + : ProgressReporter.withProgressListener(progressListener); + return Flux.range(0, numChunks) + .flatMap(chunkNum -> downloadChunk(chunkNum, initialResponse, + parallelDownloadOptions, newCount, downloadFunc, + response -> + writeBodyToFile(response, destinationFile, chunkNum, parallelDownloadOptions, + progressReporter == null ? null : progressReporter.createChild()).flux())) + .then(Mono.just(new SimpleResponse<>(initialResponse, null))); + }); + } + + private Flux getFluxStream( + HttpResponse httpResponse, + String sourceEndpoint, + HttpRange httpRange, + Context context) { + return FluxUtil.createRetriableDownloadFlux( + () -> getResponseBody(httpResponse), + (Throwable throwable, Long aLong) -> { + if (throwable instanceof CallingServerErrorException) { + CallingServerErrorException exception = (CallingServerErrorException) throwable; + if (exception.getResponse().getStatusCode() == 416) { + return makeDownloadRequest(sourceEndpoint, null, context) + .map(this::getResponseBody) + .flux() + .flatMap(flux -> flux); + } + } + + HttpRange range; + if (httpRange != null) { + range = new HttpRange(aLong + 1, httpRange.getLength() - aLong - 1); + } else { + range = new HttpRange(aLong + 1); + } + + return makeDownloadRequest(sourceEndpoint, range, context) + .map(this::getResponseBody) + .flux() + .flatMap(flux -> flux); + }, + Constants.ContentDownloader.MAX_RETRIES + ); + } + + private Flux getResponseBody(HttpResponse response) { + switch (response.getStatusCode()) { + case 200: + case 206: + return response.getBody(); + case 416: // Retriable with new HttpRange, potentially bytes=0- + return FluxUtil.fluxError(logger, + ErrorConstructorProxy.create(new HttpResponseException(formatExceptionMessage(response), response)) + ); + default: + throw logger.logExceptionAsError( + ErrorConstructorProxy.create(new HttpResponseException(formatExceptionMessage(response), response)) + ); + } + } + + private String formatExceptionMessage(HttpResponse httpResponse) { + return String.format("Service Request failed!%nStatus: %s", httpResponse.getStatusCode()); + } + + private Mono makeDownloadRequest( + String sourceEndpoint, + HttpRange httpRange, + Context context) { + HttpRequest request = getHttpRequest(sourceEndpoint, httpRange); + URL urlToSignWith = getUrlToSignRequestWith(sourceEndpoint); + + Context finalContext; + if (context == null) { + finalContext = new Context("hmacSignatureURL", urlToSignWith); + } else { + finalContext = context.addData("hmacSignatureURL", urlToSignWith); + } + + return httpPipeline.send(request, finalContext); + } + + private URL getUrlToSignRequestWith(String endpoint) { + try { + String path = new URL(endpoint).getPath(); + + if (path.startsWith("/")) { + path = path.substring(1); + } + + return new URL(resourceEndpoint + path); + } catch (MalformedURLException ex) { + throw logger.logExceptionAsError(new IllegalArgumentException(ex)); + } + } + + private HttpRequest getHttpRequest(String sourceEndpoint, HttpRange httpRange) { + HttpRequest request = new HttpRequest(HttpMethod.GET, sourceEndpoint); + + if (null != httpRange) { + request.setHeader(Constants.HeaderNames.RANGE, httpRange.toString()); + } + + return request; + } + + private Mono>>> downloadFirstChunk( + ParallelDownloadOptions parallelDownloadOptions, + Function>>> downloader) { + return downloader.apply(new HttpRange(0, parallelDownloadOptions.getBlockSize())) + .subscribeOn(Schedulers.boundedElastic()) + .flatMap(response -> { + // Extract the total length of the blob from the contentRange header. e.g. "bytes 1-6/7" + long totalLength = extractTotalBlobLength( + response.getHeaders().getValue(Constants.HeaderNames.CONTENT_RANGE) + ); + + return Mono.zip(Mono.just(totalLength), Mono.just(response)); + }); + } + + private long extractTotalBlobLength(String contentRange) { + return contentRange == null ? 0 : Long.parseLong(contentRange.split("/")[1]); + } + + private int calculateNumBlocks(long dataSize, long blockLength) { + // Can successfully cast to an int because MaxBlockSize is an int, which this expression must be less than. + int numBlocks = toIntExact(dataSize / blockLength); + // Include an extra block for trailing data. + if (dataSize % blockLength != 0) { + numBlocks++; + } + return numBlocks; + } + + private Flux downloadChunk( + Integer chunkNum, + Response> initialResponse, + ParallelDownloadOptions parallelDownloadOptions, + long newCount, + Function>>> downloader, + Function>, Flux> returnTransformer) { + if (chunkNum == 0) { + return returnTransformer.apply(initialResponse); + } + + // Calculate whether we need a full chunk or something smaller because we are at the end. + long modifier = chunkNum.longValue() * parallelDownloadOptions.getBlockSize(); + long chunkSizeActual = Math.min(parallelDownloadOptions.getBlockSize(), + newCount - modifier); + HttpRange chunkRange = new HttpRange(modifier, chunkSizeActual); + + // Make the download call. + return downloader.apply(chunkRange) + .subscribeOn(Schedulers.boundedElastic()) + .flatMapMany(returnTransformer); + } + + private static Mono writeBodyToFile( + Response> response, + AsynchronousFileChannel file, + long chunkNum, + ParallelDownloadOptions parallelDownloadOptions, + ProgressReporter progressReporter) { + // Extract the body. + Flux data = response.getValue(); + + // Report progress as necessary. + if (progressReporter != null) { + data = addProgressReporting(data, progressReporter); + } + + // Write to the file. + return FluxUtil.writeFile(data, file, chunkNum * parallelDownloadOptions.getBlockSize()); + } + + private static Flux addProgressReporting(Flux data, ProgressReporter progressReporter) { + return Mono.just(progressReporter).flatMapMany(reporter -> { + /* + Each time there is a new subscription, we will rewind the progress. This is desirable specifically + for retries, which resubscribe on each try. The first time this Flux is subscribed to, the + rewind will be a noop as there will have been no progress made. Subsequent rewinds will work as + expected. + */ + reporter.reset(); + + /* + Every time we emit some data, report it to the Tracker, which will pass it on to the end user. + */ + return data.doOnNext(buffer -> progressReporter.reportProgress(buffer.remaining())); + }); + } + + void downloadToFileCleanup(AsynchronousFileChannel channel, Path filePath, SignalType signalType) { + try { + channel.close(); + if (!signalType.equals(SignalType.ON_COMPLETE)) { + Files.deleteIfExists(filePath); + logger.verbose("Downloading to file failed. Cleaning up resources."); + } + } catch (IOException e) { + throw logger.logExceptionAsError(new UncheckedIOException(e)); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/EventHandler.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/EventHandler.java new file mode 100644 index 0000000000000..0219fe101eaa2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/EventHandler.java @@ -0,0 +1,121 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.events.AddParticipantsFailedEvent; +import com.azure.communication.callautomation.models.events.AddParticipantsSucceededEvent; +import com.azure.communication.callautomation.models.events.CallAutomationEventBase; +import com.azure.communication.callautomation.models.events.CallConnectedEvent; +import com.azure.communication.callautomation.models.events.CallDisconnectedEvent; +import com.azure.communication.callautomation.models.events.CallTransferAcceptedEvent; +import com.azure.communication.callautomation.models.events.CallTransferFailedEvent; +import com.azure.communication.callautomation.models.events.ParticipantsUpdatedEvent; +import com.azure.communication.callautomation.models.events.PlayCompleted; +import com.azure.communication.callautomation.models.events.PlayFailed; +import com.azure.communication.callautomation.models.events.RecordingStateChangedEvent; +import com.azure.core.models.CloudEvent; +import com.azure.core.util.logging.ClientLogger; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + + +/** + * Event handler for taking care of event related tasks. + */ +public final class EventHandler { + private static final ClientLogger LOGGER = new ClientLogger(EventHandler.class); + + /*** + * Returns a list of events from request's body. + * + * @param requestBody Body of the event request. + * @throws RuntimeException Any exceptions occurs at runtime. + * @return a list of CallAutomationEventBase + */ + public static List parseEventList(String requestBody) { + List callAutomationBaseEvents; + callAutomationBaseEvents = parseCloudEventList(requestBody); + + return callAutomationBaseEvents; + } + + /*** + * Returns the first(or the only) event of request's body. + * + * @param requestBody Body of the event request. + * @throws RuntimeException Any exceptions occurs at runtime. + * @return the first(or the only) event if request is not empty, otherwise null is returned. + */ + public static CallAutomationEventBase parseEvent(String requestBody) { + List callAutomationBaseEvents = parseEventList(requestBody); + return callAutomationBaseEvents.isEmpty() ? null : callAutomationBaseEvents.get(0); + } + + private static List parseCloudEventList(String requestBody) { + try { + List cloudEvents; + List callAutomationBaseEvents = new ArrayList<>(); + + try { + cloudEvents = CloudEvent.fromString(requestBody); + } catch (RuntimeException e) { + return callAutomationBaseEvents; + } + + for (CloudEvent cloudEvent : cloudEvents) { + CallAutomationEventBase temp = parseSingleCloudEvent(cloudEvent.getData().toString(), cloudEvent.getType()); + if (temp != null) { + callAutomationBaseEvents.add(temp); + } + } + return callAutomationBaseEvents; + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } + } + + private static CallAutomationEventBase parseSingleCloudEvent(String data, String eventType) { + try { + CallAutomationEventBase ret = null; + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + JsonNode eventData = mapper.readTree(data); + + if (Objects.equals(eventType, "Microsoft.Communication.CallConnected")) { + ret = mapper.convertValue(eventData, CallConnectedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.CallDisconnected")) { + ret = mapper.convertValue(eventData, CallDisconnectedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.AddParticipantsFailed")) { + ret = mapper.convertValue(eventData, AddParticipantsFailedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.AddParticipantsSucceeded")) { + ret = mapper.convertValue(eventData, AddParticipantsSucceededEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.CallTransferAccepted")) { + ret = mapper.convertValue(eventData, CallTransferAcceptedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.CallTransferFailed")) { + ret = mapper.convertValue(eventData, CallTransferFailedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.ParticipantsUpdated")) { + ret = mapper.convertValue(eventData, ParticipantsUpdatedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.CallRecordingStateChanged")) { + ret = mapper.convertValue(eventData, RecordingStateChangedEvent.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.PlayCompleted")) { + ret = mapper.convertValue(eventData, PlayCompleted.class); + } else if (Objects.equals(eventType, "Microsoft.Communication.PlayFailed")) { + ret = mapper.convertValue(eventData, PlayFailed.class); + } + + return ret; + } catch (RuntimeException e) { + throw LOGGER.logExceptionAsError(e); + } catch (JsonProcessingException e) { + throw LOGGER.logExceptionAsError(new RuntimeException(e)); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImpl.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImpl.java new file mode 100644 index 0000000000000..8d21fe19dd955 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImpl.java @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.CookiePolicy; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; + +/** Initializes a new instance of the AzureCommunicationCallAutomationService type. */ +public final class AzureCommunicationCallAutomationServiceImpl { + /** The endpoint of the Azure Communication resource. */ + private final String endpoint; + + /** + * Gets The endpoint of the Azure Communication resource. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** Api Version. */ + private final String apiVersion; + + /** + * Gets Api Version. + * + * @return the apiVersion value. + */ + public String getApiVersion() { + return this.apiVersion; + } + + /** The HTTP pipeline to send requests through. */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** The serializer to serialize an object into a string. */ + private final SerializerAdapter serializerAdapter; + + /** + * Gets The serializer to serialize an object into a string. + * + * @return the serializerAdapter value. + */ + public SerializerAdapter getSerializerAdapter() { + return this.serializerAdapter; + } + + /** The ServerCallingsImpl object to access its operations. */ + private final ServerCallingsImpl serverCallings; + + /** + * Gets the ServerCallingsImpl object to access its operations. + * + * @return the ServerCallingsImpl object. + */ + public ServerCallingsImpl getServerCallings() { + return this.serverCallings; + } + + /** The CallConnectionsImpl object to access its operations. */ + private final CallConnectionsImpl callConnections; + + /** + * Gets the CallConnectionsImpl object to access its operations. + * + * @return the CallConnectionsImpl object. + */ + public CallConnectionsImpl getCallConnections() { + return this.callConnections; + } + + /** The ContentsImpl object to access its operations. */ + private final ContentsImpl contents; + + /** + * Gets the ContentsImpl object to access its operations. + * + * @return the ContentsImpl object. + */ + public ContentsImpl getContents() { + return this.contents; + } + + /** The ServerCallsImpl object to access its operations. */ + private final ServerCallsImpl serverCalls; + + /** + * Gets the ServerCallsImpl object to access its operations. + * + * @return the ServerCallsImpl object. + */ + public ServerCallsImpl getServerCalls() { + return this.serverCalls; + } + + /** + * Initializes an instance of AzureCommunicationCallAutomationService client. + * + * @param endpoint The endpoint of the Azure Communication resource. + * @param apiVersion Api Version. + */ + AzureCommunicationCallAutomationServiceImpl(String endpoint, String apiVersion) { + this( + new HttpPipelineBuilder() + .policies(new UserAgentPolicy(), new RetryPolicy(), new CookiePolicy()) + .build(), + JacksonAdapter.createDefaultSerializerAdapter(), + endpoint, + apiVersion); + } + + /** + * Initializes an instance of AzureCommunicationCallAutomationService client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param endpoint The endpoint of the Azure Communication resource. + * @param apiVersion Api Version. + */ + AzureCommunicationCallAutomationServiceImpl(HttpPipeline httpPipeline, String endpoint, String apiVersion) { + this(httpPipeline, JacksonAdapter.createDefaultSerializerAdapter(), endpoint, apiVersion); + } + + /** + * Initializes an instance of AzureCommunicationCallAutomationService client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param serializerAdapter The serializer to serialize an object into a string. + * @param endpoint The endpoint of the Azure Communication resource. + * @param apiVersion Api Version. + */ + AzureCommunicationCallAutomationServiceImpl( + HttpPipeline httpPipeline, SerializerAdapter serializerAdapter, String endpoint, String apiVersion) { + this.httpPipeline = httpPipeline; + this.serializerAdapter = serializerAdapter; + this.endpoint = endpoint; + this.apiVersion = apiVersion; + this.serverCallings = new ServerCallingsImpl(this); + this.callConnections = new CallConnectionsImpl(this); + this.contents = new ContentsImpl(this); + this.serverCalls = new ServerCallsImpl(this); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImplBuilder.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImplBuilder.java new file mode 100644 index 0000000000000..9797d8fdb9a60 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/AzureCommunicationCallAutomationServiceImplBuilder.java @@ -0,0 +1,230 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.CookiePolicy; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.HttpPolicyProviders; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.Configuration; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** A builder for creating a new instance of the AzureCommunicationCallAutomationService type. */ +@ServiceClientBuilder(serviceClients = {AzureCommunicationCallAutomationServiceImpl.class}) +public final class AzureCommunicationCallAutomationServiceImplBuilder { + private static final String SDK_NAME = "name"; + + private static final String SDK_VERSION = "version"; + + private final Map properties = new HashMap<>(); + + /** Create an instance of the AzureCommunicationCallAutomationServiceImplBuilder. */ + public AzureCommunicationCallAutomationServiceImplBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The endpoint of the Azure Communication resource. + */ + private String endpoint; + + /** + * Sets The endpoint of the Azure Communication resource. + * + * @param endpoint the endpoint value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /* + * Api Version + */ + private String apiVersion; + + /** + * Sets Api Version. + * + * @param apiVersion the apiVersion value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder apiVersion(String apiVersion) { + this.apiVersion = apiVersion; + return this; + } + + /* + * The HTTP pipeline to send requests through + */ + private HttpPipeline pipeline; + + /** + * Sets The HTTP pipeline to send requests through. + * + * @param pipeline the pipeline value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder pipeline(HttpPipeline pipeline) { + this.pipeline = pipeline; + return this; + } + + /* + * The serializer to serialize an object into a string + */ + private SerializerAdapter serializerAdapter; + + /** + * Sets The serializer to serialize an object into a string. + * + * @param serializerAdapter the serializerAdapter value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder serializerAdapter(SerializerAdapter serializerAdapter) { + this.serializerAdapter = serializerAdapter; + return this; + } + + /* + * The HTTP client used to send the request. + */ + private HttpClient httpClient; + + /** + * Sets The HTTP client used to send the request. + * + * @param httpClient the httpClient value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The configuration store that is used during construction of the service + * client. + */ + private Configuration configuration; + + /** + * Sets The configuration store that is used during construction of the service client. + * + * @param configuration the configuration value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The logging configuration for HTTP requests and responses. + */ + private HttpLogOptions httpLogOptions; + + /** + * Sets The logging configuration for HTTP requests and responses. + * + * @param httpLogOptions the httpLogOptions value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder httpLogOptions(HttpLogOptions httpLogOptions) { + this.httpLogOptions = httpLogOptions; + return this; + } + + /* + * The retry policy that will attempt to retry failed requests, if + * applicable. + */ + private RetryPolicy retryPolicy; + + /** + * Sets The retry policy that will attempt to retry failed requests, if applicable. + * + * @param retryPolicy the retryPolicy value. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + + /* + * The list of Http pipeline policies to add. + */ + private final List pipelinePolicies; + + /** + * Adds a custom Http pipeline policy. + * + * @param customPolicy The custom Http pipeline policy to add. + * @return the AzureCommunicationCallAutomationServiceImplBuilder. + */ + public AzureCommunicationCallAutomationServiceImplBuilder addPolicy(HttpPipelinePolicy customPolicy) { + pipelinePolicies.add(customPolicy); + return this; + } + + /** + * Builds an instance of AzureCommunicationCallAutomationServiceImpl with the provided parameters. + * + * @return an instance of AzureCommunicationCallAutomationServiceImpl. + */ + public AzureCommunicationCallAutomationServiceImpl buildClient() { + if (apiVersion == null) { + this.apiVersion = "2022-04-07-preview"; + } + if (pipeline == null) { + this.pipeline = createHttpPipeline(); + } + if (serializerAdapter == null) { + this.serializerAdapter = JacksonAdapter.createDefaultSerializerAdapter(); + } + AzureCommunicationCallAutomationServiceImpl client = + new AzureCommunicationCallAutomationServiceImpl(pipeline, serializerAdapter, endpoint, apiVersion); + return client; + } + + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration = + (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + if (httpLogOptions == null) { + httpLogOptions = new HttpLogOptions(); + } + List policies = new ArrayList<>(); + String clientName = properties.getOrDefault(SDK_NAME, "UnknownName"); + String clientVersion = properties.getOrDefault(SDK_VERSION, "UnknownVersion"); + policies.add( + new UserAgentPolicy(httpLogOptions.getApplicationId(), clientName, clientVersion, buildConfiguration)); + HttpPolicyProviders.addBeforeRetryPolicies(policies); + policies.add(retryPolicy == null ? new RetryPolicy() : retryPolicy); + policies.add(new CookiePolicy()); + policies.addAll(this.pipelinePolicies); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(httpLogOptions)); + HttpPipeline httpPipeline = + new HttpPipelineBuilder() + .policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .build(); + return httpPipeline; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CallConnectionsImpl.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CallConnectionsImpl.java new file mode 100644 index 0000000000000..8b624be45747c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CallConnectionsImpl.java @@ -0,0 +1,1080 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.communication.callautomation.implementation.models.AcsCallParticipantInternal; +import com.azure.communication.callautomation.implementation.models.AddParticipantsRequestInternal; +import com.azure.communication.callautomation.implementation.models.AddParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.CallConnectionPropertiesInternal; +import com.azure.communication.callautomation.implementation.models.GetParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsRequestInternal; +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.TransferCallResponseInternal; +import com.azure.communication.callautomation.implementation.models.TransferToParticipantRequestInternal; +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.Delete; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.QueryParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** An instance of this class provides access to all the operations defined in CallConnections. */ +public final class CallConnectionsImpl { + /** The proxy service used to perform REST calls. */ + private final CallConnectionsService service; + + /** The service client containing this operation class. */ + private final AzureCommunicationCallAutomationServiceImpl client; + + /** + * Initializes an instance of CallConnectionsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + CallConnectionsImpl(AzureCommunicationCallAutomationServiceImpl client) { + this.service = + RestProxy.create(CallConnectionsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for AzureCommunicationCallAutomationServiceCallConnections to be used by + * the proxy service to perform REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "AzureCommunicationCa") + public interface CallConnectionsService { + @Get("/calling/callConnections/{callConnectionId}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getCall( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @HeaderParam("Accept") String accept, + Context context); + + @Delete("/calling/callConnections/{callConnectionId}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> hangupCall( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + Context context); + + @Post("/calling/callConnections/{callConnectionId}:terminate") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> terminateCall( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + Context context); + + @Post("/calling/callConnections/{callConnectionId}:transferToParticipant") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> transferToParticipant( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") TransferToParticipantRequestInternal transferToParticipantRequest, + @HeaderParam("Accept") String accept, + Context context); + + @Get("/calling/callConnections/{callConnectionId}/participants") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getParticipants( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @HeaderParam("Accept") String accept, + Context context); + + @Post("/calling/callConnections/{callConnectionId}/participants:add") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> addParticipant( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") AddParticipantsRequestInternal addParticipantsRequest, + @HeaderParam("Accept") String accept, + Context context); + + @Post("/calling/callConnections/{callConnectionId}/participants:remove") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> removeParticipants( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") RemoveParticipantsRequestInternal removeParticipantsRequest, + @HeaderParam("Accept") String accept, + Context context); + + @Get("/calling/callConnections/{callConnectionId}/participants/{participantMri}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getParticipant( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @PathParam("participantMri") String participantMri, + @QueryParam("api-version") String apiVersion, + @HeaderParam("Accept") String accept, + Context context); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getCallWithResponseAsync(String callConnectionId) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.getCall( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + accept, + context)); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getCallWithResponseAsync( + String callConnectionId, Context context) { + final String accept = "application/json"; + return service.getCall( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), accept, context); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getCallAsync(String callConnectionId) { + return getCallWithResponseAsync(callConnectionId) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getCallAsync(String callConnectionId, Context context) { + return getCallWithResponseAsync(callConnectionId, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallConnectionPropertiesInternal getCall(String callConnectionId) { + return getCallAsync(callConnectionId).block(); + } + + /** + * Get call connection. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call connection. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getCallWithResponse(String callConnectionId, Context context) { + return getCallWithResponseAsync(callConnectionId, context).block(); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> hangupCallWithResponseAsync(String callConnectionId) { + return FluxUtil.withContext( + context -> + service.hangupCall( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context)); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> hangupCallWithResponseAsync(String callConnectionId, Context context) { + return service.hangupCall(this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono hangupCallAsync(String callConnectionId) { + return hangupCallWithResponseAsync(callConnectionId).flatMap((Response res) -> Mono.empty()); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono hangupCallAsync(String callConnectionId, Context context) { + return hangupCallWithResponseAsync(callConnectionId, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void hangupCall(String callConnectionId) { + hangupCallAsync(callConnectionId).block(); + } + + /** + * Hangup the call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response hangupCallWithResponse(String callConnectionId, Context context) { + return hangupCallWithResponseAsync(callConnectionId, context).block(); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> terminateCallWithResponseAsync(String callConnectionId) { + return FluxUtil.withContext( + context -> + service.terminateCall( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context)); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> terminateCallWithResponseAsync(String callConnectionId, Context context) { + return service.terminateCall(this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono terminateCallAsync(String callConnectionId) { + return terminateCallWithResponseAsync(callConnectionId).flatMap((Response res) -> Mono.empty()); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono terminateCallAsync(String callConnectionId, Context context) { + return terminateCallWithResponseAsync(callConnectionId, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void terminateCall(String callConnectionId) { + terminateCallAsync(callConnectionId).block(); + } + + /** + * Terminate a call using CallConnectionId. + * + * @param callConnectionId The terminate call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response terminateCallWithResponse(String callConnectionId, Context context) { + return terminateCallWithResponseAsync(callConnectionId, context).block(); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> transferToParticipantWithResponseAsync( + String callConnectionId, TransferToParticipantRequestInternal transferToParticipantRequest) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.transferToParticipant( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + transferToParticipantRequest, + accept, + context)); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> transferToParticipantWithResponseAsync( + String callConnectionId, + TransferToParticipantRequestInternal transferToParticipantRequest, + Context context) { + final String accept = "application/json"; + return service.transferToParticipant( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + transferToParticipantRequest, + accept, + context); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono transferToParticipantAsync( + String callConnectionId, TransferToParticipantRequestInternal transferToParticipantRequest) { + return transferToParticipantWithResponseAsync(callConnectionId, transferToParticipantRequest) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono transferToParticipantAsync( + String callConnectionId, + TransferToParticipantRequestInternal transferToParticipantRequest, + Context context) { + return transferToParticipantWithResponseAsync(callConnectionId, transferToParticipantRequest, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public TransferCallResponseInternal transferToParticipant( + String callConnectionId, TransferToParticipantRequestInternal transferToParticipantRequest) { + return transferToParticipantAsync(callConnectionId, transferToParticipantRequest).block(); + } + + /** + * Transfer the call to a participant. + * + * @param callConnectionId The call connection id. + * @param transferToParticipantRequest The transfer to participant request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response transferToParticipantWithResponse( + String callConnectionId, + TransferToParticipantRequestInternal transferToParticipantRequest, + Context context) { + return transferToParticipantWithResponseAsync(callConnectionId, transferToParticipantRequest, context).block(); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getParticipantsWithResponseAsync(String callConnectionId) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.getParticipants( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + accept, + context)); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getParticipantsWithResponseAsync( + String callConnectionId, Context context) { + final String accept = "application/json"; + return service.getParticipants( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), accept, context); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getParticipantsAsync(String callConnectionId) { + return getParticipantsWithResponseAsync(callConnectionId) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getParticipantsAsync(String callConnectionId, Context context) { + return getParticipantsWithResponseAsync(callConnectionId, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public GetParticipantsResponseInternal getParticipants(String callConnectionId) { + return getParticipantsAsync(callConnectionId).block(); + } + + /** + * Get participants from a call. + * + * @param callConnectionId The call connection Id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participants from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getParticipantsWithResponse( + String callConnectionId, Context context) { + return getParticipantsWithResponseAsync(callConnectionId, context).block(); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> addParticipantWithResponseAsync( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.addParticipant( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + addParticipantsRequest, + accept, + context)); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> addParticipantWithResponseAsync( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest, Context context) { + final String accept = "application/json"; + return service.addParticipant( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + addParticipantsRequest, + accept, + context); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono addParticipantAsync( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest) { + return addParticipantWithResponseAsync(callConnectionId, addParticipantsRequest) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono addParticipantAsync( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest, Context context) { + return addParticipantWithResponseAsync(callConnectionId, addParticipantsRequest, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public AddParticipantsResponseInternal addParticipant( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest) { + return addParticipantAsync(callConnectionId, addParticipantsRequest).block(); + } + + /** + * Add participants to the call. + * + * @param callConnectionId The call connection Id. + * @param addParticipantsRequest The add participants request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response addParticipantWithResponse( + String callConnectionId, AddParticipantsRequestInternal addParticipantsRequest, Context context) { + return addParticipantWithResponseAsync(callConnectionId, addParticipantsRequest, context).block(); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> removeParticipantsWithResponseAsync( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.removeParticipants( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + removeParticipantsRequest, + accept, + context)); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> removeParticipantsWithResponseAsync( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest, Context context) { + final String accept = "application/json"; + return service.removeParticipants( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + removeParticipantsRequest, + accept, + context); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono removeParticipantsAsync( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest) { + return removeParticipantsWithResponseAsync(callConnectionId, removeParticipantsRequest) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono removeParticipantsAsync( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest, Context context) { + return removeParticipantsWithResponseAsync(callConnectionId, removeParticipantsRequest, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RemoveParticipantsResponseInternal removeParticipants( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest) { + return removeParticipantsAsync(callConnectionId, removeParticipantsRequest).block(); + } + + /** + * Remove participant from the call using identifier. + * + * @param callConnectionId The call connection id. + * @param removeParticipantsRequest The participants to be removed from the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response removeParticipantsWithResponse( + String callConnectionId, RemoveParticipantsRequestInternal removeParticipantsRequest, Context context) { + return removeParticipantsWithResponseAsync(callConnectionId, removeParticipantsRequest, context).block(); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getParticipantWithResponseAsync( + String callConnectionId, String participantMri) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.getParticipant( + this.client.getEndpoint(), + callConnectionId, + participantMri, + this.client.getApiVersion(), + accept, + context)); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getParticipantWithResponseAsync( + String callConnectionId, String participantMri, Context context) { + final String accept = "application/json"; + return service.getParticipant( + this.client.getEndpoint(), + callConnectionId, + participantMri, + this.client.getApiVersion(), + accept, + context); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getParticipantAsync(String callConnectionId, String participantMri) { + return getParticipantWithResponseAsync(callConnectionId, participantMri) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getParticipantAsync( + String callConnectionId, String participantMri, Context context) { + return getParticipantWithResponseAsync(callConnectionId, participantMri, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public AcsCallParticipantInternal getParticipant(String callConnectionId, String participantMri) { + return getParticipantAsync(callConnectionId, participantMri).block(); + } + + /** + * Get participant from a call. + * + * @param callConnectionId The call connection Id. + * @param participantMri MRI of the participants to retrieve. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return participant from a call. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getParticipantWithResponse( + String callConnectionId, String participantMri, Context context) { + return getParticipantWithResponseAsync(callConnectionId, participantMri, context).block(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/Constants.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/Constants.java new file mode 100644 index 0000000000000..e2568110b0d93 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/Constants.java @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation; + +/*** + * Constants to be used by CallingServer. + */ +public final class Constants { + public static final int KB = 1024; + public static final int MB = KB * 1024; + + /*** + * Content downloader constants + */ + public static class ContentDownloader { + public static final int DEFAULT_CONCURRENT_TRANSFERS_COUNT = 5; + public static final int DEFAULT_BUFFER_SIZE = 4 * MB; + public static final int DEFAULT_INITIAL_DOWNLOAD_RANGE_SIZE = 256 * MB; + public static final int MAX_RETRIES = 4; + } + + /*** + * HTTP Header Names + */ + public static class HeaderNames { + public static final String RANGE = "Range"; + public static final String CONTENT_RANGE = "Content-Range"; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ContentsImpl.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ContentsImpl.java new file mode 100644 index 0000000000000..0dcc091b2d744 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ContentsImpl.java @@ -0,0 +1,509 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.communication.callautomation.implementation.models.PlayRequest; +import com.azure.communication.callautomation.implementation.models.RecognizeRequest; +import com.azure.communication.callautomation.implementation.models.RecordingStateResponseInternal; +import com.azure.communication.callautomation.implementation.models.StartCallRecordingRequestInternal; +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.QueryParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** An instance of this class provides access to all the operations defined in Contents. */ +public final class ContentsImpl { + /** The proxy service used to perform REST calls. */ + private final ContentsService service; + + /** The service client containing this operation class. */ + private final AzureCommunicationCallAutomationServiceImpl client; + + /** + * Initializes an instance of ContentsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + ContentsImpl(AzureCommunicationCallAutomationServiceImpl client) { + this.service = RestProxy.create(ContentsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for AzureCommunicationCallAutomationServiceContents to be used by the + * proxy service to perform REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "AzureCommunicationCa") + public interface ContentsService { + @Post("/calling/callConnections/{callConnectionId}:play") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> play( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") PlayRequest playRequest, + Context context); + + @Post("/calling/callConnections/{callConnectionId}:cancelAllMediaOperations") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> cancelAllMediaOperations( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + Context context); + + @Post("/calling/callConnections/{callConnectionId}:recognize") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> recognize( + @HostParam("endpoint") String endpoint, + @PathParam("callConnectionId") String callConnectionId, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") RecognizeRequest recognizeRequest, + Context context); + + @Post("/calling/recordings") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> recording( + @HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") StartCallRecordingRequestInternal startCallRecording, + @HeaderParam("Accept") String accept, + Context context); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> playWithResponseAsync(String callConnectionId, PlayRequest playRequest) { + return FluxUtil.withContext( + context -> + service.play( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + playRequest, + context)); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> playWithResponseAsync( + String callConnectionId, PlayRequest playRequest, Context context) { + return service.play( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), playRequest, context); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono playAsync(String callConnectionId, PlayRequest playRequest) { + return playWithResponseAsync(callConnectionId, playRequest).flatMap((Response res) -> Mono.empty()); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono playAsync(String callConnectionId, PlayRequest playRequest, Context context) { + return playWithResponseAsync(callConnectionId, playRequest, context) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void play(String callConnectionId, PlayRequest playRequest) { + playAsync(callConnectionId, playRequest).block(); + } + + /** + * Plays audio to participants in the call. + * + * @param callConnectionId The callConnectionId parameter. + * @param playRequest The playRequest parameter. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response playWithResponse(String callConnectionId, PlayRequest playRequest, Context context) { + return playWithResponseAsync(callConnectionId, playRequest, context).block(); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> cancelAllMediaOperationsWithResponseAsync(String callConnectionId) { + return FluxUtil.withContext( + context -> + service.cancelAllMediaOperations( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context)); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> cancelAllMediaOperationsWithResponseAsync(String callConnectionId, Context context) { + return service.cancelAllMediaOperations( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), context); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono cancelAllMediaOperationsAsync(String callConnectionId) { + return cancelAllMediaOperationsWithResponseAsync(callConnectionId) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono cancelAllMediaOperationsAsync(String callConnectionId, Context context) { + return cancelAllMediaOperationsWithResponseAsync(callConnectionId, context) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void cancelAllMediaOperations(String callConnectionId) { + cancelAllMediaOperationsAsync(callConnectionId).block(); + } + + /** + * Cancel all media operations in a call. + * + * @param callConnectionId The call connection id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response cancelAllMediaOperationsWithResponse(String callConnectionId, Context context) { + return cancelAllMediaOperationsWithResponseAsync(callConnectionId, context).block(); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> recognizeWithResponseAsync(String callConnectionId, RecognizeRequest recognizeRequest) { + return FluxUtil.withContext( + context -> + service.recognize( + this.client.getEndpoint(), + callConnectionId, + this.client.getApiVersion(), + recognizeRequest, + context)); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> recognizeWithResponseAsync( + String callConnectionId, RecognizeRequest recognizeRequest, Context context) { + return service.recognize( + this.client.getEndpoint(), callConnectionId, this.client.getApiVersion(), recognizeRequest, context); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono recognizeAsync(String callConnectionId, RecognizeRequest recognizeRequest) { + return recognizeWithResponseAsync(callConnectionId, recognizeRequest) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono recognizeAsync(String callConnectionId, RecognizeRequest recognizeRequest, Context context) { + return recognizeWithResponseAsync(callConnectionId, recognizeRequest, context) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void recognize(String callConnectionId, RecognizeRequest recognizeRequest) { + recognizeAsync(callConnectionId, recognizeRequest).block(); + } + + /** + * Recognize media from call. + * + * @param callConnectionId The call connection id. + * @param recognizeRequest The media recognize request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response recognizeWithResponse( + String callConnectionId, RecognizeRequest recognizeRequest, Context context) { + return recognizeWithResponseAsync(callConnectionId, recognizeRequest, context).block(); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> recordingWithResponseAsync( + StartCallRecordingRequestInternal startCallRecording) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.recording( + this.client.getEndpoint(), + this.client.getApiVersion(), + startCallRecording, + accept, + context)); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> recordingWithResponseAsync( + StartCallRecordingRequestInternal startCallRecording, Context context) { + final String accept = "application/json"; + return service.recording( + this.client.getEndpoint(), this.client.getApiVersion(), startCallRecording, accept, context); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono recordingAsync(StartCallRecordingRequestInternal startCallRecording) { + return recordingWithResponseAsync(startCallRecording) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono recordingAsync( + StartCallRecordingRequestInternal startCallRecording, Context context) { + return recordingWithResponseAsync(startCallRecording, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RecordingStateResponseInternal recording(StartCallRecordingRequestInternal startCallRecording) { + return recordingAsync(startCallRecording).block(); + } + + /** + * Start recording the call. + * + * @param startCallRecording The request body of start call recording request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response recordingWithResponse( + StartCallRecordingRequestInternal startCallRecording, Context context) { + return recordingWithResponseAsync(startCallRecording, context).block(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CustomHmacAuthenticationPolicy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CustomHmacAuthenticationPolicy.java new file mode 100644 index 0000000000000..196364be214ed --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/CustomHmacAuthenticationPolicy.java @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.communication.callautomation.implementation; + +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; + +import com.azure.core.util.logging.ClientLogger; +import reactor.core.Exceptions; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +/** + * HttpPipelinePolicy to append CommunicationClient required headers + */ +public final class CustomHmacAuthenticationPolicy implements HttpPipelinePolicy { + private static final String X_MS_DATE_HEADER = "x-ms-date"; + private static final String X_MS_STRING_TO_SIGN_HEADER = "x-ms-hmac-string-to-sign-base64"; + private static final String HOST_HEADER = "host"; + private static final String CONTENT_HASH_HEADER = "x-ms-content-sha256"; + // Order of the headers are important here for generating correct signature + private static final String[] SIGNED_HEADERS = new String[]{X_MS_DATE_HEADER, HOST_HEADER, CONTENT_HASH_HEADER}; + + private static final String AUTHORIZATIONHEADERNAME = "Authorization"; + private static final String HMACSHA256FORMAT = "HMAC-SHA256 SignedHeaders=%s&Signature=%s"; + + // Previously DateTimeFormatter.RFC_1123_DATE_TIME was being used. There + // was an issue with the day of month part. RFC_1123_DATE_TIME does not + // append a leading '0' on days that are less than 10. It is important + // that the locale remain US. In other locals the values that are generated + // for the day and month strings may be different. (e.g. Canada day strings + // have a '.' at the end) + static final DateTimeFormatter HMAC_DATETIMEFORMATTER_PATTERN = + DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US); + + private final AzureKeyCredential credential; + private final String acsResource; + private final ClientLogger logger = new ClientLogger(CustomHmacAuthenticationPolicy.class); + + /** + * Created with a non-null client credential + * @param clientCredential client credential with valid access key + * @param acsResource the acs resource endpoint + */ + public CustomHmacAuthenticationPolicy(AzureKeyCredential clientCredential, String acsResource) { + Objects.requireNonNull(clientCredential, "'clientCredential' cannot be a null value."); + this.credential = clientCredential; + this.acsResource = acsResource; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + final Flux contents = context.getHttpRequest().getBody() == null + ? Flux.just(ByteBuffer.allocate(0)) + : context.getHttpRequest().getBody(); + + if ("http".equals(context.getHttpRequest().getUrl().getProtocol())) { + return Mono.error( + new RuntimeException("AzureKeyCredential requires a URL using the HTTPS protocol scheme")); + } + + try { + URL hostnameToSignWith = context.getData("hmacSignatureURL") + .filter(alternativeUrl -> alternativeUrl instanceof URL) + .map(alternativeUrl -> (URL) alternativeUrl) + .orElse(context.getHttpRequest().getUrl()); + + return appendAuthorizationHeaders( + hostnameToSignWith, + context.getHttpRequest().getHttpMethod().toString(), + contents) + .flatMap(headers -> { + headers.entrySet().forEach( + header -> context.getHttpRequest().setHeader(header.getKey(), header.getValue())); + + return next.process(); + }); + } catch (RuntimeException r) { + return Mono.error(r); + } + } + + private Mono> appendAuthorizationHeaders(URL url, String httpMethod, Flux contents) { + return contents.collect(() -> { + try { + return MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw logger.logExceptionAsError(Exceptions.propagate(e)); + } + }, MessageDigest::update) + .map(messageDigest -> addAuthenticationHeaders(url, httpMethod, messageDigest)); + } + + private Map addAuthenticationHeaders(final URL url, + final String httpMethod, + final MessageDigest messageDigest) { + final Map headers = new HashMap<>(); + + final String contentHash = Base64.getEncoder().encodeToString(messageDigest.digest()); + headers.put("X_FORWARDED_HOST", acsResource); + headers.put(HOST_HEADER, acsResource); + headers.put(CONTENT_HASH_HEADER, contentHash); + String utcNow = OffsetDateTime.now(ZoneOffset.UTC) + .format(HMAC_DATETIMEFORMATTER_PATTERN); + headers.put(X_MS_DATE_HEADER, utcNow); + addSignatureHeader(url, httpMethod, headers); + return headers; + } + + private void addSignatureHeader(final URL url, final String httpMethod, final Map httpHeaders) { + final String signedHeaderNames = String.join(";", SIGNED_HEADERS); + final String signedHeaderValues = Arrays.stream(SIGNED_HEADERS) + .map(httpHeaders::get) + .collect(Collectors.joining(";")); + + String pathAndQuery = url.getPath(); + if (url.getQuery() != null) { + pathAndQuery += '?' + url.getQuery(); + } + + // String-To-Sign=HTTP_METHOD + '\n' + path_and_query + '\n' + signed_headers_values + // The line separator has to be \n. Using %n with String.format will result in a 401 from the service. + String stringToSign = httpMethod.toUpperCase(Locale.US) + "\n" + pathAndQuery + "\n" + signedHeaderValues; + + String accessKey = credential.getKey(); + byte[] key = Base64.getDecoder().decode(accessKey); + Mac sha256HMAC; + try { + sha256HMAC = Mac.getInstance("HmacSHA256"); + sha256HMAC.init(new SecretKeySpec(key, "HmacSHA256")); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw logger.logExceptionAsError(new RuntimeException(e)); + } + + final String signature = + Base64.getEncoder().encodeToString(sha256HMAC.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8))); + httpHeaders.put(AUTHORIZATIONHEADERNAME, String.format(HMACSHA256FORMAT, signedHeaderNames, signature)); + httpHeaders.put(X_MS_STRING_TO_SIGN_HEADER, Base64.getEncoder().encodeToString(stringToSign.getBytes(StandardCharsets.UTF_8))); + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallingsImpl.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallingsImpl.java new file mode 100644 index 0000000000000..72c9dbad129d0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallingsImpl.java @@ -0,0 +1,504 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.communication.callautomation.implementation.models.AnswerCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.CallConnectionPropertiesInternal; +import com.azure.communication.callautomation.implementation.models.CreateCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.RedirectCallRequestInternal; +import com.azure.communication.callautomation.implementation.models.RejectCallRequestInternal; +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.QueryParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** An instance of this class provides access to all the operations defined in ServerCallings. */ +public final class ServerCallingsImpl { + /** The proxy service used to perform REST calls. */ + private final ServerCallingsService service; + + /** The service client containing this operation class. */ + private final AzureCommunicationCallAutomationServiceImpl client; + + /** + * Initializes an instance of ServerCallingsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + ServerCallingsImpl(AzureCommunicationCallAutomationServiceImpl client) { + this.service = + RestProxy.create(ServerCallingsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for AzureCommunicationCallAutomationServiceServerCallings to be used by + * the proxy service to perform REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "AzureCommunicationCa") + public interface ServerCallingsService { + @Post("/calling/callConnections") + @ExpectedResponses({201}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> createCall( + @HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") CreateCallRequestInternal body, + @HeaderParam("Accept") String accept, + Context context); + + @Post("/calling/callConnections:answer") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> answerCall( + @HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") AnswerCallRequestInternal answerCallRequest, + @HeaderParam("Accept") String accept, + Context context); + + @Post("/calling/callConnections:redirect") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> redirectCall( + @HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") RedirectCallRequestInternal redirectCallRequest, + Context context); + + @Post("/calling/callConnections:reject") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> rejectCall( + @HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, + @BodyParam("application/json") RejectCallRequestInternal rejectCallRequest, + Context context); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createCallWithResponseAsync( + CreateCallRequestInternal body) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.createCall( + this.client.getEndpoint(), this.client.getApiVersion(), body, accept, context)); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createCallWithResponseAsync( + CreateCallRequestInternal body, Context context) { + final String accept = "application/json"; + return service.createCall(this.client.getEndpoint(), this.client.getApiVersion(), body, accept, context); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createCallAsync(CreateCallRequestInternal body) { + return createCallWithResponseAsync(body) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createCallAsync(CreateCallRequestInternal body, Context context) { + return createCallWithResponseAsync(body, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallConnectionPropertiesInternal createCall(CreateCallRequestInternal body) { + return createCallAsync(body).block(); + } + + /** + * Create an outbound call. + * + * @param body The create call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createCallWithResponse( + CreateCallRequestInternal body, Context context) { + return createCallWithResponseAsync(body, context).block(); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> answerCallWithResponseAsync( + AnswerCallRequestInternal answerCallRequest) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.answerCall( + this.client.getEndpoint(), + this.client.getApiVersion(), + answerCallRequest, + accept, + context)); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> answerCallWithResponseAsync( + AnswerCallRequestInternal answerCallRequest, Context context) { + final String accept = "application/json"; + return service.answerCall( + this.client.getEndpoint(), this.client.getApiVersion(), answerCallRequest, accept, context); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono answerCallAsync(AnswerCallRequestInternal answerCallRequest) { + return answerCallWithResponseAsync(answerCallRequest) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono answerCallAsync( + AnswerCallRequestInternal answerCallRequest, Context context) { + return answerCallWithResponseAsync(answerCallRequest, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public CallConnectionPropertiesInternal answerCall(AnswerCallRequestInternal answerCallRequest) { + return answerCallAsync(answerCallRequest).block(); + } + + /** + * Answer a call using the IncomingCallContext from Event Grid. + * + * @param answerCallRequest The answer call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response answerCallWithResponse( + AnswerCallRequestInternal answerCallRequest, Context context) { + return answerCallWithResponseAsync(answerCallRequest, context).block(); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> redirectCallWithResponseAsync(RedirectCallRequestInternal redirectCallRequest) { + return FluxUtil.withContext( + context -> + service.redirectCall( + this.client.getEndpoint(), this.client.getApiVersion(), redirectCallRequest, context)); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> redirectCallWithResponseAsync( + RedirectCallRequestInternal redirectCallRequest, Context context) { + return service.redirectCall( + this.client.getEndpoint(), this.client.getApiVersion(), redirectCallRequest, context); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono redirectCallAsync(RedirectCallRequestInternal redirectCallRequest) { + return redirectCallWithResponseAsync(redirectCallRequest).flatMap((Response res) -> Mono.empty()); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono redirectCallAsync(RedirectCallRequestInternal redirectCallRequest, Context context) { + return redirectCallWithResponseAsync(redirectCallRequest, context) + .flatMap((Response res) -> Mono.empty()); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void redirectCall(RedirectCallRequestInternal redirectCallRequest) { + redirectCallAsync(redirectCallRequest).block(); + } + + /** + * Redirect a call. + * + * @param redirectCallRequest The request payload for redirecting the call. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response redirectCallWithResponse(RedirectCallRequestInternal redirectCallRequest, Context context) { + return redirectCallWithResponseAsync(redirectCallRequest, context).block(); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> rejectCallWithResponseAsync(RejectCallRequestInternal rejectCallRequest) { + return FluxUtil.withContext( + context -> + service.rejectCall( + this.client.getEndpoint(), this.client.getApiVersion(), rejectCallRequest, context)); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> rejectCallWithResponseAsync( + RejectCallRequestInternal rejectCallRequest, Context context) { + return service.rejectCall(this.client.getEndpoint(), this.client.getApiVersion(), rejectCallRequest, context); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono rejectCallAsync(RejectCallRequestInternal rejectCallRequest) { + return rejectCallWithResponseAsync(rejectCallRequest).flatMap((Response res) -> Mono.empty()); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono rejectCallAsync(RejectCallRequestInternal rejectCallRequest, Context context) { + return rejectCallWithResponseAsync(rejectCallRequest, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void rejectCall(RejectCallRequestInternal rejectCallRequest) { + rejectCallAsync(rejectCallRequest).block(); + } + + /** + * Reject the call. + * + * @param rejectCallRequest The reject call request. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response rejectCallWithResponse(RejectCallRequestInternal rejectCallRequest, Context context) { + return rejectCallWithResponseAsync(rejectCallRequest, context).block(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallsImpl.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallsImpl.java new file mode 100644 index 0000000000000..c58ae65c02b3b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/ServerCallsImpl.java @@ -0,0 +1,469 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation; + +import com.azure.communication.callautomation.implementation.models.RecordingStateResponseInternal; +import com.azure.core.annotation.Delete; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.QueryParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import reactor.core.publisher.Mono; + +/** An instance of this class provides access to all the operations defined in ServerCalls. */ +public final class ServerCallsImpl { + /** The proxy service used to perform REST calls. */ + private final ServerCallsService service; + + /** The service client containing this operation class. */ + private final AzureCommunicationCallAutomationServiceImpl client; + + /** + * Initializes an instance of ServerCallsImpl. + * + * @param client the instance of the service client containing this operation class. + */ + ServerCallsImpl(AzureCommunicationCallAutomationServiceImpl client) { + this.service = + RestProxy.create(ServerCallsService.class, client.getHttpPipeline(), client.getSerializerAdapter()); + this.client = client; + } + + /** + * The interface defining all the services for AzureCommunicationCallAutomationServiceServerCalls to be used by the + * proxy service to perform REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "AzureCommunicationCa") + public interface ServerCallsService { + @Get("/calling/recordings/{recordingId}") + @ExpectedResponses({200}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getRecordingProperties( + @HostParam("endpoint") String endpoint, + @PathParam("recordingId") String recordingId, + @QueryParam("api-version") String apiVersion, + @HeaderParam("Accept") String accept, + Context context); + + @Delete("/calling/recordings/{recordingId}") + @ExpectedResponses({204}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> stopRecording( + @HostParam("endpoint") String endpoint, + @PathParam("recordingId") String recordingId, + @QueryParam("api-version") String apiVersion, + Context context); + + @Post("/calling/recordings/{recordingId}:pause") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> pauseRecording( + @HostParam("endpoint") String endpoint, + @PathParam("recordingId") String recordingId, + @QueryParam("api-version") String apiVersion, + Context context); + + @Post("/calling/recordings/{recordingId}:resume") + @ExpectedResponses({202}) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> resumeRecording( + @HostParam("endpoint") String endpoint, + @PathParam("recordingId") String recordingId, + @QueryParam("api-version") String apiVersion, + Context context); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRecordingPropertiesWithResponseAsync(String recordingId) { + final String accept = "application/json"; + return FluxUtil.withContext( + context -> + service.getRecordingProperties( + this.client.getEndpoint(), recordingId, this.client.getApiVersion(), accept, context)); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRecordingPropertiesWithResponseAsync( + String recordingId, Context context) { + final String accept = "application/json"; + return service.getRecordingProperties( + this.client.getEndpoint(), recordingId, this.client.getApiVersion(), accept, context); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getRecordingPropertiesAsync(String recordingId) { + return getRecordingPropertiesWithResponseAsync(recordingId) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getRecordingPropertiesAsync(String recordingId, Context context) { + return getRecordingPropertiesWithResponseAsync(recordingId, context) + .flatMap( + (Response res) -> { + if (res.getValue() != null) { + return Mono.just(res.getValue()); + } else { + return Mono.empty(); + } + }); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public RecordingStateResponseInternal getRecordingProperties(String recordingId) { + return getRecordingPropertiesAsync(recordingId).block(); + } + + /** + * Get call recording properties. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return call recording properties. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRecordingPropertiesWithResponse( + String recordingId, Context context) { + return getRecordingPropertiesWithResponseAsync(recordingId, context).block(); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> stopRecordingWithResponseAsync(String recordingId) { + return FluxUtil.withContext( + context -> + service.stopRecording( + this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context)); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> stopRecordingWithResponseAsync(String recordingId, Context context) { + return service.stopRecording(this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono stopRecordingAsync(String recordingId) { + return stopRecordingWithResponseAsync(recordingId).flatMap((Response res) -> Mono.empty()); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono stopRecordingAsync(String recordingId, Context context) { + return stopRecordingWithResponseAsync(recordingId, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void stopRecording(String recordingId) { + stopRecordingAsync(recordingId).block(); + } + + /** + * Stop recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response stopRecordingWithResponse(String recordingId, Context context) { + return stopRecordingWithResponseAsync(recordingId, context).block(); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> pauseRecordingWithResponseAsync(String recordingId) { + return FluxUtil.withContext( + context -> + service.pauseRecording( + this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context)); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> pauseRecordingWithResponseAsync(String recordingId, Context context) { + return service.pauseRecording(this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono pauseRecordingAsync(String recordingId) { + return pauseRecordingWithResponseAsync(recordingId).flatMap((Response res) -> Mono.empty()); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono pauseRecordingAsync(String recordingId, Context context) { + return pauseRecordingWithResponseAsync(recordingId, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void pauseRecording(String recordingId) { + pauseRecordingAsync(recordingId).block(); + } + + /** + * Pause recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response pauseRecordingWithResponse(String recordingId, Context context) { + return pauseRecordingWithResponseAsync(recordingId, context).block(); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> resumeRecordingWithResponseAsync(String recordingId) { + return FluxUtil.withContext( + context -> + service.resumeRecording( + this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context)); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> resumeRecordingWithResponseAsync(String recordingId, Context context) { + return service.resumeRecording(this.client.getEndpoint(), recordingId, this.client.getApiVersion(), context); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono resumeRecordingAsync(String recordingId) { + return resumeRecordingWithResponseAsync(recordingId).flatMap((Response res) -> Mono.empty()); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the completion. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono resumeRecordingAsync(String recordingId, Context context) { + return resumeRecordingWithResponseAsync(recordingId, context).flatMap((Response res) -> Mono.empty()); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public void resumeRecording(String recordingId) { + resumeRecordingAsync(recordingId).block(); + } + + /** + * Resume recording the call. + * + * @param recordingId The recording id. + * @param context The context to associate with this operation. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return the response. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response resumeRecordingWithResponse(String recordingId, Context context) { + return resumeRecordingWithResponseAsync(recordingId, context).block(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/AddParticipantsResponseConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/AddParticipantsResponseConstructorProxy.java new file mode 100644 index 0000000000000..56ed5680dce8f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/AddParticipantsResponseConstructorProxy.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.AddParticipantsResponseInternal; +import com.azure.communication.callautomation.models.AddParticipantsResult; + +/** + * Helper class to access private values of {@link AddParticipantsResult} across package boundaries. + */ +public final class AddParticipantsResponseConstructorProxy { + private static AddParticipantsResponseConstructorAccessor accessor; + + private AddParticipantsResponseConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link AddParticipantsResponseConstructorAccessor} + * instance. + */ + public interface AddParticipantsResponseConstructorAccessor { + /** + * Creates a new instance of {@link AddParticipantsResult} backed by an internal instance of + * {@link AddParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link AddParticipantsResult}. + */ + AddParticipantsResult create(AddParticipantsResponseInternal internalResponse); + } + + /** + * The method called from {@link AddParticipantsResult} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final AddParticipantsResponseConstructorAccessor accessor) { + AddParticipantsResponseConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link AddParticipantsResult} backed by an internal instance of + * {@link AddParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link AddParticipantsResult}. + */ + public static AddParticipantsResult create(AddParticipantsResponseInternal internalResponse) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses BlobDownloadHeaders which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new AddParticipantsResult(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/CallConnectionPropertiesConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/CallConnectionPropertiesConstructorProxy.java new file mode 100644 index 0000000000000..95102edec8b0c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/CallConnectionPropertiesConstructorProxy.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.CallConnectionPropertiesInternal; +import com.azure.communication.callautomation.models.CallConnectionProperties; + +import java.net.URISyntaxException; + +/** + * Helper class to access private values of {@link CallConnectionProperties} across package boundaries. + */ +public final class CallConnectionPropertiesConstructorProxy { + private static CallConnectionPropertiesConstructorAccessor accessor; + + private CallConnectionPropertiesConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link CallConnectionPropertiesConstructorAccessor} + * instance. + */ + public interface CallConnectionPropertiesConstructorAccessor { + /** + * Creates a new instance of {@link CallConnectionProperties} backed by an internal instance of + * {@link CallConnectionProperties}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link CallConnectionProperties}. + */ + CallConnectionProperties create(CallConnectionPropertiesInternal internalResponse) throws URISyntaxException; + } + + /** + * The method called from {@link CallConnectionProperties} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final CallConnectionPropertiesConstructorAccessor accessor) { + CallConnectionPropertiesConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link CallConnectionProperties} backed by an internal instance of + * {@link CallConnectionPropertiesInternal}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link CallConnectionProperties}. + */ + public static CallConnectionProperties create(CallConnectionPropertiesInternal internalResponse) throws URISyntaxException { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses BlobDownloadHeaders which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new CallConnectionProperties(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ErrorConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ErrorConstructorProxy.java new file mode 100644 index 0000000000000..8630afcf5030f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ErrorConstructorProxy.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.core.exception.HttpResponseException; + +/** + * Helper class to access private values of {@link CallingServerErrorException} across package boundaries. + */ +public final class ErrorConstructorProxy { + private static ErrorConstructorProxy.ErrorConstructorAccessor accessor; + + private ErrorConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link CallConnectionPropertiesConstructorProxy.CallConnectionPropertiesConstructorAccessor} + * instance. + */ + public interface ErrorConstructorAccessor { + /** + * Creates a new instance of {@link CallingServerErrorException} backed by an internal instance of + * {@link CallingServerErrorException}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link CallingServerErrorException}. + */ + CallingServerErrorException create(HttpResponseException internalResponse); + } + + /** + * The method called from {@link CallingServerErrorException} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final ErrorConstructorProxy.ErrorConstructorAccessor accessor) { + ErrorConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link CallingServerErrorException} backed by an internal instance of + * {@link HttpResponseException}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link CallingServerErrorException}. + */ + public static CallingServerErrorException create(HttpResponseException internalResponse) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses CallingServerErrorException which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + try { + if (accessor == null) { + throw new CallingServerErrorException(); + } + + return accessor.create(internalResponse); + } catch (CallingServerErrorException e) { + try { + return create(internalResponse); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ListParticipantsResponseConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ListParticipantsResponseConstructorProxy.java new file mode 100644 index 0000000000000..ae468531115d3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/ListParticipantsResponseConstructorProxy.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.GetParticipantsResponseInternal; +import com.azure.communication.callautomation.models.ListParticipantsResult; + +public final class ListParticipantsResponseConstructorProxy { + private static ListParticipantsResponseConstructorProxy.ListParticipantsResponseConstructorAccessor accessor; + + private ListParticipantsResponseConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link ListParticipantsResponseConstructorProxy.ListParticipantsResponseConstructorAccessor} + * instance. + */ + public interface ListParticipantsResponseConstructorAccessor { + /** + * Creates a new instance of {@link ListParticipantsResult} backed by an internal instance of + * {@link ListParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link ListParticipantsResult}. + */ + ListParticipantsResult create(GetParticipantsResponseInternal internalResponse); + } + + /** + * The method called from {@link ListParticipantsResult} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final ListParticipantsResponseConstructorProxy.ListParticipantsResponseConstructorAccessor accessor) { + ListParticipantsResponseConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link ListParticipantsResult} backed by an internal instance of + * {@link ListParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link ListParticipantsResult}. + */ + public static ListParticipantsResult create(GetParticipantsResponseInternal internalResponse) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses BlobDownloadHeaders which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new ListParticipantsResult(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RecordingStateResponseConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RecordingStateResponseConstructorProxy.java new file mode 100644 index 0000000000000..a80293d4335d8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RecordingStateResponseConstructorProxy.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.RecordingStateResponseInternal; +import com.azure.communication.callautomation.models.RecordingStateResult; + +/** + * Helper class to access private values of {@link RecordingStateResult} across package boundaries. + */ +public final class RecordingStateResponseConstructorProxy { + private static RecordingStateResponseConstructorAccessor accessor; + + private RecordingStateResponseConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link RecordingStateResponseConstructorAccessor} + * instance. + */ + public interface RecordingStateResponseConstructorAccessor { + /** + * Creates a new instance of {@link RecordingStateResult} backed by an internal instance of + * {@link RecordingStateResponseInternal}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link RecordingStateResult}. + */ + RecordingStateResult create(RecordingStateResponseInternal internalResponse); + } + + /** + * The method called from {@link RecordingStateResult} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final RecordingStateResponseConstructorAccessor accessor) { + RecordingStateResponseConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link RecordingStateResult} backed by an internal instance of + * {@link RecordingStateResponseInternal}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link RecordingStateResult}. + */ + public static RecordingStateResult create(RecordingStateResponseInternal internalResponse) { + if (accessor == null) { + new RecordingStateResult(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RemoveParticipantsResponseConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RemoveParticipantsResponseConstructorProxy.java new file mode 100644 index 0000000000000..54da1d6f7f615 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/RemoveParticipantsResponseConstructorProxy.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsResponseInternal; +import com.azure.communication.callautomation.models.RemoveParticipantsResult; + +/** + * Helper class to access private values of {@link RemoveParticipantsResult} across package boundaries. + */ +public final class RemoveParticipantsResponseConstructorProxy { + private static RemoveParticipantsResponseConstructorAccessor accessor; + + private RemoveParticipantsResponseConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link RemoveParticipantsResponseConstructorAccessor} + * instance. + */ + public interface RemoveParticipantsResponseConstructorAccessor { + /** + * Creates a new instance of {@link RemoveParticipantsResult} backed by an internal instance of + * {@link RemoveParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link RemoveParticipantsResult}. + */ + RemoveParticipantsResult create(RemoveParticipantsResponseInternal internalResponse); + } + + /** + * The method called from {@link RemoveParticipantsResult} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final RemoveParticipantsResponseConstructorAccessor accessor) { + RemoveParticipantsResponseConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link RemoveParticipantsResult} backed by an internal instance of + * {@link RemoveParticipantsResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link RemoveParticipantsResult}. + */ + public static RemoveParticipantsResult create(RemoveParticipantsResponseInternal internalResponse) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses BlobDownloadHeaders which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new RemoveParticipantsResult(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/TransferCallResponseConstructorProxy.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/TransferCallResponseConstructorProxy.java new file mode 100644 index 0000000000000..ec7fa670397c1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/accesshelpers/TransferCallResponseConstructorProxy.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.accesshelpers; + +import com.azure.communication.callautomation.implementation.models.TransferCallResponseInternal; +import com.azure.communication.callautomation.models.TransferCallResult; + +/** + * Helper class to access private values of {@link TransferCallResult} across package boundaries. + */ +public final class TransferCallResponseConstructorProxy { + private static TransferCallResponseConstructorAccessor accessor; + + private TransferCallResponseConstructorProxy() { } + + /** + * Type defining the methods to set the non-public properties of a {@link TransferCallResponseConstructorAccessor} + * instance. + */ + public interface TransferCallResponseConstructorAccessor { + /** + * Creates a new instance of {@link TransferCallResult} backed by an internal instance of + * {@link TransferCallResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link TransferCallResult}. + */ + TransferCallResult create(TransferCallResponseInternal internalResponse); + } + + /** + * The method called from {@link TransferCallResult} to set it's accessor. + * + * @param accessor The accessor. + */ + public static void setAccessor(final TransferCallResponseConstructorAccessor accessor) { + TransferCallResponseConstructorProxy.accessor = accessor; + } + + /** + * Creates a new instance of {@link TransferCallResult} backed by an internal instance of + * {@link TransferCallResult}. + * + * @param internalResponse The internal response. + * @return A new instance of {@link TransferCallResult}. + */ + public static TransferCallResult create(TransferCallResponseInternal internalResponse) { + // This looks odd but is necessary, it is possible to engage the access helper before anywhere else in the + // application accesses BlobDownloadHeaders which triggers the accessor to be configured. So, if the accessor + // is null this effectively pokes the class to set up the accessor. + if (accessor == null) { + new TransferCallResult(); + } + + assert accessor != null; + return accessor.create(internalResponse); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallParticipantConverter.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallParticipantConverter.java new file mode 100644 index 0000000000000..5e62d09123cfd --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallParticipantConverter.java @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.converters; + +import com.azure.communication.callautomation.implementation.models.AcsCallParticipantInternal; +import com.azure.communication.callautomation.models.CallParticipant; + +/** + * A converter for {@link CallParticipant} + */ +public final class CallParticipantConverter { + + /** + * Converts to {@link CallParticipant}. + */ + public static CallParticipant convert( + AcsCallParticipantInternal acsCallParticipantDto) { + + if (acsCallParticipantDto == null) { + return null; + } + + return new CallParticipant(CommunicationIdentifierConverter.convert(acsCallParticipantDto.getIdentifier()), + acsCallParticipantDto.isMuted()); + } + + private CallParticipantConverter() { + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallSourceConverter.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallSourceConverter.java new file mode 100644 index 0000000000000..14b9eb75d07ab --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CallSourceConverter.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.converters; + +import com.azure.communication.callautomation.implementation.models.CallSourceInternal; +import com.azure.communication.callautomation.models.CallSource; + +/** + * A converter for {@link CallSource} + */ +public final class CallSourceConverter { + + /** + * Converts to {@link CallSource}. + */ + public static CallSource convert(CallSourceInternal callSourceDto) { + + if (callSourceDto == null) { + return null; + } + + return new CallSource(CommunicationIdentifierConverter.convert(callSourceDto.getIdentifier())) + .setCallerId(PhoneNumberIdentifierConverter.convert(callSourceDto.getCallerId())); + } + + /** + * Converts to {@link CallSourceInternal}. + */ + public static CallSourceInternal convert(CallSource callSource) { + + if (callSource == null) { + return null; + } + + return new CallSourceInternal() + .setIdentifier(CommunicationIdentifierConverter.convert(callSource.getIdentifier())) + .setCallerId(PhoneNumberIdentifierConverter.convert(callSource.getCallerId())); + } + + private CallSourceConverter() { + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CommunicationIdentifierConverter.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CommunicationIdentifierConverter.java new file mode 100644 index 0000000000000..9d4a60a2e1bf4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/CommunicationIdentifierConverter.java @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.converters; + +import com.azure.communication.callautomation.implementation.models.CommunicationCloudEnvironmentModel; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.callautomation.implementation.models.CommunicationUserIdentifierModel; +import com.azure.communication.callautomation.implementation.models.MicrosoftTeamsUserIdentifierModel; +import com.azure.communication.callautomation.implementation.models.PhoneNumberIdentifierModel; +import com.azure.communication.common.CommunicationCloudEnvironment; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.communication.common.MicrosoftTeamsUserIdentifier; +import com.azure.communication.common.PhoneNumberIdentifier; +import com.azure.communication.common.UnknownIdentifier; + +import java.util.ArrayList; +import java.util.Objects; +/** + * A converter between {@link CommunicationIdentifierModel} and {@link CommunicationIdentifier}. + */ +public class CommunicationIdentifierConverter { + + /** + * Maps from {@link CommunicationIdentifierModel} to {@link CommunicationIdentifier}. + */ + public static CommunicationIdentifier convert(CommunicationIdentifierModel identifier) { + if (identifier == null) { + return null; + } + + assertSingleType(identifier); + String rawId = identifier.getRawId(); + + if (identifier.getCommunicationUser() != null) { + Objects.requireNonNull(identifier.getCommunicationUser().getId()); + return new CommunicationUserIdentifier(identifier.getCommunicationUser().getId()); + } + + if (identifier.getPhoneNumber() != null) { + PhoneNumberIdentifierModel phoneNumberModel = identifier.getPhoneNumber(); + Objects.requireNonNull(phoneNumberModel.getValue()); + return new PhoneNumberIdentifier(phoneNumberModel.getValue()).setRawId(rawId); + } + + if (identifier.getMicrosoftTeamsUser() != null) { + MicrosoftTeamsUserIdentifierModel teamsUserIdentifierModel = identifier.getMicrosoftTeamsUser(); + Objects.requireNonNull(teamsUserIdentifierModel.getUserId()); + Objects.requireNonNull(teamsUserIdentifierModel.getCloud()); + Objects.requireNonNull(rawId); + return new MicrosoftTeamsUserIdentifier(teamsUserIdentifierModel.getUserId(), + teamsUserIdentifierModel.isAnonymous()) + .setRawId(rawId) + .setCloudEnvironment(CommunicationCloudEnvironment + .fromString(teamsUserIdentifierModel.getCloud().toString())); + } + + Objects.requireNonNull(rawId); + return new UnknownIdentifier(rawId); + } + + /** + * Maps from {@link CommunicationIdentifier} to {@link CommunicationIdentifierModel}. + */ + public static CommunicationIdentifierModel convert(CommunicationIdentifier identifier) + throws IllegalArgumentException { + + if (identifier == null) { + return null; + } + + if (identifier instanceof CommunicationUserIdentifier) { + CommunicationUserIdentifier communicationUserIdentifier = (CommunicationUserIdentifier) identifier; + return new CommunicationIdentifierModel() + .setRawId(communicationUserIdentifier.getRawId()) + .setCommunicationUser( + new CommunicationUserIdentifierModel().setId(communicationUserIdentifier.getId())); + } + + if (identifier instanceof PhoneNumberIdentifier) { + PhoneNumberIdentifier phoneNumberIdentifier = (PhoneNumberIdentifier) identifier; + return new CommunicationIdentifierModel() + .setRawId(phoneNumberIdentifier.getRawId()) + .setPhoneNumber(new PhoneNumberIdentifierModel().setValue(phoneNumberIdentifier.getPhoneNumber())); + } + + if (identifier instanceof MicrosoftTeamsUserIdentifier) { + MicrosoftTeamsUserIdentifier teamsUserIdentifier = (MicrosoftTeamsUserIdentifier) identifier; + return new CommunicationIdentifierModel() + .setRawId(teamsUserIdentifier.getRawId()) + .setMicrosoftTeamsUser(new MicrosoftTeamsUserIdentifierModel() + .setIsAnonymous(teamsUserIdentifier.isAnonymous()) + .setUserId(teamsUserIdentifier.getUserId()) + .setCloud(CommunicationCloudEnvironmentModel.fromString( + teamsUserIdentifier.getCloudEnvironment().toString()))); + } + + if (identifier instanceof UnknownIdentifier) { + UnknownIdentifier unknownIdentifier = (UnknownIdentifier) identifier; + return new CommunicationIdentifierModel().setRawId(unknownIdentifier.getId()); + } + + throw new IllegalArgumentException(String.format("Unknown identifier class '%s'", identifier.getClass().getName())); + } + + private static void assertSingleType(CommunicationIdentifierModel identifier) { + CommunicationUserIdentifierModel communicationUser = identifier.getCommunicationUser(); + PhoneNumberIdentifierModel phoneNumber = identifier.getPhoneNumber(); + MicrosoftTeamsUserIdentifierModel microsoftTeamsUser = identifier.getMicrosoftTeamsUser(); + + ArrayList presentProperties = new ArrayList<>(); + if (communicationUser != null) { + presentProperties.add(communicationUser.getClass().getName()); + } + if (phoneNumber != null) { + presentProperties.add(phoneNumber.getClass().getName()); + } + if (microsoftTeamsUser != null) { + presentProperties.add(microsoftTeamsUser.getClass().getName()); + } + + if (presentProperties.size() > 1) { + throw new IllegalArgumentException( + String.format( + "Only one of the identifier models in %s should be present.", + String.join(", ", presentProperties))); + } + } +} + diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/PhoneNumberIdentifierConverter.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/PhoneNumberIdentifierConverter.java new file mode 100644 index 0000000000000..ccc4d37040138 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/PhoneNumberIdentifierConverter.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.implementation.converters; + +import com.azure.communication.callautomation.implementation.models.PhoneNumberIdentifierModel; +import com.azure.communication.common.PhoneNumberIdentifier; + +/** + * A converter for {@link PhoneNumberIdentifier} and {@link PhoneNumberIdentifierModel} + */ +public final class PhoneNumberIdentifierConverter { + + /** + * Converts to {@link PhoneNumberIdentifierModel}. + */ + public static PhoneNumberIdentifierModel convert(PhoneNumberIdentifier phoneNumberIdentifier) { + + PhoneNumberIdentifierModel phoneNumberIdentifierModel = + (phoneNumberIdentifier == null || phoneNumberIdentifier.getPhoneNumber().isEmpty()) ? null + : CommunicationIdentifierConverter + .convert(new PhoneNumberIdentifier(phoneNumberIdentifier.getPhoneNumber())).getPhoneNumber(); + return phoneNumberIdentifierModel; + } + + /** + * Converts to {@link PhoneNumberIdentifier}. + */ + public static PhoneNumberIdentifier convert(PhoneNumberIdentifierModel phoneNumberIdentifierModel) { + + PhoneNumberIdentifier phoneNumberIdentifier = + (phoneNumberIdentifierModel == null || phoneNumberIdentifierModel.getValue().isEmpty()) ? null + : new PhoneNumberIdentifier(phoneNumberIdentifierModel.getValue()); + + return phoneNumberIdentifier; + } + private PhoneNumberIdentifierConverter() { + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/package-info.java new file mode 100644 index 0000000000000..b758e4b72c2c7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/converters/package-info.java @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** Package containing the implementations for AzureCommunicationCallingServerService. null. */ +package com.azure.communication.callautomation.implementation.converters; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsCallParticipantInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsCallParticipantInternal.java new file mode 100644 index 0000000000000..9cc804a5bc51b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsCallParticipantInternal.java @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The AcsCallParticipantInternal model. */ +@Fluent +public final class AcsCallParticipantInternal { + /* + * Communication identifier of the participant + */ + @JsonProperty(value = "identifier") + private CommunicationIdentifierModel identifier; + + /* + * Is participant muted + */ + @JsonProperty(value = "isMuted") + private Boolean isMuted; + + /** + * Get the identifier property: Communication identifier of the participant. + * + * @return the identifier value. + */ + public CommunicationIdentifierModel getIdentifier() { + return this.identifier; + } + + /** + * Set the identifier property: Communication identifier of the participant. + * + * @param identifier the identifier value to set. + * @return the AcsCallParticipantInternal object itself. + */ + public AcsCallParticipantInternal setIdentifier(CommunicationIdentifierModel identifier) { + this.identifier = identifier; + return this; + } + + /** + * Get the isMuted property: Is participant muted. + * + * @return the isMuted value. + */ + public Boolean isMuted() { + return this.isMuted; + } + + /** + * Set the isMuted property: Is participant muted. + * + * @param isMuted the isMuted value to set. + * @return the AcsCallParticipantInternal object itself. + */ + public AcsCallParticipantInternal setIsMuted(Boolean isMuted) { + this.isMuted = isMuted; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsEventTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsEventTypeInternal.java new file mode 100644 index 0000000000000..7964d47c7ddd9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AcsEventTypeInternal.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for AcsEventTypeInternal. */ +public final class AcsEventTypeInternal extends ExpandableStringEnum { + /** Static value unknown for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal UNKNOWN = fromString("unknown"); + + /** Static value callConnected for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal CALL_CONNECTED = fromString("callConnected"); + + /** Static value callDisconnected for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal CALL_DISCONNECTED = fromString("callDisconnected"); + + /** Static value callTransferAccepted for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal CALL_TRANSFER_ACCEPTED = fromString("callTransferAccepted"); + + /** Static value callTransferFailed for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal CALL_TRANSFER_FAILED = fromString("callTransferFailed"); + + /** Static value addParticipantsSucceeded for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal ADD_PARTICIPANTS_SUCCEEDED = fromString("addParticipantsSucceeded"); + + /** Static value addParticipantsFailed for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal ADD_PARTICIPANTS_FAILED = fromString("addParticipantsFailed"); + + /** Static value participantsUpdated for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal PARTICIPANTS_UPDATED = fromString("participantsUpdated"); + + /** Static value recordingStateChanged for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal RECORDING_STATE_CHANGED = fromString("recordingStateChanged"); + + /** Static value playCompleted for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal PLAY_COMPLETED = fromString("playCompleted"); + + /** Static value playFailed for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal PLAY_FAILED = fromString("playFailed"); + + /** Static value recognizeCompleted for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal RECOGNIZE_COMPLETED = fromString("recognizeCompleted"); + + /** Static value recognizeFailed for AcsEventTypeInternal. */ + public static final AcsEventTypeInternal RECOGNIZE_FAILED = fromString("recognizeFailed"); + + /** + * Creates or finds a AcsEventTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding AcsEventTypeInternal. + */ + @JsonCreator + public static AcsEventTypeInternal fromString(String name) { + return fromString(name, AcsEventTypeInternal.class); + } + + /** @return known AcsEventTypeInternal values. */ + public static Collection values() { + return values(AcsEventTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsRequestInternal.java new file mode 100644 index 0000000000000..865f8675ed725 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsRequestInternal.java @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The AddParticipantsRequestInternal model. */ +@Fluent +public final class AddParticipantsRequestInternal { + /* + * The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + */ + @JsonProperty(value = "sourceCallerId") + private PhoneNumberIdentifierModel sourceCallerId; + + /* + * The participants to invite. + */ + @JsonProperty(value = "participantsToAdd", required = true) + private List participantsToAdd; + + /* + * Gets or sets the timeout to wait for the invited participant to pickup. + * The maximum value of this is 180 seconds + */ + @JsonProperty(value = "invitationTimeoutInSeconds") + private Integer invitationTimeoutInSeconds; + + /* + * The operation context. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the sourceCallerId property: The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + * + * @return the sourceCallerId value. + */ + public PhoneNumberIdentifierModel getSourceCallerId() { + return this.sourceCallerId; + } + + /** + * Set the sourceCallerId property: The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + * + * @param sourceCallerId the sourceCallerId value to set. + * @return the AddParticipantsRequestInternal object itself. + */ + public AddParticipantsRequestInternal setSourceCallerId(PhoneNumberIdentifierModel sourceCallerId) { + this.sourceCallerId = sourceCallerId; + return this; + } + + /** + * Get the participantsToAdd property: The participants to invite. + * + * @return the participantsToAdd value. + */ + public List getParticipantsToAdd() { + return this.participantsToAdd; + } + + /** + * Set the participantsToAdd property: The participants to invite. + * + * @param participantsToAdd the participantsToAdd value to set. + * @return the AddParticipantsRequestInternal object itself. + */ + public AddParticipantsRequestInternal setParticipantsToAdd(List participantsToAdd) { + this.participantsToAdd = participantsToAdd; + return this; + } + + /** + * Get the invitationTimeoutInSeconds property: Gets or sets the timeout to wait for the invited participant to + * pickup. The maximum value of this is 180 seconds. + * + * @return the invitationTimeoutInSeconds value. + */ + public Integer getInvitationTimeoutInSeconds() { + return this.invitationTimeoutInSeconds; + } + + /** + * Set the invitationTimeoutInSeconds property: Gets or sets the timeout to wait for the invited participant to + * pickup. The maximum value of this is 180 seconds. + * + * @param invitationTimeoutInSeconds the invitationTimeoutInSeconds value to set. + * @return the AddParticipantsRequestInternal object itself. + */ + public AddParticipantsRequestInternal setInvitationTimeoutInSeconds(Integer invitationTimeoutInSeconds) { + this.invitationTimeoutInSeconds = invitationTimeoutInSeconds; + return this; + } + + /** + * Get the operationContext property: The operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context. + * + * @param operationContext the operationContext value to set. + * @return the AddParticipantsRequestInternal object itself. + */ + public AddParticipantsRequestInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsResponseInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsResponseInternal.java new file mode 100644 index 0000000000000..4f10da41fe521 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AddParticipantsResponseInternal.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The AddParticipantsResponseInternal model. */ +@Fluent +public final class AddParticipantsResponseInternal { + /* + * The participants property. + */ + @JsonProperty(value = "participants") + private List participants; + + /* + * The operation context provided by client. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the participants property: The participants property. + * + * @return the participants value. + */ + public List getParticipants() { + return this.participants; + } + + /** + * Set the participants property: The participants property. + * + * @param participants the participants value to set. + * @return the AddParticipantsResponseInternal object itself. + */ + public AddParticipantsResponseInternal setParticipants(List participants) { + this.participants = participants; + return this; + } + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context provided by client. + * + * @param operationContext the operationContext value to set. + * @return the AddParticipantsResponseInternal object itself. + */ + public AddParticipantsResponseInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AnswerCallRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AnswerCallRequestInternal.java new file mode 100644 index 0000000000000..48d6b50069887 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/AnswerCallRequestInternal.java @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The request payload for answering the call. */ +@Fluent +public final class AnswerCallRequestInternal { + /* + * The context associated with the call. + */ + @JsonProperty(value = "incomingCallContext", required = true) + private String incomingCallContext; + + /* + * The callback uri. + */ + @JsonProperty(value = "callbackUri") + private String callbackUri; + + /* + * Media Streaming Configuration. + */ + @JsonProperty(value = "mediaStreamingConfiguration") + private MediaStreamingConfigurationInternal mediaStreamingConfiguration; + + /** + * Get the incomingCallContext property: The context associated with the call. + * + * @return the incomingCallContext value. + */ + public String getIncomingCallContext() { + return this.incomingCallContext; + } + + /** + * Set the incomingCallContext property: The context associated with the call. + * + * @param incomingCallContext the incomingCallContext value to set. + * @return the AnswerCallRequestInternal object itself. + */ + public AnswerCallRequestInternal setIncomingCallContext(String incomingCallContext) { + this.incomingCallContext = incomingCallContext; + return this; + } + + /** + * Get the callbackUri property: The callback uri. + * + * @return the callbackUri value. + */ + public String getCallbackUri() { + return this.callbackUri; + } + + /** + * Set the callbackUri property: The callback uri. + * + * @param callbackUri the callbackUri value to set. + * @return the AnswerCallRequestInternal object itself. + */ + public AnswerCallRequestInternal setCallbackUri(String callbackUri) { + this.callbackUri = callbackUri; + return this; + } + + /** + * Get the mediaStreamingConfiguration property: Media Streaming Configuration. + * + * @return the mediaStreamingConfiguration value. + */ + public MediaStreamingConfigurationInternal getMediaStreamingConfiguration() { + return this.mediaStreamingConfiguration; + } + + /** + * Set the mediaStreamingConfiguration property: Media Streaming Configuration. + * + * @param mediaStreamingConfiguration the mediaStreamingConfiguration value to set. + * @return the AnswerCallRequestInternal object itself. + */ + public AnswerCallRequestInternal setMediaStreamingConfiguration( + MediaStreamingConfigurationInternal mediaStreamingConfiguration) { + this.mediaStreamingConfiguration = mediaStreamingConfiguration; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionPropertiesInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionPropertiesInternal.java new file mode 100644 index 0000000000000..67c2dbb4adba3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionPropertiesInternal.java @@ -0,0 +1,222 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The CallConnectionPropertiesInternal model. */ +@Fluent +public final class CallConnectionPropertiesInternal { + /* + * The call connection id. + */ + @JsonProperty(value = "callConnectionId") + private String callConnectionId; + + /* + * The server call id. + */ + @JsonProperty(value = "serverCallId") + private String serverCallId; + + /* + * The source of the call. + */ + @JsonProperty(value = "source") + private CallSourceInternal source; + + /* + * The targets of the call. + */ + @JsonProperty(value = "targets") + private List targets; + + /* + * The state of the call connection. + */ + @JsonProperty(value = "callConnectionState") + private CallConnectionStateModelInternal callConnectionState; + + /* + * The subject. + */ + @JsonProperty(value = "subject") + private String subject; + + /* + * The callback URI. + */ + @JsonProperty(value = "callbackUri") + private String callbackUri; + + /* + * SubscriptionId for media streaming + */ + @JsonProperty(value = "mediaSubscriptionId") + private String mediaSubscriptionId; + + /** + * Get the callConnectionId property: The call connection id. + * + * @return the callConnectionId value. + */ + public String getCallConnectionId() { + return this.callConnectionId; + } + + /** + * Set the callConnectionId property: The call connection id. + * + * @param callConnectionId the callConnectionId value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setCallConnectionId(String callConnectionId) { + this.callConnectionId = callConnectionId; + return this; + } + + /** + * Get the serverCallId property: The server call id. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } + + /** + * Set the serverCallId property: The server call id. + * + * @param serverCallId the serverCallId value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setServerCallId(String serverCallId) { + this.serverCallId = serverCallId; + return this; + } + + /** + * Get the source property: The source of the call. + * + * @return the source value. + */ + public CallSourceInternal getSource() { + return this.source; + } + + /** + * Set the source property: The source of the call. + * + * @param source the source value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setSource(CallSourceInternal source) { + this.source = source; + return this; + } + + /** + * Get the targets property: The targets of the call. + * + * @return the targets value. + */ + public List getTargets() { + return this.targets; + } + + /** + * Set the targets property: The targets of the call. + * + * @param targets the targets value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setTargets(List targets) { + this.targets = targets; + return this; + } + + /** + * Get the callConnectionState property: The state of the call connection. + * + * @return the callConnectionState value. + */ + public CallConnectionStateModelInternal getCallConnectionState() { + return this.callConnectionState; + } + + /** + * Set the callConnectionState property: The state of the call connection. + * + * @param callConnectionState the callConnectionState value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setCallConnectionState( + CallConnectionStateModelInternal callConnectionState) { + this.callConnectionState = callConnectionState; + return this; + } + + /** + * Get the subject property: The subject. + * + * @return the subject value. + */ + public String getSubject() { + return this.subject; + } + + /** + * Set the subject property: The subject. + * + * @param subject the subject value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setSubject(String subject) { + this.subject = subject; + return this; + } + + /** + * Get the callbackUri property: The callback URI. + * + * @return the callbackUri value. + */ + public String getCallbackUri() { + return this.callbackUri; + } + + /** + * Set the callbackUri property: The callback URI. + * + * @param callbackUri the callbackUri value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setCallbackUri(String callbackUri) { + this.callbackUri = callbackUri; + return this; + } + + /** + * Get the mediaSubscriptionId property: SubscriptionId for media streaming. + * + * @return the mediaSubscriptionId value. + */ + public String getMediaSubscriptionId() { + return this.mediaSubscriptionId; + } + + /** + * Set the mediaSubscriptionId property: SubscriptionId for media streaming. + * + * @param mediaSubscriptionId the mediaSubscriptionId value to set. + * @return the CallConnectionPropertiesInternal object itself. + */ + public CallConnectionPropertiesInternal setMediaSubscriptionId(String mediaSubscriptionId) { + this.mediaSubscriptionId = mediaSubscriptionId; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionStateModelInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionStateModelInternal.java new file mode 100644 index 0000000000000..db1e3f9b57df8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallConnectionStateModelInternal.java @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for CallConnectionStateModelInternal. */ +public final class CallConnectionStateModelInternal extends ExpandableStringEnum { + /** Static value unknown for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal UNKNOWN = fromString("unknown"); + + /** Static value connecting for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal CONNECTING = fromString("connecting"); + + /** Static value connected for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal CONNECTED = fromString("connected"); + + /** Static value transferring for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal TRANSFERRING = fromString("transferring"); + + /** Static value transferAccepted for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal TRANSFER_ACCEPTED = fromString("transferAccepted"); + + /** Static value disconnecting for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal DISCONNECTING = fromString("disconnecting"); + + /** Static value disconnected for CallConnectionStateModelInternal. */ + public static final CallConnectionStateModelInternal DISCONNECTED = fromString("disconnected"); + + /** + * Creates or finds a CallConnectionStateModelInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallConnectionStateModelInternal. + */ + @JsonCreator + public static CallConnectionStateModelInternal fromString(String name) { + return fromString(name, CallConnectionStateModelInternal.class); + } + + /** @return known CallConnectionStateModelInternal values. */ + public static Collection values() { + return values(CallConnectionStateModelInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorInternal.java new file mode 100644 index 0000000000000..847ccfe1bf766 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorInternal.java @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The locator used for joining or taking action on a call. */ +@Fluent +public final class CallLocatorInternal { + /* + * The group call id + */ + @JsonProperty(value = "groupCallId") + private String groupCallId; + + /* + * The server call id. + */ + @JsonProperty(value = "serverCallId") + private String serverCallId; + + /* + * The call locator kind. + */ + @JsonProperty(value = "kind") + private CallLocatorKindInternal kind; + + /** + * Get the groupCallId property: The group call id. + * + * @return the groupCallId value. + */ + public String getGroupCallId() { + return this.groupCallId; + } + + /** + * Set the groupCallId property: The group call id. + * + * @param groupCallId the groupCallId value to set. + * @return the CallLocatorInternal object itself. + */ + public CallLocatorInternal setGroupCallId(String groupCallId) { + this.groupCallId = groupCallId; + return this; + } + + /** + * Get the serverCallId property: The server call id. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } + + /** + * Set the serverCallId property: The server call id. + * + * @param serverCallId the serverCallId value to set. + * @return the CallLocatorInternal object itself. + */ + public CallLocatorInternal setServerCallId(String serverCallId) { + this.serverCallId = serverCallId; + return this; + } + + /** + * Get the kind property: The call locator kind. + * + * @return the kind value. + */ + public CallLocatorKindInternal getKind() { + return this.kind; + } + + /** + * Set the kind property: The call locator kind. + * + * @param kind the kind value to set. + * @return the CallLocatorInternal object itself. + */ + public CallLocatorInternal setKind(CallLocatorKindInternal kind) { + this.kind = kind; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorKindInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorKindInternal.java new file mode 100644 index 0000000000000..5e413597d6186 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallLocatorKindInternal.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for CallLocatorKindInternal. */ +public final class CallLocatorKindInternal extends ExpandableStringEnum { + /** Static value groupCallLocator for CallLocatorKindInternal. */ + public static final CallLocatorKindInternal GROUP_CALL_LOCATOR = fromString("groupCallLocator"); + + /** Static value serverCallLocator for CallLocatorKindInternal. */ + public static final CallLocatorKindInternal SERVER_CALL_LOCATOR = fromString("serverCallLocator"); + + /** + * Creates or finds a CallLocatorKindInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallLocatorKindInternal. + */ + @JsonCreator + public static CallLocatorKindInternal fromString(String name) { + return fromString(name, CallLocatorKindInternal.class); + } + + /** @return known CallLocatorKindInternal values. */ + public static Collection values() { + return values(CallLocatorKindInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallRejectReasonInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallRejectReasonInternal.java new file mode 100644 index 0000000000000..5cb7dc57aa9eb --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallRejectReasonInternal.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for CallRejectReasonInternal. */ +public final class CallRejectReasonInternal extends ExpandableStringEnum { + /** Static value none for CallRejectReasonInternal. */ + public static final CallRejectReasonInternal NONE = fromString("none"); + + /** Static value busy for CallRejectReasonInternal. */ + public static final CallRejectReasonInternal BUSY = fromString("busy"); + + /** Static value forbidden for CallRejectReasonInternal. */ + public static final CallRejectReasonInternal FORBIDDEN = fromString("forbidden"); + + /** + * Creates or finds a CallRejectReasonInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallRejectReasonInternal. + */ + @JsonCreator + public static CallRejectReasonInternal fromString(String name) { + return fromString(name, CallRejectReasonInternal.class); + } + + /** @return known CallRejectReasonInternal values. */ + public static Collection values() { + return values(CallRejectReasonInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallSourceInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallSourceInternal.java new file mode 100644 index 0000000000000..cde48ab8203c6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CallSourceInternal.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CallSourceInternal model. */ +@Fluent +public final class CallSourceInternal { + /* + * The alternate identity of the source of the call if dialing out to a + * pstn number + */ + @JsonProperty(value = "callerId") + private PhoneNumberIdentifierModel callerId; + + /* + * The identifier of the source of the call + */ + @JsonProperty(value = "identifier", required = true) + private CommunicationIdentifierModel identifier; + + /** + * Get the callerId property: The alternate identity of the source of the call if dialing out to a pstn number. + * + * @return the callerId value. + */ + public PhoneNumberIdentifierModel getCallerId() { + return this.callerId; + } + + /** + * Set the callerId property: The alternate identity of the source of the call if dialing out to a pstn number. + * + * @param callerId the callerId value to set. + * @return the CallSourceInternal object itself. + */ + public CallSourceInternal setCallerId(PhoneNumberIdentifierModel callerId) { + this.callerId = callerId; + return this; + } + + /** + * Get the identifier property: The identifier of the source of the call. + * + * @return the identifier value. + */ + public CommunicationIdentifierModel getIdentifier() { + return this.identifier; + } + + /** + * Set the identifier property: The identifier of the source of the call. + * + * @param identifier the identifier value to set. + * @return the CallSourceInternal object itself. + */ + public CallSourceInternal setIdentifier(CommunicationIdentifierModel identifier) { + this.identifier = identifier; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ChannelAffinityInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ChannelAffinityInternal.java new file mode 100644 index 0000000000000..9f1acf86df669 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ChannelAffinityInternal.java @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** Channel affinity for a participant. */ +@Fluent +public final class ChannelAffinityInternal { + /* + * Channel number to which bitstream from a particular participant will be + * written. + */ + @JsonProperty(value = "channel") + private Integer channel; + + /* + * The identifier for the participant whose bitstream will be written to + * the channel + * represented by the channel number. + */ + @JsonProperty(value = "participant") + private CommunicationIdentifierModel participant; + + /** + * Get the channel property: Channel number to which bitstream from a particular participant will be written. + * + * @return the channel value. + */ + public Integer getChannel() { + return this.channel; + } + + /** + * Set the channel property: Channel number to which bitstream from a particular participant will be written. + * + * @param channel the channel value to set. + * @return the ChannelAffinityInternal object itself. + */ + public ChannelAffinityInternal setChannel(Integer channel) { + this.channel = channel; + return this; + } + + /** + * Get the participant property: The identifier for the participant whose bitstream will be written to the channel + * represented by the channel number. + * + * @return the participant value. + */ + public CommunicationIdentifierModel getParticipant() { + return this.participant; + } + + /** + * Set the participant property: The identifier for the participant whose bitstream will be written to the channel + * represented by the channel number. + * + * @param participant the participant value to set. + * @return the ChannelAffinityInternal object itself. + */ + public ChannelAffinityInternal setParticipant(CommunicationIdentifierModel participant) { + this.participant = participant; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CollectTonesResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CollectTonesResult.java new file mode 100644 index 0000000000000..9b9cbf6608d2d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CollectTonesResult.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The CollectTonesResult model. */ +@Fluent +public final class CollectTonesResult { + /* + * The tones property. + */ + @JsonProperty(value = "tones") + private List tones; + + /** + * Get the tones property: The tones property. + * + * @return the tones value. + */ + public List getTones() { + return this.tones; + } + + /** + * Set the tones property: The tones property. + * + * @param tones the tones value to set. + * @return the CollectTonesResult object itself. + */ + public CollectTonesResult setTones(List tones) { + this.tones = tones; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationCloudEnvironmentModel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationCloudEnvironmentModel.java new file mode 100644 index 0000000000000..07a1b2042c1cb --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationCloudEnvironmentModel.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for CommunicationCloudEnvironmentModel. */ +public final class CommunicationCloudEnvironmentModel extends ExpandableStringEnum { + /** Static value public for CommunicationCloudEnvironmentModel. */ + public static final CommunicationCloudEnvironmentModel PUBLIC = fromString("public"); + + /** Static value dod for CommunicationCloudEnvironmentModel. */ + public static final CommunicationCloudEnvironmentModel DOD = fromString("dod"); + + /** Static value gcch for CommunicationCloudEnvironmentModel. */ + public static final CommunicationCloudEnvironmentModel GCCH = fromString("gcch"); + + /** + * Creates or finds a CommunicationCloudEnvironmentModel from its string representation. + * + * @param name a name to look for. + * @return the corresponding CommunicationCloudEnvironmentModel. + */ + @JsonCreator + public static CommunicationCloudEnvironmentModel fromString(String name) { + return fromString(name, CommunicationCloudEnvironmentModel.class); + } + + /** @return known CommunicationCloudEnvironmentModel values. */ + public static Collection values() { + return values(CommunicationCloudEnvironmentModel.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationError.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationError.java new file mode 100644 index 0000000000000..807674c111298 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationError.java @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The CommunicationError model. */ +@Fluent +public final class CommunicationError { + /* + * The code property. + */ + @JsonProperty(value = "code") + private String code; + + /* + * The message property. + */ + @JsonProperty(value = "message") + private String message; + + /* + * The target property. + */ + @JsonProperty(value = "target") + private String target; + + /* + * The details property. + */ + @JsonProperty(value = "details") + private List details; + + /* + * The innererror property. + */ + @JsonProperty(value = "innererror") + private CommunicationError innererror; + + /** + * Get the code property: The code property. + * + * @return the code value. + */ + public String getCode() { + return this.code; + } + + /** + * Set the code property: The code property. + * + * @param code the code value to set. + * @return the CommunicationError object itself. + */ + public CommunicationError setCode(String code) { + this.code = code; + return this; + } + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String getMessage() { + return this.message; + } + + /** + * Set the message property: The message property. + * + * @param message the message value to set. + * @return the CommunicationError object itself. + */ + public CommunicationError setMessage(String message) { + this.message = message; + return this; + } + + /** + * Get the target property: The target property. + * + * @return the target value. + */ + public String getTarget() { + return this.target; + } + + /** + * Set the target property: The target property. + * + * @param target the target value to set. + * @return the CommunicationError object itself. + */ + public CommunicationError setTarget(String target) { + this.target = target; + return this; + } + + /** + * Get the details property: The details property. + * + * @return the details value. + */ + public List getDetails() { + return this.details; + } + + /** + * Set the details property: The details property. + * + * @param details the details value to set. + * @return the CommunicationError object itself. + */ + public CommunicationError setDetails(List details) { + this.details = details; + return this; + } + + /** + * Get the innererror property: The innererror property. + * + * @return the innererror value. + */ + public CommunicationError getInnererror() { + return this.innererror; + } + + /** + * Set the innererror property: The innererror property. + * + * @param innererror the innererror value to set. + * @return the CommunicationError object itself. + */ + public CommunicationError setInnererror(CommunicationError innererror) { + this.innererror = innererror; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationErrorResponse.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationErrorResponse.java new file mode 100644 index 0000000000000..2508630f6ed42 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationErrorResponse.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The Communication Services error response. */ +@Fluent +public final class CommunicationErrorResponse { + /* + * The error property. + */ + @JsonProperty(value = "error", required = true) + private CommunicationError error; + + /** + * Get the error property: The error property. + * + * @return the error value. + */ + public CommunicationError getError() { + return this.error; + } + + /** + * Set the error property: The error property. + * + * @param error the error value to set. + * @return the CommunicationErrorResponse object itself. + */ + public CommunicationErrorResponse setError(CommunicationError error) { + this.error = error; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModel.java new file mode 100644 index 0000000000000..92e57fdbf6b82 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModel.java @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CommunicationIdentifierModel model. */ +@Fluent +public final class CommunicationIdentifierModel { + /* + * Full ID of the identifier. + */ + @JsonProperty(value = "rawId") + private String rawId; + + /* + * Type of CommunicationIdentifierModel. + */ + @JsonProperty(value = "kind") + private CommunicationIdentifierModelKind kind; + + /* + * The communication user. + */ + @JsonProperty(value = "communicationUser") + private CommunicationUserIdentifierModel communicationUser; + + /* + * The phone number. + */ + @JsonProperty(value = "phoneNumber") + private PhoneNumberIdentifierModel phoneNumber; + + /* + * The Microsoft Teams user. + */ + @JsonProperty(value = "microsoftTeamsUser") + private MicrosoftTeamsUserIdentifierModel microsoftTeamsUser; + + /** + * Get the rawId property: Full ID of the identifier. + * + * @return the rawId value. + */ + public String getRawId() { + return this.rawId; + } + + /** + * Set the rawId property: Full ID of the identifier. + * + * @param rawId the rawId value to set. + * @return the CommunicationIdentifierModel object itself. + */ + public CommunicationIdentifierModel setRawId(String rawId) { + this.rawId = rawId; + return this; + } + + /** + * Get the kind property: Type of CommunicationIdentifierModel. + * + * @return the kind value. + */ + public CommunicationIdentifierModelKind getKind() { + return this.kind; + } + + /** + * Set the kind property: Type of CommunicationIdentifierModel. + * + * @param kind the kind value to set. + * @return the CommunicationIdentifierModel object itself. + */ + public CommunicationIdentifierModel setKind(CommunicationIdentifierModelKind kind) { + this.kind = kind; + return this; + } + + /** + * Get the communicationUser property: The communication user. + * + * @return the communicationUser value. + */ + public CommunicationUserIdentifierModel getCommunicationUser() { + return this.communicationUser; + } + + /** + * Set the communicationUser property: The communication user. + * + * @param communicationUser the communicationUser value to set. + * @return the CommunicationIdentifierModel object itself. + */ + public CommunicationIdentifierModel setCommunicationUser(CommunicationUserIdentifierModel communicationUser) { + this.communicationUser = communicationUser; + return this; + } + + /** + * Get the phoneNumber property: The phone number. + * + * @return the phoneNumber value. + */ + public PhoneNumberIdentifierModel getPhoneNumber() { + return this.phoneNumber; + } + + /** + * Set the phoneNumber property: The phone number. + * + * @param phoneNumber the phoneNumber value to set. + * @return the CommunicationIdentifierModel object itself. + */ + public CommunicationIdentifierModel setPhoneNumber(PhoneNumberIdentifierModel phoneNumber) { + this.phoneNumber = phoneNumber; + return this; + } + + /** + * Get the microsoftTeamsUser property: The Microsoft Teams user. + * + * @return the microsoftTeamsUser value. + */ + public MicrosoftTeamsUserIdentifierModel getMicrosoftTeamsUser() { + return this.microsoftTeamsUser; + } + + /** + * Set the microsoftTeamsUser property: The Microsoft Teams user. + * + * @param microsoftTeamsUser the microsoftTeamsUser value to set. + * @return the CommunicationIdentifierModel object itself. + */ + public CommunicationIdentifierModel setMicrosoftTeamsUser(MicrosoftTeamsUserIdentifierModel microsoftTeamsUser) { + this.microsoftTeamsUser = microsoftTeamsUser; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModelKind.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModelKind.java new file mode 100644 index 0000000000000..dd31e3047e264 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationIdentifierModelKind.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for CommunicationIdentifierModelKind. */ +public final class CommunicationIdentifierModelKind extends ExpandableStringEnum { + /** Static value unknown for CommunicationIdentifierModelKind. */ + public static final CommunicationIdentifierModelKind UNKNOWN = fromString("unknown"); + + /** Static value communicationUser for CommunicationIdentifierModelKind. */ + public static final CommunicationIdentifierModelKind COMMUNICATION_USER = fromString("communicationUser"); + + /** Static value phoneNumber for CommunicationIdentifierModelKind. */ + public static final CommunicationIdentifierModelKind PHONE_NUMBER = fromString("phoneNumber"); + + /** Static value microsoftTeamsUser for CommunicationIdentifierModelKind. */ + public static final CommunicationIdentifierModelKind MICROSOFT_TEAMS_USER = fromString("microsoftTeamsUser"); + + /** + * Creates or finds a CommunicationIdentifierModelKind from its string representation. + * + * @param name a name to look for. + * @return the corresponding CommunicationIdentifierModelKind. + */ + @JsonCreator + public static CommunicationIdentifierModelKind fromString(String name) { + return fromString(name, CommunicationIdentifierModelKind.class); + } + + /** @return known CommunicationIdentifierModelKind values. */ + public static Collection values() { + return values(CommunicationIdentifierModelKind.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationUserIdentifierModel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationUserIdentifierModel.java new file mode 100644 index 0000000000000..815e59517afff --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CommunicationUserIdentifierModel.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CommunicationUserIdentifierModel model. */ +@Fluent +public final class CommunicationUserIdentifierModel { + /* + * The id property. + */ + @JsonProperty(value = "id") + private String id; + + /** + * Get the id property: The id property. + * + * @return the id value. + */ + public String getId() { + return this.id; + } + + /** + * Set the id property: The id property. + * + * @param id the id value to set. + * @return the CommunicationUserIdentifierModel object itself. + */ + public CommunicationUserIdentifierModel setId(String id) { + this.id = id; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CreateCallRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CreateCallRequestInternal.java new file mode 100644 index 0000000000000..73c89e14e46b3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/CreateCallRequestInternal.java @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The CreateCallRequestInternal model. */ +@Fluent +public final class CreateCallRequestInternal { + /* + * The targets of the call. + */ + @JsonProperty(value = "targets", required = true) + private List targets; + + /* + * The source of the call. + */ + @JsonProperty(value = "source", required = true) + private CallSourceInternal source; + + /* + * The subject. + */ + @JsonProperty(value = "subject") + private String subject; + + /* + * The callback URI. + */ + @JsonProperty(value = "callbackUri", required = true) + private String callbackUri; + + /* + * Media Streaming Configuration. + */ + @JsonProperty(value = "mediaStreamingConfiguration") + private MediaStreamingConfigurationInternal mediaStreamingConfiguration; + + /** + * Get the targets property: The targets of the call. + * + * @return the targets value. + */ + public List getTargets() { + return this.targets; + } + + /** + * Set the targets property: The targets of the call. + * + * @param targets the targets value to set. + * @return the CreateCallRequestInternal object itself. + */ + public CreateCallRequestInternal setTargets(List targets) { + this.targets = targets; + return this; + } + + /** + * Get the source property: The source of the call. + * + * @return the source value. + */ + public CallSourceInternal getSource() { + return this.source; + } + + /** + * Set the source property: The source of the call. + * + * @param source the source value to set. + * @return the CreateCallRequestInternal object itself. + */ + public CreateCallRequestInternal setSource(CallSourceInternal source) { + this.source = source; + return this; + } + + /** + * Get the subject property: The subject. + * + * @return the subject value. + */ + public String getSubject() { + return this.subject; + } + + /** + * Set the subject property: The subject. + * + * @param subject the subject value to set. + * @return the CreateCallRequestInternal object itself. + */ + public CreateCallRequestInternal setSubject(String subject) { + this.subject = subject; + return this; + } + + /** + * Get the callbackUri property: The callback URI. + * + * @return the callbackUri value. + */ + public String getCallbackUri() { + return this.callbackUri; + } + + /** + * Set the callbackUri property: The callback URI. + * + * @param callbackUri the callbackUri value to set. + * @return the CreateCallRequestInternal object itself. + */ + public CreateCallRequestInternal setCallbackUri(String callbackUri) { + this.callbackUri = callbackUri; + return this; + } + + /** + * Get the mediaStreamingConfiguration property: Media Streaming Configuration. + * + * @return the mediaStreamingConfiguration value. + */ + public MediaStreamingConfigurationInternal getMediaStreamingConfiguration() { + return this.mediaStreamingConfiguration; + } + + /** + * Set the mediaStreamingConfiguration property: Media Streaming Configuration. + * + * @param mediaStreamingConfiguration the mediaStreamingConfiguration value to set. + * @return the CreateCallRequestInternal object itself. + */ + public CreateCallRequestInternal setMediaStreamingConfiguration( + MediaStreamingConfigurationInternal mediaStreamingConfiguration) { + this.mediaStreamingConfiguration = mediaStreamingConfiguration; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/DtmfConfigurationsInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/DtmfConfigurationsInternal.java new file mode 100644 index 0000000000000..1a4c9faf9a306 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/DtmfConfigurationsInternal.java @@ -0,0 +1,91 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** Options for DTMF recognition. */ +@Fluent +public final class DtmfConfigurationsInternal { + /* + * Time to wait between DTMF inputs to stop recognizing. + */ + @JsonProperty(value = "interToneTimeoutInSeconds") + private Integer interToneTimeoutInSeconds; + + /* + * Maximum number of DTMFs to be collected. + */ + @JsonProperty(value = "maxTonesToCollect") + private Integer maxTonesToCollect; + + /* + * List of tones that will stop recognizing. + */ + @JsonProperty(value = "stopTones") + private List stopTones; + + /** + * Get the interToneTimeoutInSeconds property: Time to wait between DTMF inputs to stop recognizing. + * + * @return the interToneTimeoutInSeconds value. + */ + public Integer getInterToneTimeoutInSeconds() { + return this.interToneTimeoutInSeconds; + } + + /** + * Set the interToneTimeoutInSeconds property: Time to wait between DTMF inputs to stop recognizing. + * + * @param interToneTimeoutInSeconds the interToneTimeoutInSeconds value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurationsInternal setInterToneTimeoutInSeconds(Integer interToneTimeoutInSeconds) { + this.interToneTimeoutInSeconds = interToneTimeoutInSeconds; + return this; + } + + /** + * Get the maxTonesToCollect property: Maximum number of DTMFs to be collected. + * + * @return the maxTonesToCollect value. + */ + public Integer getMaxTonesToCollect() { + return this.maxTonesToCollect; + } + + /** + * Set the maxTonesToCollect property: Maximum number of DTMFs to be collected. + * + * @param maxTonesToCollect the maxTonesToCollect value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurationsInternal setMaxTonesToCollect(Integer maxTonesToCollect) { + this.maxTonesToCollect = maxTonesToCollect; + return this; + } + + /** + * Get the stopTones property: List of tones that will stop recognizing. + * + * @return the stopTones value. + */ + public List getStopTones() { + return this.stopTones; + } + + /** + * Set the stopTones property: List of tones that will stop recognizing. + * + * @param stopTones the stopTones value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurationsInternal setStopTones(List stopTones) { + this.stopTones = stopTones; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/FileSourceInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/FileSourceInternal.java new file mode 100644 index 0000000000000..e59e9464a3b20 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/FileSourceInternal.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The FileSourceInternal model. */ +@Fluent +public final class FileSourceInternal { + /* + * Uri for the audio file to be played + */ + @JsonProperty(value = "uri", required = true) + private String uri; + + /** + * Get the uri property: Uri for the audio file to be played. + * + * @return the uri value. + */ + public String getUri() { + return this.uri; + } + + /** + * Set the uri property: Uri for the audio file to be played. + * + * @param uri the uri value to set. + * @return the FileSourceInternal object itself. + */ + public FileSourceInternal setUri(String uri) { + this.uri = uri; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/GetParticipantsResponseInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/GetParticipantsResponseInternal.java new file mode 100644 index 0000000000000..383f2a6cb0f68 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/GetParticipantsResponseInternal.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The GetParticipantsResponseInternal model. */ +@Fluent +public final class GetParticipantsResponseInternal { + /* + * The values property. + */ + @JsonProperty(value = "values") + private List values; + + /* + * The nextLink property. + */ + @JsonProperty(value = "nextLink") + private String nextLink; + + /** + * Get the values property: The values property. + * + * @return the values value. + */ + public List getValues() { + return this.values; + } + + /** + * Set the values property: The values property. + * + * @param values the values value to set. + * @return the GetParticipantsResponseInternal object itself. + */ + public GetParticipantsResponseInternal setValues(List values) { + this.values = values; + return this; + } + + /** + * Get the nextLink property: The nextLink property. + * + * @return the nextLink value. + */ + public String getNextLink() { + return this.nextLink; + } + + /** + * Set the nextLink property: The nextLink property. + * + * @param nextLink the nextLink value to set. + * @return the GetParticipantsResponseInternal object itself. + */ + public GetParticipantsResponseInternal setNextLink(String nextLink) { + this.nextLink = nextLink; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingAudioChannelTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingAudioChannelTypeInternal.java new file mode 100644 index 0000000000000..f953410cea3b7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingAudioChannelTypeInternal.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingAudioChannelTypeInternal. */ +public final class MediaStreamingAudioChannelTypeInternal + extends ExpandableStringEnum { + /** Static value mixed for MediaStreamingAudioChannelTypeInternal. */ + public static final MediaStreamingAudioChannelTypeInternal MIXED = fromString("mixed"); + + /** Static value unmixed for MediaStreamingAudioChannelTypeInternal. */ + public static final MediaStreamingAudioChannelTypeInternal UNMIXED = fromString("unmixed"); + + /** + * Creates or finds a MediaStreamingAudioChannelTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingAudioChannelTypeInternal. + */ + @JsonCreator + public static MediaStreamingAudioChannelTypeInternal fromString(String name) { + return fromString(name, MediaStreamingAudioChannelTypeInternal.class); + } + + /** @return known MediaStreamingAudioChannelTypeInternal values. */ + public static Collection values() { + return values(MediaStreamingAudioChannelTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingConfigurationInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingConfigurationInternal.java new file mode 100644 index 0000000000000..8511b11d5dec0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingConfigurationInternal.java @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The MediaStreamingConfigurationInternal model. */ +@Fluent +public final class MediaStreamingConfigurationInternal { + /* + * Transport URL for media streaming + */ + @JsonProperty(value = "transportUrl", required = true) + private String transportUrl; + + /* + * The type of tranport to be used for media streaming, eg. Websocket + */ + @JsonProperty(value = "transportType", required = true) + private MediaStreamingTransportTypeInternal transportType; + + /* + * Content type to stream, eg. audio, audio/video + */ + @JsonProperty(value = "contentType", required = true) + private MediaStreamingContentTypeInternal contentType; + + /* + * Audio channel type to stream, eg. unmixed audio, mixed audio + */ + @JsonProperty(value = "audioChannelType", required = true) + private MediaStreamingAudioChannelTypeInternal audioChannelType; + + /** + * Get the transportUrl property: Transport URL for media streaming. + * + * @return the transportUrl value. + */ + public String getTransportUrl() { + return this.transportUrl; + } + + /** + * Set the transportUrl property: Transport URL for media streaming. + * + * @param transportUrl the transportUrl value to set. + * @return the MediaStreamingConfigurationInternal object itself. + */ + public MediaStreamingConfigurationInternal setTransportUrl(String transportUrl) { + this.transportUrl = transportUrl; + return this; + } + + /** + * Get the transportType property: The type of tranport to be used for media streaming, eg. Websocket. + * + * @return the transportType value. + */ + public MediaStreamingTransportTypeInternal getTransportType() { + return this.transportType; + } + + /** + * Set the transportType property: The type of tranport to be used for media streaming, eg. Websocket. + * + * @param transportType the transportType value to set. + * @return the MediaStreamingConfigurationInternal object itself. + */ + public MediaStreamingConfigurationInternal setTransportType(MediaStreamingTransportTypeInternal transportType) { + this.transportType = transportType; + return this; + } + + /** + * Get the contentType property: Content type to stream, eg. audio, audio/video. + * + * @return the contentType value. + */ + public MediaStreamingContentTypeInternal getContentType() { + return this.contentType; + } + + /** + * Set the contentType property: Content type to stream, eg. audio, audio/video. + * + * @param contentType the contentType value to set. + * @return the MediaStreamingConfigurationInternal object itself. + */ + public MediaStreamingConfigurationInternal setContentType(MediaStreamingContentTypeInternal contentType) { + this.contentType = contentType; + return this; + } + + /** + * Get the audioChannelType property: Audio channel type to stream, eg. unmixed audio, mixed audio. + * + * @return the audioChannelType value. + */ + public MediaStreamingAudioChannelTypeInternal getAudioChannelType() { + return this.audioChannelType; + } + + /** + * Set the audioChannelType property: Audio channel type to stream, eg. unmixed audio, mixed audio. + * + * @param audioChannelType the audioChannelType value to set. + * @return the MediaStreamingConfigurationInternal object itself. + */ + public MediaStreamingConfigurationInternal setAudioChannelType( + MediaStreamingAudioChannelTypeInternal audioChannelType) { + this.audioChannelType = audioChannelType; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingContentTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingContentTypeInternal.java new file mode 100644 index 0000000000000..1554ea125e581 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingContentTypeInternal.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingContentTypeInternal. */ +public final class MediaStreamingContentTypeInternal extends ExpandableStringEnum { + /** Static value audio for MediaStreamingContentTypeInternal. */ + public static final MediaStreamingContentTypeInternal AUDIO = fromString("audio"); + + /** + * Creates or finds a MediaStreamingContentTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingContentTypeInternal. + */ + @JsonCreator + public static MediaStreamingContentTypeInternal fromString(String name) { + return fromString(name, MediaStreamingContentTypeInternal.class); + } + + /** @return known MediaStreamingContentTypeInternal values. */ + public static Collection values() { + return values(MediaStreamingContentTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingTransportTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingTransportTypeInternal.java new file mode 100644 index 0000000000000..4bad8f6a8d5ca --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MediaStreamingTransportTypeInternal.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingTransportTypeInternal. */ +public final class MediaStreamingTransportTypeInternal + extends ExpandableStringEnum { + /** Static value websocket for MediaStreamingTransportTypeInternal. */ + public static final MediaStreamingTransportTypeInternal WEBSOCKET = fromString("websocket"); + + /** + * Creates or finds a MediaStreamingTransportTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingTransportTypeInternal. + */ + @JsonCreator + public static MediaStreamingTransportTypeInternal fromString(String name) { + return fromString(name, MediaStreamingTransportTypeInternal.class); + } + + /** @return known MediaStreamingTransportTypeInternal values. */ + public static Collection values() { + return values(MediaStreamingTransportTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MicrosoftTeamsUserIdentifierModel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MicrosoftTeamsUserIdentifierModel.java new file mode 100644 index 0000000000000..d54e41c3a280c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/MicrosoftTeamsUserIdentifierModel.java @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The MicrosoftTeamsUserIdentifierModel model. */ +@Fluent +public final class MicrosoftTeamsUserIdentifierModel { + /* + * The userId property. + */ + @JsonProperty(value = "userId", required = true) + private String userId; + + /* + * The isAnonymous property. + */ + @JsonProperty(value = "isAnonymous") + private Boolean isAnonymous; + + /* + * The cloud property. + */ + @JsonProperty(value = "cloud") + private CommunicationCloudEnvironmentModel cloud; + + /** + * Get the userId property: The userId property. + * + * @return the userId value. + */ + public String getUserId() { + return this.userId; + } + + /** + * Set the userId property: The userId property. + * + * @param userId the userId value to set. + * @return the MicrosoftTeamsUserIdentifierModel object itself. + */ + public MicrosoftTeamsUserIdentifierModel setUserId(String userId) { + this.userId = userId; + return this; + } + + /** + * Get the isAnonymous property: The isAnonymous property. + * + * @return the isAnonymous value. + */ + public Boolean isAnonymous() { + return this.isAnonymous; + } + + /** + * Set the isAnonymous property: The isAnonymous property. + * + * @param isAnonymous the isAnonymous value to set. + * @return the MicrosoftTeamsUserIdentifierModel object itself. + */ + public MicrosoftTeamsUserIdentifierModel setIsAnonymous(Boolean isAnonymous) { + this.isAnonymous = isAnonymous; + return this; + } + + /** + * Get the cloud property: The cloud property. + * + * @return the cloud value. + */ + public CommunicationCloudEnvironmentModel getCloud() { + return this.cloud; + } + + /** + * Set the cloud property: The cloud property. + * + * @param cloud the cloud value to set. + * @return the MicrosoftTeamsUserIdentifierModel object itself. + */ + public MicrosoftTeamsUserIdentifierModel setCloud(CommunicationCloudEnvironmentModel cloud) { + this.cloud = cloud; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PhoneNumberIdentifierModel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PhoneNumberIdentifierModel.java new file mode 100644 index 0000000000000..deaf684d936a1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PhoneNumberIdentifierModel.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PhoneNumberIdentifierModel model. */ +@Fluent +public final class PhoneNumberIdentifierModel { + /* + * The value property. + */ + @JsonProperty(value = "value") + private String value; + + /** + * Get the value property: The value property. + * + * @return the value value. + */ + public String getValue() { + return this.value; + } + + /** + * Set the value property: The value property. + * + * @param value the value value to set. + * @return the PhoneNumberIdentifierModel object itself. + */ + public PhoneNumberIdentifierModel setValue(String value) { + this.value = value; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayOptionsInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayOptionsInternal.java new file mode 100644 index 0000000000000..60b1f526769e9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayOptionsInternal.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PlayOptionsInternal model. */ +@Fluent +public final class PlayOptionsInternal { + /* + * The option to play the provided audio source in loop when set to true + */ + @JsonProperty(value = "loop", required = true) + private boolean loop; + + /** + * Get the loop property: The option to play the provided audio source in loop when set to true. + * + * @return the loop value. + */ + public boolean isLoop() { + return this.loop; + } + + /** + * Set the loop property: The option to play the provided audio source in loop when set to true. + * + * @param loop the loop value to set. + * @return the PlayOptionsInternal object itself. + */ + public PlayOptionsInternal setLoop(boolean loop) { + this.loop = loop; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayRequest.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayRequest.java new file mode 100644 index 0000000000000..6c2efe31d7fde --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlayRequest.java @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The PlayRequest model. */ +@Fluent +public final class PlayRequest { + /* + * The source of the audio to be played. + */ + @JsonProperty(value = "playSourceInfo", required = true) + private PlaySourceInternal playSourceInfo; + + /* + * The list of call participants play provided audio to. + * Plays to everyone in the call when not provided. + */ + @JsonProperty(value = "playTo") + private List playTo; + + /* + * Defines options for playing the audio. + */ + @JsonProperty(value = "playOptions") + private PlayOptionsInternal playOptions; + + /* + * The value to identify context of the operation. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the playSourceInfo property: The source of the audio to be played. + * + * @return the playSourceInfo value. + */ + public PlaySourceInternal getPlaySourceInfo() { + return this.playSourceInfo; + } + + /** + * Set the playSourceInfo property: The source of the audio to be played. + * + * @param playSourceInfo the playSourceInfo value to set. + * @return the PlayRequest object itself. + */ + public PlayRequest setPlaySourceInfo(PlaySourceInternal playSourceInfo) { + this.playSourceInfo = playSourceInfo; + return this; + } + + /** + * Get the playTo property: The list of call participants play provided audio to. Plays to everyone in the call when + * not provided. + * + * @return the playTo value. + */ + public List getPlayTo() { + return this.playTo; + } + + /** + * Set the playTo property: The list of call participants play provided audio to. Plays to everyone in the call when + * not provided. + * + * @param playTo the playTo value to set. + * @return the PlayRequest object itself. + */ + public PlayRequest setPlayTo(List playTo) { + this.playTo = playTo; + return this; + } + + /** + * Get the playOptions property: Defines options for playing the audio. + * + * @return the playOptions value. + */ + public PlayOptionsInternal getPlayOptions() { + return this.playOptions; + } + + /** + * Set the playOptions property: Defines options for playing the audio. + * + * @param playOptions the playOptions value to set. + * @return the PlayRequest object itself. + */ + public PlayRequest setPlayOptions(PlayOptionsInternal playOptions) { + this.playOptions = playOptions; + return this; + } + + /** + * Get the operationContext property: The value to identify context of the operation. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The value to identify context of the operation. + * + * @param operationContext the operationContext value to set. + * @return the PlayRequest object itself. + */ + public PlayRequest setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceInternal.java new file mode 100644 index 0000000000000..47a223e8ab5a5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceInternal.java @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PlaySourceInternal model. */ +@Fluent +public final class PlaySourceInternal { + /* + * Defines the type of the play source + */ + @JsonProperty(value = "sourceType", required = true) + private PlaySourceTypeInternal sourceType; + + /* + * Defines the identifier to be used for caching related media + */ + @JsonProperty(value = "playSourceId") + private String playSourceId; + + /* + * Defines the file source info to be used for play + */ + @JsonProperty(value = "fileSource") + private FileSourceInternal fileSource; + + /** + * Get the sourceType property: Defines the type of the play source. + * + * @return the sourceType value. + */ + public PlaySourceTypeInternal getSourceType() { + return this.sourceType; + } + + /** + * Set the sourceType property: Defines the type of the play source. + * + * @param sourceType the sourceType value to set. + * @return the PlaySourceInternal object itself. + */ + public PlaySourceInternal setSourceType(PlaySourceTypeInternal sourceType) { + this.sourceType = sourceType; + return this; + } + + /** + * Get the playSourceId property: Defines the identifier to be used for caching related media. + * + * @return the playSourceId value. + */ + public String getPlaySourceId() { + return this.playSourceId; + } + + /** + * Set the playSourceId property: Defines the identifier to be used for caching related media. + * + * @param playSourceId the playSourceId value to set. + * @return the PlaySourceInternal object itself. + */ + public PlaySourceInternal setPlaySourceId(String playSourceId) { + this.playSourceId = playSourceId; + return this; + } + + /** + * Get the fileSource property: Defines the file source info to be used for play. + * + * @return the fileSource value. + */ + public FileSourceInternal getFileSource() { + return this.fileSource; + } + + /** + * Set the fileSource property: Defines the file source info to be used for play. + * + * @param fileSource the fileSource value to set. + * @return the PlaySourceInternal object itself. + */ + public PlaySourceInternal setFileSource(FileSourceInternal fileSource) { + this.fileSource = fileSource; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceTypeInternal.java new file mode 100644 index 0000000000000..e3b920812b911 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/PlaySourceTypeInternal.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for PlaySourceTypeInternal. */ +public final class PlaySourceTypeInternal extends ExpandableStringEnum { + /** Static value file for PlaySourceTypeInternal. */ + public static final PlaySourceTypeInternal FILE = fromString("file"); + + /** + * Creates or finds a PlaySourceTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding PlaySourceTypeInternal. + */ + @JsonCreator + public static PlaySourceTypeInternal fromString(String name) { + return fromString(name, PlaySourceTypeInternal.class); + } + + /** @return known PlaySourceTypeInternal values. */ + public static Collection values() { + return values(PlaySourceTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognitionType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognitionType.java new file mode 100644 index 0000000000000..e4a5e38e98c14 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognitionType.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecognitionType. */ +public final class RecognitionType extends ExpandableStringEnum { + /** Static value dtmf for RecognitionType. */ + public static final RecognitionType DTMF = fromString("dtmf"); + + /** + * Creates or finds a RecognitionType from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecognitionType. + */ + @JsonCreator + public static RecognitionType fromString(String name) { + return fromString(name, RecognitionType.class); + } + + /** @return known RecognitionType values. */ + public static Collection values() { + return values(RecognitionType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeCompleted.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeCompleted.java new file mode 100644 index 0000000000000..dd01022264adb --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeCompleted.java @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RecognizeCompleted model. */ +@Fluent +public final class RecognizeCompleted { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /* + * Determines the sub-type pf the recognize operation + */ + @JsonProperty(value = "recognitionType") + private RecognitionType recognitionType; + + /* + * Defines the result for RecognitionType = Dtmf + */ + @JsonProperty(value = "collectTonesResult") + private CollectTonesResult collectTonesResult; + + /* + * Defines the code, sub-code and message for the operation + */ + @JsonProperty(value = "resultInfo") + private ResultInformation resultInfo; + + /* + * The type property. + */ + @JsonProperty(value = "type") + private AcsEventTypeInternal type; + + /* + * Call connection ID. + */ + @JsonProperty(value = "callConnectionId") + private String callConnectionId; + + /* + * Server call ID. + */ + @JsonProperty(value = "serverCallId") + private String serverCallId; + + /* + * Correlation ID for event to call correlation. Also called ChainId for + * skype chain ID. + */ + @JsonProperty(value = "correlationId") + private String correlationId; + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: Operation context. + * + * @param operationContext the operationContext value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } + + /** + * Get the recognitionType property: Determines the sub-type pf the recognize operation. + * + * @return the recognitionType value. + */ + public RecognitionType getRecognitionType() { + return this.recognitionType; + } + + /** + * Set the recognitionType property: Determines the sub-type pf the recognize operation. + * + * @param recognitionType the recognitionType value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setRecognitionType(RecognitionType recognitionType) { + this.recognitionType = recognitionType; + return this; + } + + /** + * Get the collectTonesResult property: Defines the result for RecognitionType = Dtmf. + * + * @return the collectTonesResult value. + */ + public CollectTonesResult getCollectTonesResult() { + return this.collectTonesResult; + } + + /** + * Set the collectTonesResult property: Defines the result for RecognitionType = Dtmf. + * + * @param collectTonesResult the collectTonesResult value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setCollectTonesResult(CollectTonesResult collectTonesResult) { + this.collectTonesResult = collectTonesResult; + return this; + } + + /** + * Get the resultInfo property: Defines the code, sub-code and message for the operation. + * + * @return the resultInfo value. + */ + public ResultInformation getResultInfo() { + return this.resultInfo; + } + + /** + * Set the resultInfo property: Defines the code, sub-code and message for the operation. + * + * @param resultInfo the resultInfo value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setResultInfo(ResultInformation resultInfo) { + this.resultInfo = resultInfo; + return this; + } + + /** + * Get the type property: The type property. + * + * @return the type value. + */ + public AcsEventTypeInternal getType() { + return this.type; + } + + /** + * Set the type property: The type property. + * + * @param type the type value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setType(AcsEventTypeInternal type) { + this.type = type; + return this; + } + + /** + * Get the callConnectionId property: Call connection ID. + * + * @return the callConnectionId value. + */ + public String getCallConnectionId() { + return this.callConnectionId; + } + + /** + * Set the callConnectionId property: Call connection ID. + * + * @param callConnectionId the callConnectionId value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setCallConnectionId(String callConnectionId) { + this.callConnectionId = callConnectionId; + return this; + } + + /** + * Get the serverCallId property: Server call ID. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } + + /** + * Set the serverCallId property: Server call ID. + * + * @param serverCallId the serverCallId value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setServerCallId(String serverCallId) { + this.serverCallId = serverCallId; + return this; + } + + /** + * Get the correlationId property: Correlation ID for event to call correlation. Also called ChainId for skype chain + * ID. + * + * @return the correlationId value. + */ + public String getCorrelationId() { + return this.correlationId; + } + + /** + * Set the correlationId property: Correlation ID for event to call correlation. Also called ChainId for skype chain + * ID. + * + * @param correlationId the correlationId value to set. + * @return the RecognizeCompleted object itself. + */ + public RecognizeCompleted setCorrelationId(String correlationId) { + this.correlationId = correlationId; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeConfigurationsInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeConfigurationsInternal.java new file mode 100644 index 0000000000000..4ed51a9ca9a68 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeConfigurationsInternal.java @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RecognizeConfigurationsInternal model. */ +@Fluent +public final class RecognizeConfigurationsInternal { + /* + * Determines if we interrupt the prompt and start recognizing. + */ + @JsonProperty(value = "interruptPromptAndStartRecognition") + private Boolean interruptPromptAndStartRecognition; + + /* + * Time to wait for first input after prompt (if any). + */ + @JsonProperty(value = "initialSilenceTimeoutInSeconds") + private Integer initialSilenceTimeoutInSeconds; + + /* + * Target participant of DTFM tone recognition. + */ + @JsonProperty(value = "targetParticipant") + private CommunicationIdentifierModel targetParticipant; + + /* + * Defines configurations for DTMF. + */ + @JsonProperty(value = "dtmfConfigurations") + private DtmfConfigurationsInternal dtmfConfigurations; + + /** + * Get the interruptPromptAndStartRecognition property: Determines if we interrupt the prompt and start recognizing. + * + * @return the interruptPromptAndStartRecognition value. + */ + public Boolean isInterruptPromptAndStartRecognition() { + return this.interruptPromptAndStartRecognition; + } + + /** + * Set the interruptPromptAndStartRecognition property: Determines if we interrupt the prompt and start recognizing. + * + * @param interruptPromptAndStartRecognition the interruptPromptAndStartRecognition value to set. + * @return the RecognizeConfigurationsInternal object itself. + */ + public RecognizeConfigurationsInternal setInterruptPromptAndStartRecognition( + Boolean interruptPromptAndStartRecognition) { + this.interruptPromptAndStartRecognition = interruptPromptAndStartRecognition; + return this; + } + + /** + * Get the initialSilenceTimeoutInSeconds property: Time to wait for first input after prompt (if any). + * + * @return the initialSilenceTimeoutInSeconds value. + */ + public Integer getInitialSilenceTimeoutInSeconds() { + return this.initialSilenceTimeoutInSeconds; + } + + /** + * Set the initialSilenceTimeoutInSeconds property: Time to wait for first input after prompt (if any). + * + * @param initialSilenceTimeoutInSeconds the initialSilenceTimeoutInSeconds value to set. + * @return the RecognizeConfigurationsInternal object itself. + */ + public RecognizeConfigurationsInternal setInitialSilenceTimeoutInSeconds(Integer initialSilenceTimeoutInSeconds) { + this.initialSilenceTimeoutInSeconds = initialSilenceTimeoutInSeconds; + return this; + } + + /** + * Get the targetParticipant property: Target participant of DTFM tone recognition. + * + * @return the targetParticipant value. + */ + public CommunicationIdentifierModel getTargetParticipant() { + return this.targetParticipant; + } + + /** + * Set the targetParticipant property: Target participant of DTFM tone recognition. + * + * @param targetParticipant the targetParticipant value to set. + * @return the RecognizeConfigurationsInternal object itself. + */ + public RecognizeConfigurationsInternal setTargetParticipant(CommunicationIdentifierModel targetParticipant) { + this.targetParticipant = targetParticipant; + return this; + } + + /** + * Get the dtmfConfigurations property: Defines configurations for DTMF. + * + * @return the dtmfConfigurations value. + */ + public DtmfConfigurationsInternal getDtmfConfigurations() { + return this.dtmfConfigurations; + } + + /** + * Set the dtmfConfigurations property: Defines configurations for DTMF. + * + * @param dtmfConfigurations the dtmfConfigurations value to set. + * @return the RecognizeConfigurationsInternal object itself. + */ + public RecognizeConfigurationsInternal setDtmfConfigurations(DtmfConfigurationsInternal dtmfConfigurations) { + this.dtmfConfigurations = dtmfConfigurations; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeFailed.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeFailed.java new file mode 100644 index 0000000000000..190967a6236c2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeFailed.java @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RecognizeFailed model. */ +@Fluent +public final class RecognizeFailed { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /* + * Defines the code, sub-code and message for the operation + */ + @JsonProperty(value = "resultInfo") + private ResultInformation resultInfo; + + /* + * The type property. + */ + @JsonProperty(value = "type") + private AcsEventTypeInternal type; + + /* + * Call connection ID. + */ + @JsonProperty(value = "callConnectionId") + private String callConnectionId; + + /* + * Server call ID. + */ + @JsonProperty(value = "serverCallId") + private String serverCallId; + + /* + * Correlation ID for event to call correlation. Also called ChainId for + * skype chain ID. + */ + @JsonProperty(value = "correlationId") + private String correlationId; + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: Operation context. + * + * @param operationContext the operationContext value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } + + /** + * Get the resultInfo property: Defines the code, sub-code and message for the operation. + * + * @return the resultInfo value. + */ + public ResultInformation getResultInfo() { + return this.resultInfo; + } + + /** + * Set the resultInfo property: Defines the code, sub-code and message for the operation. + * + * @param resultInfo the resultInfo value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setResultInfo(ResultInformation resultInfo) { + this.resultInfo = resultInfo; + return this; + } + + /** + * Get the type property: The type property. + * + * @return the type value. + */ + public AcsEventTypeInternal getType() { + return this.type; + } + + /** + * Set the type property: The type property. + * + * @param type the type value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setType(AcsEventTypeInternal type) { + this.type = type; + return this; + } + + /** + * Get the callConnectionId property: Call connection ID. + * + * @return the callConnectionId value. + */ + public String getCallConnectionId() { + return this.callConnectionId; + } + + /** + * Set the callConnectionId property: Call connection ID. + * + * @param callConnectionId the callConnectionId value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setCallConnectionId(String callConnectionId) { + this.callConnectionId = callConnectionId; + return this; + } + + /** + * Get the serverCallId property: Server call ID. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } + + /** + * Set the serverCallId property: Server call ID. + * + * @param serverCallId the serverCallId value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setServerCallId(String serverCallId) { + this.serverCallId = serverCallId; + return this; + } + + /** + * Get the correlationId property: Correlation ID for event to call correlation. Also called ChainId for skype chain + * ID. + * + * @return the correlationId value. + */ + public String getCorrelationId() { + return this.correlationId; + } + + /** + * Set the correlationId property: Correlation ID for event to call correlation. Also called ChainId for skype chain + * ID. + * + * @param correlationId the correlationId value to set. + * @return the RecognizeFailed object itself. + */ + public RecognizeFailed setCorrelationId(String correlationId) { + this.correlationId = correlationId; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeInputTypeInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeInputTypeInternal.java new file mode 100644 index 0000000000000..c149219c511a2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeInputTypeInternal.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecognizeInputTypeInternal. */ +public final class RecognizeInputTypeInternal extends ExpandableStringEnum { + /** Static value dtmf for RecognizeInputTypeInternal. */ + public static final RecognizeInputTypeInternal DTMF = fromString("dtmf"); + + /** + * Creates or finds a RecognizeInputTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecognizeInputTypeInternal. + */ + @JsonCreator + public static RecognizeInputTypeInternal fromString(String name) { + return fromString(name, RecognizeInputTypeInternal.class); + } + + /** @return known RecognizeInputTypeInternal values. */ + public static Collection values() { + return values(RecognizeInputTypeInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeRequest.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeRequest.java new file mode 100644 index 0000000000000..82b8eed088012 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecognizeRequest.java @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RecognizeRequest model. */ +@Fluent +public final class RecognizeRequest { + /* + * Determines the type of the recognition. + */ + @JsonProperty(value = "recognizeInputType", required = true) + private RecognizeInputTypeInternal recognizeInputType; + + /* + * The source of the audio to be played for recognition. + */ + @JsonProperty(value = "playPrompt") + private PlaySourceInternal playPrompt; + + /* + * If set recognize can barge into other existing + * queued-up/currently-processing requests. + */ + @JsonProperty(value = "stopCurrentOperations") + private Boolean stopCurrentOperations; + + /* + * Defines options for recognition. + */ + @JsonProperty(value = "recognizeConfiguration", required = true) + private RecognizeConfigurationsInternal recognizeConfiguration; + + /* + * The value to identify context of the operation. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the recognizeInputType property: Determines the type of the recognition. + * + * @return the recognizeInputType value. + */ + public RecognizeInputTypeInternal getRecognizeInputType() { + return this.recognizeInputType; + } + + /** + * Set the recognizeInputType property: Determines the type of the recognition. + * + * @param recognizeInputType the recognizeInputType value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeRequest setRecognizeInputType(RecognizeInputTypeInternal recognizeInputType) { + this.recognizeInputType = recognizeInputType; + return this; + } + + /** + * Get the playPrompt property: The source of the audio to be played for recognition. + * + * @return the playPrompt value. + */ + public PlaySourceInternal getPlayPrompt() { + return this.playPrompt; + } + + /** + * Set the playPrompt property: The source of the audio to be played for recognition. + * + * @param playPrompt the playPrompt value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeRequest setPlayPrompt(PlaySourceInternal playPrompt) { + this.playPrompt = playPrompt; + return this; + } + + /** + * Get the stopCurrentOperations property: If set recognize can barge into other existing + * queued-up/currently-processing requests. + * + * @return the stopCurrentOperations value. + */ + public Boolean isStopCurrentOperations() { + return this.stopCurrentOperations; + } + + /** + * Set the stopCurrentOperations property: If set recognize can barge into other existing + * queued-up/currently-processing requests. + * + * @param stopCurrentOperations the stopCurrentOperations value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeRequest setStopCurrentOperations(Boolean stopCurrentOperations) { + this.stopCurrentOperations = stopCurrentOperations; + return this; + } + + /** + * Get the recognizeConfiguration property: Defines options for recognition. + * + * @return the recognizeConfiguration value. + */ + public RecognizeConfigurationsInternal getRecognizeConfiguration() { + return this.recognizeConfiguration; + } + + /** + * Set the recognizeConfiguration property: Defines options for recognition. + * + * @param recognizeConfiguration the recognizeConfiguration value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeRequest setRecognizeConfiguration(RecognizeConfigurationsInternal recognizeConfiguration) { + this.recognizeConfiguration = recognizeConfiguration; + return this; + } + + /** + * Get the operationContext property: The value to identify context of the operation. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The value to identify context of the operation. + * + * @param operationContext the operationContext value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeRequest setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingChannelInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingChannelInternal.java new file mode 100644 index 0000000000000..7bc685488a2a5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingChannelInternal.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecordingChannelInternal. */ +public final class RecordingChannelInternal extends ExpandableStringEnum { + /** Static value mixed for RecordingChannelInternal. */ + public static final RecordingChannelInternal MIXED = fromString("mixed"); + + /** Static value unmixed for RecordingChannelInternal. */ + public static final RecordingChannelInternal UNMIXED = fromString("unmixed"); + + /** + * Creates or finds a RecordingChannelInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingChannelInternal. + */ + @JsonCreator + public static RecordingChannelInternal fromString(String name) { + return fromString(name, RecordingChannelInternal.class); + } + + /** @return known RecordingChannelInternal values. */ + public static Collection values() { + return values(RecordingChannelInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingContentInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingContentInternal.java new file mode 100644 index 0000000000000..929ba38b8cffc --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingContentInternal.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecordingContentInternal. */ +public final class RecordingContentInternal extends ExpandableStringEnum { + /** Static value audio for RecordingContentInternal. */ + public static final RecordingContentInternal AUDIO = fromString("audio"); + + /** Static value audioVideo for RecordingContentInternal. */ + public static final RecordingContentInternal AUDIO_VIDEO = fromString("audioVideo"); + + /** + * Creates or finds a RecordingContentInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingContentInternal. + */ + @JsonCreator + public static RecordingContentInternal fromString(String name) { + return fromString(name, RecordingContentInternal.class); + } + + /** @return known RecordingContentInternal values. */ + public static Collection values() { + return values(RecordingContentInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingFormatInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingFormatInternal.java new file mode 100644 index 0000000000000..9bb0859bafbea --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingFormatInternal.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecordingFormatInternal. */ +public final class RecordingFormatInternal extends ExpandableStringEnum { + /** Static value wav for RecordingFormatInternal. */ + public static final RecordingFormatInternal WAV = fromString("wav"); + + /** Static value mp3 for RecordingFormatInternal. */ + public static final RecordingFormatInternal MP3 = fromString("mp3"); + + /** Static value mp4 for RecordingFormatInternal. */ + public static final RecordingFormatInternal MP4 = fromString("mp4"); + + /** + * Creates or finds a RecordingFormatInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingFormatInternal. + */ + @JsonCreator + public static RecordingFormatInternal fromString(String name) { + return fromString(name, RecordingFormatInternal.class); + } + + /** @return known RecordingFormatInternal values. */ + public static Collection values() { + return values(RecordingFormatInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateInternal.java new file mode 100644 index 0000000000000..0e87ac073cf63 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateInternal.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecordingStateInternal. */ +public final class RecordingStateInternal extends ExpandableStringEnum { + /** Static value active for RecordingStateInternal. */ + public static final RecordingStateInternal ACTIVE = fromString("active"); + + /** Static value inactive for RecordingStateInternal. */ + public static final RecordingStateInternal INACTIVE = fromString("inactive"); + + /** + * Creates or finds a RecordingStateInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingStateInternal. + */ + @JsonCreator + public static RecordingStateInternal fromString(String name) { + return fromString(name, RecordingStateInternal.class); + } + + /** @return known RecordingStateInternal values. */ + public static Collection values() { + return values(RecordingStateInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateResponseInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateResponseInternal.java new file mode 100644 index 0000000000000..8553b6ccba2b5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RecordingStateResponseInternal.java @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RecordingStateResponseInternal model. */ +@Fluent +public final class RecordingStateResponseInternal { + /* + * The recordingId property. + */ + @JsonProperty(value = "recordingId") + private String recordingId; + + /* + * The recordingState property. + */ + @JsonProperty(value = "recordingState") + private RecordingStateInternal recordingState; + + /** + * Get the recordingId property: The recordingId property. + * + * @return the recordingId value. + */ + public String getRecordingId() { + return this.recordingId; + } + + /** + * Set the recordingId property: The recordingId property. + * + * @param recordingId the recordingId value to set. + * @return the RecordingStateResponseInternal object itself. + */ + public RecordingStateResponseInternal setRecordingId(String recordingId) { + this.recordingId = recordingId; + return this; + } + + /** + * Get the recordingState property: The recordingState property. + * + * @return the recordingState value. + */ + public RecordingStateInternal getRecordingState() { + return this.recordingState; + } + + /** + * Set the recordingState property: The recordingState property. + * + * @param recordingState the recordingState value to set. + * @return the RecordingStateResponseInternal object itself. + */ + public RecordingStateResponseInternal setRecordingState(RecordingStateInternal recordingState) { + this.recordingState = recordingState; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RedirectCallRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RedirectCallRequestInternal.java new file mode 100644 index 0000000000000..e9b377f1fac4c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RedirectCallRequestInternal.java @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The request payload for redirecting the call. */ +@Fluent +public final class RedirectCallRequestInternal { + /* + * The context associated with the call. + */ + @JsonProperty(value = "incomingCallContext", required = true) + private String incomingCallContext; + + /* + * The target identity to redirect the call to. + */ + @JsonProperty(value = "target", required = true) + private CommunicationIdentifierModel target; + + /** + * Get the incomingCallContext property: The context associated with the call. + * + * @return the incomingCallContext value. + */ + public String getIncomingCallContext() { + return this.incomingCallContext; + } + + /** + * Set the incomingCallContext property: The context associated with the call. + * + * @param incomingCallContext the incomingCallContext value to set. + * @return the RedirectCallRequestInternal object itself. + */ + public RedirectCallRequestInternal setIncomingCallContext(String incomingCallContext) { + this.incomingCallContext = incomingCallContext; + return this; + } + + /** + * Get the target property: The target identity to redirect the call to. + * + * @return the target value. + */ + public CommunicationIdentifierModel getTarget() { + return this.target; + } + + /** + * Set the target property: The target identity to redirect the call to. + * + * @param target the target value to set. + * @return the RedirectCallRequestInternal object itself. + */ + public RedirectCallRequestInternal setTarget(CommunicationIdentifierModel target) { + this.target = target; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RejectCallRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RejectCallRequestInternal.java new file mode 100644 index 0000000000000..b315242b2382e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RejectCallRequestInternal.java @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The request payload for rejecting the call. */ +@Fluent +public final class RejectCallRequestInternal { + /* + * The context associated with the call. + */ + @JsonProperty(value = "incomingCallContext", required = true) + private String incomingCallContext; + + /* + * The rejection reason. + */ + @JsonProperty(value = "callRejectReason") + private CallRejectReasonInternal callRejectReason; + + /** + * Get the incomingCallContext property: The context associated with the call. + * + * @return the incomingCallContext value. + */ + public String getIncomingCallContext() { + return this.incomingCallContext; + } + + /** + * Set the incomingCallContext property: The context associated with the call. + * + * @param incomingCallContext the incomingCallContext value to set. + * @return the RejectCallRequestInternal object itself. + */ + public RejectCallRequestInternal setIncomingCallContext(String incomingCallContext) { + this.incomingCallContext = incomingCallContext; + return this; + } + + /** + * Get the callRejectReason property: The rejection reason. + * + * @return the callRejectReason value. + */ + public CallRejectReasonInternal getCallRejectReason() { + return this.callRejectReason; + } + + /** + * Set the callRejectReason property: The rejection reason. + * + * @param callRejectReason the callRejectReason value to set. + * @return the RejectCallRequestInternal object itself. + */ + public RejectCallRequestInternal setCallRejectReason(CallRejectReasonInternal callRejectReason) { + this.callRejectReason = callRejectReason; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsRequestInternal.java new file mode 100644 index 0000000000000..6d6659536f972 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsRequestInternal.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The remove participant by identifier request. */ +@Fluent +public final class RemoveParticipantsRequestInternal { + /* + * The participants to invite. + */ + @JsonProperty(value = "participantsToRemove", required = true) + private List participantsToRemove; + + /* + * The operation context. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the participantsToRemove property: The participants to invite. + * + * @return the participantsToRemove value. + */ + public List getParticipantsToRemove() { + return this.participantsToRemove; + } + + /** + * Set the participantsToRemove property: The participants to invite. + * + * @param participantsToRemove the participantsToRemove value to set. + * @return the RemoveParticipantsRequestInternal object itself. + */ + public RemoveParticipantsRequestInternal setParticipantsToRemove( + List participantsToRemove) { + this.participantsToRemove = participantsToRemove; + return this; + } + + /** + * Get the operationContext property: The operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context. + * + * @param operationContext the operationContext value to set. + * @return the RemoveParticipantsRequestInternal object itself. + */ + public RemoveParticipantsRequestInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsResponseInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsResponseInternal.java new file mode 100644 index 0000000000000..8fe6aeef37a47 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/RemoveParticipantsResponseInternal.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The RemoveParticipantsResponseInternal model. */ +@Fluent +public final class RemoveParticipantsResponseInternal { + /* + * The operation context provided by client. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context provided by client. + * + * @param operationContext the operationContext value to set. + * @return the RemoveParticipantsResponseInternal object itself. + */ + public RemoveParticipantsResponseInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ResultInformation.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ResultInformation.java new file mode 100644 index 0000000000000..4c5cc48cd415c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/ResultInformation.java @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The ResultInformation model. */ +@Fluent +public final class ResultInformation { + /* + * The code property. + */ + @JsonProperty(value = "code") + private Integer code; + + /* + * The subCode property. + */ + @JsonProperty(value = "subCode") + private Integer subCode; + + /* + * The message property. + */ + @JsonProperty(value = "message") + private String message; + + /** + * Get the code property: The code property. + * + * @return the code value. + */ + public Integer getCode() { + return this.code; + } + + /** + * Set the code property: The code property. + * + * @param code the code value to set. + * @return the ResultInformation object itself. + */ + public ResultInformation setCode(Integer code) { + this.code = code; + return this; + } + + /** + * Get the subCode property: The subCode property. + * + * @return the subCode value. + */ + public Integer getSubCode() { + return this.subCode; + } + + /** + * Set the subCode property: The subCode property. + * + * @param subCode the subCode value to set. + * @return the ResultInformation object itself. + */ + public ResultInformation setSubCode(Integer subCode) { + this.subCode = subCode; + return this; + } + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String getMessage() { + return this.message; + } + + /** + * Set the message property: The message property. + * + * @param message the message value to set. + * @return the ResultInformation object itself. + */ + public ResultInformation setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StartCallRecordingRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StartCallRecordingRequestInternal.java new file mode 100644 index 0000000000000..8699cd567328b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StartCallRecordingRequestInternal.java @@ -0,0 +1,169 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** The request payload start for call recording operation with call locator. */ +@Fluent +public final class StartCallRecordingRequestInternal { + /* + * The call locator. + */ + @JsonProperty(value = "callLocator", required = true) + private CallLocatorInternal callLocator; + + /* + * The uri to send notifications to. + */ + @JsonProperty(value = "recordingStateCallbackUri") + private String recordingStateCallbackUri; + + /* + * The content type of call recording. + */ + @JsonProperty(value = "recordingContentType") + private RecordingContentInternal recordingContentType; + + /* + * The channel type of call recording. + */ + @JsonProperty(value = "recordingChannelType") + private RecordingChannelInternal recordingChannelType; + + /* + * The format type of call recording. + */ + @JsonProperty(value = "recordingFormatType") + private RecordingFormatInternal recordingFormatType; + + /* + * The channel affinity of call recording. + */ + @JsonProperty(value = "channelAffinity") + private List channelAffinity; + + /** + * Get the callLocator property: The call locator. + * + * @return the callLocator value. + */ + public CallLocatorInternal getCallLocator() { + return this.callLocator; + } + + /** + * Set the callLocator property: The call locator. + * + * @param callLocator the callLocator value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setCallLocator(CallLocatorInternal callLocator) { + this.callLocator = callLocator; + return this; + } + + /** + * Get the recordingStateCallbackUri property: The uri to send notifications to. + * + * @return the recordingStateCallbackUri value. + */ + public String getRecordingStateCallbackUri() { + return this.recordingStateCallbackUri; + } + + /** + * Set the recordingStateCallbackUri property: The uri to send notifications to. + * + * @param recordingStateCallbackUri the recordingStateCallbackUri value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setRecordingStateCallbackUri(String recordingStateCallbackUri) { + this.recordingStateCallbackUri = recordingStateCallbackUri; + return this; + } + + /** + * Get the recordingContentType property: The content type of call recording. + * + * @return the recordingContentType value. + */ + public RecordingContentInternal getRecordingContentType() { + return this.recordingContentType; + } + + /** + * Set the recordingContentType property: The content type of call recording. + * + * @param recordingContentType the recordingContentType value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setRecordingContentType(RecordingContentInternal recordingContentType) { + this.recordingContentType = recordingContentType; + return this; + } + + /** + * Get the recordingChannelType property: The channel type of call recording. + * + * @return the recordingChannelType value. + */ + public RecordingChannelInternal getRecordingChannelType() { + return this.recordingChannelType; + } + + /** + * Set the recordingChannelType property: The channel type of call recording. + * + * @param recordingChannelType the recordingChannelType value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setRecordingChannelType(RecordingChannelInternal recordingChannelType) { + this.recordingChannelType = recordingChannelType; + return this; + } + + /** + * Get the recordingFormatType property: The format type of call recording. + * + * @return the recordingFormatType value. + */ + public RecordingFormatInternal getRecordingFormatType() { + return this.recordingFormatType; + } + + /** + * Set the recordingFormatType property: The format type of call recording. + * + * @param recordingFormatType the recordingFormatType value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setRecordingFormatType(RecordingFormatInternal recordingFormatType) { + this.recordingFormatType = recordingFormatType; + return this; + } + + /** + * Get the channelAffinity property: The channel affinity of call recording. + * + * @return the channelAffinity value. + */ + public List getChannelAffinity() { + return this.channelAffinity; + } + + /** + * Set the channelAffinity property: The channel affinity of call recording. + * + * @param channelAffinity the channelAffinity value to set. + * @return the StartCallRecordingRequestInternal object itself. + */ + public StartCallRecordingRequestInternal setChannelAffinity(List channelAffinity) { + this.channelAffinity = channelAffinity; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StopTonesInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StopTonesInternal.java new file mode 100644 index 0000000000000..68fe11d1879d2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/StopTonesInternal.java @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for StopTonesInternal. */ +public final class StopTonesInternal extends ExpandableStringEnum { + /** Static value zero for StopTonesInternal. */ + public static final StopTonesInternal ZERO = fromString("zero"); + + /** Static value one for StopTonesInternal. */ + public static final StopTonesInternal ONE = fromString("one"); + + /** Static value two for StopTonesInternal. */ + public static final StopTonesInternal TWO = fromString("two"); + + /** Static value three for StopTonesInternal. */ + public static final StopTonesInternal THREE = fromString("three"); + + /** Static value four for StopTonesInternal. */ + public static final StopTonesInternal FOUR = fromString("four"); + + /** Static value five for StopTonesInternal. */ + public static final StopTonesInternal FIVE = fromString("five"); + + /** Static value six for StopTonesInternal. */ + public static final StopTonesInternal SIX = fromString("six"); + + /** Static value seven for StopTonesInternal. */ + public static final StopTonesInternal SEVEN = fromString("seven"); + + /** Static value eight for StopTonesInternal. */ + public static final StopTonesInternal EIGHT = fromString("eight"); + + /** Static value nine for StopTonesInternal. */ + public static final StopTonesInternal NINE = fromString("nine"); + + /** Static value a for StopTonesInternal. */ + public static final StopTonesInternal A = fromString("a"); + + /** Static value b for StopTonesInternal. */ + public static final StopTonesInternal B = fromString("b"); + + /** Static value c for StopTonesInternal. */ + public static final StopTonesInternal C = fromString("c"); + + /** Static value d for StopTonesInternal. */ + public static final StopTonesInternal D = fromString("d"); + + /** Static value pound for StopTonesInternal. */ + public static final StopTonesInternal POUND = fromString("pound"); + + /** Static value asterisk for StopTonesInternal. */ + public static final StopTonesInternal ASTERISK = fromString("asterisk"); + + /** + * Creates or finds a StopTonesInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding StopTonesInternal. + */ + @JsonCreator + public static StopTonesInternal fromString(String name) { + return fromString(name, StopTonesInternal.class); + } + + /** @return known StopTonesInternal values. */ + public static Collection values() { + return values(StopTonesInternal.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferCallResponseInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferCallResponseInternal.java new file mode 100644 index 0000000000000..1040a4ffd12e1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferCallResponseInternal.java @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The TransferCallResponseInternal model. */ +@Fluent +public final class TransferCallResponseInternal { + /* + * The operation context provided by client. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context provided by client. + * + * @param operationContext the operationContext value to set. + * @return the TransferCallResponseInternal object itself. + */ + public TransferCallResponseInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferToParticipantRequestInternal.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferToParticipantRequestInternal.java new file mode 100644 index 0000000000000..f2d03266046de --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/TransferToParticipantRequestInternal.java @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The transfer call to participant request. */ +@Fluent +public final class TransferToParticipantRequestInternal { + /* + * The identity of the target where call should be transferred to. + */ + @JsonProperty(value = "targetParticipant", required = true) + private CommunicationIdentifierModel targetParticipant; + + /* + * The caller ID of the transferee when transferring to PSTN. + */ + @JsonProperty(value = "transfereeCallerId") + private PhoneNumberIdentifierModel transfereeCallerId; + + /* + * The user to user information. + */ + @JsonProperty(value = "userToUserInformation") + private String userToUserInformation; + + /* + * The operation context. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Get the targetParticipant property: The identity of the target where call should be transferred to. + * + * @return the targetParticipant value. + */ + public CommunicationIdentifierModel getTargetParticipant() { + return this.targetParticipant; + } + + /** + * Set the targetParticipant property: The identity of the target where call should be transferred to. + * + * @param targetParticipant the targetParticipant value to set. + * @return the TransferToParticipantRequestInternal object itself. + */ + public TransferToParticipantRequestInternal setTargetParticipant(CommunicationIdentifierModel targetParticipant) { + this.targetParticipant = targetParticipant; + return this; + } + + /** + * Get the transfereeCallerId property: The caller ID of the transferee when transferring to PSTN. + * + * @return the transfereeCallerId value. + */ + public PhoneNumberIdentifierModel getTransfereeCallerId() { + return this.transfereeCallerId; + } + + /** + * Set the transfereeCallerId property: The caller ID of the transferee when transferring to PSTN. + * + * @param transfereeCallerId the transfereeCallerId value to set. + * @return the TransferToParticipantRequestInternal object itself. + */ + public TransferToParticipantRequestInternal setTransfereeCallerId(PhoneNumberIdentifierModel transfereeCallerId) { + this.transfereeCallerId = transfereeCallerId; + return this; + } + + /** + * Get the userToUserInformation property: The user to user information. + * + * @return the userToUserInformation value. + */ + public String getUserToUserInformation() { + return this.userToUserInformation; + } + + /** + * Set the userToUserInformation property: The user to user information. + * + * @param userToUserInformation the userToUserInformation value to set. + * @return the TransferToParticipantRequestInternal object itself. + */ + public TransferToParticipantRequestInternal setUserToUserInformation(String userToUserInformation) { + this.userToUserInformation = userToUserInformation; + return this; + } + + /** + * Get the operationContext property: The operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The operation context. + * + * @param operationContext the operationContext value to set. + * @return the TransferToParticipantRequestInternal object itself. + */ + public TransferToParticipantRequestInternal setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/package-info.java new file mode 100644 index 0000000000000..942519dc658d7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/models/package-info.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** Package containing the data models for AzureCommunicationCallAutomationService. null. */ +package com.azure.communication.callautomation.implementation.models; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/package-info.java new file mode 100644 index 0000000000000..dc6ff23f5a5c5 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/implementation/package-info.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** Package containing the implementations for AzureCommunicationCallAutomationService. null. */ +package com.azure.communication.callautomation.implementation; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsOptions.java new file mode 100644 index 0000000000000..c42345a5e96c8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsOptions.java @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.PhoneNumberIdentifier; +import com.azure.core.annotation.Fluent; + +import java.time.Duration; +import java.util.List; + +/** + * The options for adding participants. + */ +@Fluent +public final class AddParticipantsOptions { + /** + * The list of participants to invite. + */ + private final List participants; + + /** + * The operational context + */ + private String operationContext; + + /** + * The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + */ + private PhoneNumberIdentifier sourceCallerId; + + /** + * The timeout to wait for the invited participant to pickup. + * The maximum value of this is 180 seconds. + */ + private Duration invitationTimeout; + + /** + * Constructor + * + * @param participants The list of participants to invite. + */ + public AddParticipantsOptions(List participants) { + this.participants = participants; + } + + /** + * Get the participants. + * + * @return the list of participants to be added + */ + public List getParticipants() { + return participants; + } + + /** + * Get the operationContext. + * + * @return the operationContext + */ + public String getOperationContext() { + return operationContext; + } + + /** + * Get the sourceCallerId. + * + * @return the sourceCallerId phone identifier. + */ + public PhoneNumberIdentifier getSourceCallerId() { + return sourceCallerId; + } + + /** + * Get the invitationTimeoutInSeconds. + * + * @return the Invitation Timeout In Seconds + */ + public Duration getInvitationTimeout() { + return invitationTimeout; + } + + /** + * Set the operationContext. + * + * @param operationContext the operationContext to set + * @return the AddParticipantsOptions object itself. + */ + public AddParticipantsOptions setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } + + /** + * Set the sourceCallerId. + * + * @param sourceCallerId Set the source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + * @return the AddParticipantsOptions object itself. + */ + public AddParticipantsOptions setSourceCallerId(PhoneNumberIdentifier sourceCallerId) { + this.sourceCallerId = sourceCallerId; + return this; + } + + /** + * Set the invitationTimeoutInSeconds. + * + * @param invitationTimeout Set the timeout to wait for the invited participant to pickup. + * The maximum value of this is 180 seconds. + * @return the AddParticipantsOptions object itself. + */ + public AddParticipantsOptions setInvitationTimeout(Duration invitationTimeout) { + this.invitationTimeout = invitationTimeout; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsResult.java new file mode 100644 index 0000000000000..02885e9e64e87 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AddParticipantsResult.java @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.AddParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CallParticipantConverter; +import com.azure.communication.callautomation.implementation.models.AddParticipantsResponseInternal; +import com.azure.core.annotation.Immutable; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** The AddParticipantsResult model. */ +@Immutable +public final class AddParticipantsResult { + /* + * The participants property. + */ + private final List participants; + + /* + * The operation context provided by client. + */ + private final String operationContext; + + static { + AddParticipantsResponseConstructorProxy.setAccessor( + new AddParticipantsResponseConstructorProxy.AddParticipantsResponseConstructorAccessor() { + @Override + public AddParticipantsResult create(AddParticipantsResponseInternal internalHeaders) { + return new AddParticipantsResult(internalHeaders); + } + }); + } + + /** + * Public constructor. + * + */ + public AddParticipantsResult() { + this.participants = null; + this.operationContext = null; + } + + /** + * Constructor of the class + * + * @param addParticipantsResponseInternal The response from the addParticipant service + */ + AddParticipantsResult(AddParticipantsResponseInternal addParticipantsResponseInternal) { + Objects.requireNonNull(addParticipantsResponseInternal, "addParticipantsResponseInternal must not be null"); + + this.participants = addParticipantsResponseInternal.getParticipants() + .stream() + .map(CallParticipantConverter::convert) + .collect(Collectors.toList()); + this.operationContext = addParticipantsResponseInternal.getOperationContext(); + } + + /** + * Get the participants property: The participants property. + * + * @return the participants value. + */ + public List getParticipants() { + return this.participants; + } + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AnswerCallResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AnswerCallResult.java new file mode 100644 index 0000000000000..17d927ebfa540 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/AnswerCallResult.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.CallConnection; +import com.azure.communication.callautomation.CallConnectionAsync; + +/** + * The result of answering a call + */ +public class AnswerCallResult extends CallResult { + + /** + * Constructor + * + * @param callConnectionProperties The callConnectionProperties + * @param callConnection The callConnection + * @param callConnectionAsync The callConnectionAsync + */ + public AnswerCallResult(CallConnectionProperties callConnectionProperties, CallConnection callConnection, CallConnectionAsync callConnectionAsync) { + super(callConnectionProperties, callConnection, callConnectionAsync); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionProperties.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionProperties.java new file mode 100644 index 0000000000000..d0cf787d908f0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionProperties.java @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.CallConnectionPropertiesConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CallSourceConverter; +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CallConnectionPropertiesInternal; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Immutable; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Asynchronous client that supports call connection operations. + */ +@Immutable +public final class CallConnectionProperties { + private final String callConnectionId; + private final String serverCallId; + private final CallSource source; + private final List targets; + private final CallConnectionState callConnectionState; + private final String subject; + private final URI callbackUri; + + static { + CallConnectionPropertiesConstructorProxy.setAccessor( + new CallConnectionPropertiesConstructorProxy.CallConnectionPropertiesConstructorAccessor() { + @Override + public CallConnectionProperties create(CallConnectionPropertiesInternal internalHeaders) throws URISyntaxException { + return new CallConnectionProperties(internalHeaders); + } + }); + } + + /** + * Public constructor. + * + */ + public CallConnectionProperties() { + this.callConnectionId = null; + this.source = null; + this.serverCallId = null; + this.targets = null; + this.callConnectionState = null; + this.subject = null; + this.callbackUri = null; + } + + /** + * Package-private constructor of the class, used internally. + * + * @param callConnectionPropertiesInternal The internal response of callConnectionProperties + * @throws URISyntaxException exception of invalid URI. + */ + CallConnectionProperties(CallConnectionPropertiesInternal callConnectionPropertiesInternal) throws URISyntaxException { + this.callConnectionId = callConnectionPropertiesInternal.getCallConnectionId(); + this.source = CallSourceConverter.convert(callConnectionPropertiesInternal.getSource()); + this.serverCallId = callConnectionPropertiesInternal.getServerCallId(); + this.targets = callConnectionPropertiesInternal.getTargets().stream().map(CommunicationIdentifierConverter::convert).collect(Collectors.toList()); + this.callConnectionState = CallConnectionState.fromString(callConnectionPropertiesInternal.getCallConnectionState().toString()); + this.subject = callConnectionPropertiesInternal.getSubject(); + this.callbackUri = new URI(callConnectionPropertiesInternal.getCallbackUri()); + } + + /** + * Get the source property. + * + * @return source value. + */ + public CallSource getSource() { + return source; + } + + /** + * Get the targets property. + * + * @return list of targets + */ + public List getTargets() { + return targets; + } + + /** + * Get the server call Id. + * + * @return serverCallId value. + */ + public String getServerCallId() { + return serverCallId; + } + + /** + * Get the callConnectionState property. + * + * @return callConnectionState value. + */ + public CallConnectionState getCallConnectionState() { + return callConnectionState; + } + + /** + * Get the subject property. + * + * @return subject value. + */ + public String getSubject() { + return subject; + } + + /** + * Get the callbackUri property. + * + * @return callbackUri value. + */ + public URI getCallbackUri() { + return callbackUri; + } + + /** + * Get the callConnectionId property, which is the call connection id. + * + * @return callConnectionId value. + */ + public String getCallConnectionId() { + return callConnectionId; + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionState.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionState.java new file mode 100644 index 0000000000000..80ff71178c90f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallConnectionState.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collection; + +/** Defines values for CallConnectionState. */ +public final class CallConnectionState extends ExpandableStringEnum { + /** Static value connecting for CallConnectionState. */ + public static final CallConnectionState CONNECTING = fromString("connecting"); + + /** Static value connected for CallConnectionState. */ + public static final CallConnectionState CONNECTED = fromString("connected"); + + /** Static value transferring for CallConnectionState. */ + public static final CallConnectionState TRANSFERRING = fromString("transferring"); + + /** Static value transferAccepted for CallConnectionState. */ + public static final CallConnectionState TRANSFER_ACCEPTED = fromString("transferAccepted"); + + /** Static value disconnecting for CallConnectionState. */ + public static final CallConnectionState DISCONNECTING = fromString("disconnecting"); + + /** Static value disconnected for CallConnectionState. */ + public static final CallConnectionState DISCONNECTED = fromString("disconnected"); + + /** + * Creates or finds a CallConnectionState from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallConnectionState. + */ + + public static CallConnectionState fromString(String name) { + return fromString(name, CallConnectionState.class); + } + + /** Return values + * @return known CallConnectionState values. + */ + public static Collection values() { + return values(CallConnectionState.class); + } + + /** + * Private constructor + */ + private CallConnectionState() { + + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocator.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocator.java new file mode 100644 index 0000000000000..276ba3c400f27 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocator.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +/** The locator used for joining or taking action on a call. */ +public abstract class CallLocator { + /* + * The call locator kind. + */ + private final CallLocatorKind kind; + + /** + * The constructor + * + * @param kind Specify the call locator kind. + */ + CallLocator(CallLocatorKind kind) { + if (kind == CallLocatorKind.GROUP_CALL_LOCATOR || kind == CallLocatorKind.SERVER_CALL_LOCATOR) { + this.kind = kind; + } else { + throw new IllegalArgumentException("Illegal callLocator kind"); + } + } + + /** + * Get the kind property: The call locator kind. + * + * @return the kind value. + */ + public CallLocatorKind getKind() { + return this.kind; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocatorKind.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocatorKind.java new file mode 100644 index 0000000000000..ae77e5ebe2ecc --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallLocatorKind.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collection; + +/** Defines values for CallLocatorKind. */ +public final class CallLocatorKind extends ExpandableStringEnum { + /** Static value groupCallLocator for CallLocatorKind. */ + public static final CallLocatorKind GROUP_CALL_LOCATOR = fromString("groupCallLocator"); + + /** Static value serverCallLocator for CallLocatorKind. */ + public static final CallLocatorKind SERVER_CALL_LOCATOR = fromString("serverCallLocator"); + + /** + * Creates or finds a CallLocatorKind from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallLocatorKind. + */ + public static CallLocatorKind fromString(String name) { + return fromString(name, CallLocatorKind.class); + } + + /** @return known CallLocatorKind values. */ + public static Collection values() { + return values(CallLocatorKind.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallParticipant.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallParticipant.java new file mode 100644 index 0000000000000..35beaf569e59f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallParticipant.java @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Immutable; + +/** The CallParticipant model. */ +@Immutable +public final class CallParticipant { + /* + * Communication identifier of the participant + */ + private final CommunicationIdentifier identifier; + + /* + * Is participant muted + */ + private final Boolean isMuted; + + /** + * Constructor of the class + * + * @param identifier The communication identifier + * @param isMuted The value of isMuted + */ + public CallParticipant(CommunicationIdentifier identifier, Boolean isMuted) { + this.identifier = identifier; + this.isMuted = isMuted; + } + + /** + * Get the identifier property: Communication identifier of the participant. + * + * @return the identifier value. + */ + public CommunicationIdentifier getIdentifier() { + return this.identifier; + } + + /** + * Get the isMuted property: Is participant muted. + * + * @return the isMuted value. + */ + public Boolean isMuted() { + return this.isMuted; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallRejectReason.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallRejectReason.java new file mode 100644 index 0000000000000..a8527333a25e9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallRejectReason.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** Defines values for CallRejectReason. */ +public final class CallRejectReason extends ExpandableStringEnum { + /** Static value none for CallRejectReason. */ + public static final CallRejectReason NONE = fromString("none"); + + /** Static value busy for CallRejectReason. */ + public static final CallRejectReason BUSY = fromString("busy"); + + /** Static value forbidden for CallRejectReason. */ + public static final CallRejectReason FORBIDDEN = fromString("forbidden"); + + /** + * Creates or finds a CallRejectReason from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallRejectReason. + */ + public static CallRejectReason fromString(String name) { + return fromString(name, CallRejectReason.class); + } + + /** @return known CallRejectReason values. */ + public static Collection values() { + return values(CallRejectReason.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallResult.java new file mode 100644 index 0000000000000..cc62d51d83b3d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallResult.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.CallConnection; +import com.azure.communication.callautomation.CallConnectionAsync; + +/** + * The abstract class used as parent of [action]CallResult + */ +public abstract class CallResult { + /* + * The callConnectionProperties + */ + private final CallConnectionProperties callConnectionProperties; + + /* + * The callConnection + */ + private final CallConnection callConnection; + + /* + * The callConnectionAsync + */ + private final CallConnectionAsync callConnectionAsync; + + CallResult(CallConnectionProperties callConnectionProperties, CallConnection callConnection, CallConnectionAsync callConnectionAsync) { + this.callConnectionProperties = callConnectionProperties; + this.callConnection = callConnection; + this.callConnectionAsync = callConnectionAsync; + } + + /** + * Get the callConnectionProperties. + * + * @return the callConnectionProperties. + */ + public CallConnectionProperties getCallConnectionProperties() { + return callConnectionProperties; + } + + /** + * Get the callConnection. + * + * @return the callConnection. + */ + public CallConnection getCallConnection() { + return callConnection; + } + + /** + * Get the callConnectionAsync. + * + * @return the callConnectionAsync. + */ + public CallConnectionAsync getCallConnectionAsync() { + return callConnectionAsync; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallSource.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallSource.java new file mode 100644 index 0000000000000..33de34ad68b65 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallSource.java @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.PhoneNumberIdentifier; +import com.azure.core.annotation.Fluent; + +/** The CallSource model. */ +@Fluent +public final class CallSource { + /* + * The alternate identity of the source of the call if dialing out to a + * pstn number + */ + private PhoneNumberIdentifier callerId; + + /* + * The identifier property. + */ + private final CommunicationIdentifier identifier; + + /** + * Constructor of the class + * + * @param identifier the identifier value to set. Required. + */ + public CallSource(CommunicationIdentifier identifier) { + this.identifier = identifier; + } + + /** + * Get the callerId property: The alternate identity of the source of the call if dialing out to a pstn number. + * + * @return the callerId value. + */ + public PhoneNumberIdentifier getCallerId() { + return this.callerId; + } + + /** + * Set the callerId property: The alternate identity of the source of the call if dialing out to a pstn number. + * + * @param callerId the callerId value to set. + * @return the CallSource object itself. + */ + public CallSource setCallerId(PhoneNumberIdentifier callerId) { + this.callerId = callerId; + return this; + } + + /** + * Get the identifier property: The identifier property. + * + * @return the identifier value. + */ + public CommunicationIdentifier getIdentifier() { + return this.identifier; + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingOperationStatus.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingOperationStatus.java new file mode 100644 index 0000000000000..2194b50cb247b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingOperationStatus.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collection; + +/** Defines values for CallingOperationStatus. */ +public final class CallingOperationStatus extends ExpandableStringEnum { + /** Static value notStarted for CallingOperationStatus. */ + public static final CallingOperationStatus NOT_STARTED = fromString("notStarted"); + + /** Static value running for CallingOperationStatus. */ + public static final CallingOperationStatus RUNNING = fromString("running"); + + /** Static value completed for CallingOperationStatus. */ + public static final CallingOperationStatus COMPLETED = fromString("completed"); + + /** Static value failed for CallingOperationStatus. */ + public static final CallingOperationStatus FAILED = fromString("failed"); + + /** + * Creates or finds a CallingOperationStatus from its string representation. + * + * @param name a name to look for. + * @return the corresponding CallingOperationStatus. + */ + public static CallingOperationStatus fromString(String name) { + return fromString(name, CallingOperationStatus.class); + } + + /** Return the values. + * @return known CallingOperationStatus values. + * */ + public static Collection values() { + return values(CallingOperationStatus.class); + } + + /** + * Private constructor + */ + private CallingOperationStatus() { + + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerError.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerError.java new file mode 100644 index 0000000000000..9d55d7273817b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerError.java @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Immutable; + +import java.util.List; + +/** The Calling Server error. */ +@Immutable +public final class CallingServerError { + /* + * The error code. + */ + private final String code; + + /* + * The error message. + */ + private final String message; + + /* + * The error target. + */ + private final String target; + + /* + * Further details about specific errors that led to this error. + */ + private final List details; + + /* + * The inner error if any. + */ + private final CallingServerError innerError; + + /** + * Get the code property: The error code. + * + * @return the code value. + */ + public String getCode() { + return code; + } + + /** + * Get the message property: The error message. + * + * @return the message value. + */ + public String getMessage() { + return message; + } + + /** + * Get the target property: The error target. + * + * @return the target value. + */ + public String getTarget() { + return target; + } + + /** + * Get the details property: Further details about specific errors that led to + * this error. + * + * @return the details value. + */ + public List getDetails() { + return details; + } + + /** + * Get the innerError property: The inner error if any. + * + * @return the innerError value. + */ + public CallingServerError getInnerError() { + return innerError; + } + + /** + * Constructs a new CallingServerError + * @param message The message of the original error + * @param code The error code + * @param target The target of the error + * @param details Additional details + * @param innerError The inner error + */ + CallingServerError( + String message, + String code, String target, + List details, + CallingServerError innerError) { + this.message = message; + this.code = code; + this.target = target; + this.details = details; + this.innerError = innerError; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerErrorException.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerErrorException.java new file mode 100644 index 0000000000000..88ccb1c13cfd9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CallingServerErrorException.java @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.communication.callautomation.implementation.models.CommunicationError; +import com.azure.communication.callautomation.implementation.models.CommunicationErrorResponse; +import com.azure.core.annotation.Immutable; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpResponse; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Exception thrown for an invalid response with {@link CallingServerError} information. + **/ +@Immutable +public final class CallingServerErrorException extends HttpResponseException { + /** + * Initializes a new instance of the CallingServerResponseException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + */ + CallingServerErrorException(String message, HttpResponse response) { + super(message, response); + } + + /** + * Initializes a new instance of the CallingServerErrorException class. + * + * @param message the exception message or the response content if a message is not available. + * @param response the HTTP response. + * @param value the deserialized response value. + */ + CallingServerErrorException(String message, HttpResponse response, CallingServerError value) { + super(message, response, value); + } + + /** + * Public constructor + */ + public CallingServerErrorException() { + super(null, null, null); + } + + static { + ErrorConstructorProxy.setAccessor( + new ErrorConstructorProxy.ErrorConstructorAccessor() { + @Override + public CallingServerErrorException create(HttpResponseException internalHeaders) { + CallingServerError error = null; + if (internalHeaders.getValue() != null) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + CommunicationErrorResponse communicationErrorResponse = objectMapper.convertValue( + internalHeaders.getValue(), CommunicationErrorResponse.class); + error = convert(communicationErrorResponse.getError()); + } + return new CallingServerErrorException(internalHeaders.getMessage(), internalHeaders.getResponse(), error); + } + }); + } + + /** + * Maps from {@link CommunicationError} to {@link CallingServerError}. + */ + private static CallingServerError convert(CommunicationError communicationError) { + if (communicationError == null) { + return null; + } + + List details = new ArrayList<>(); + + if (communicationError.getDetails() != null) { + details = communicationError + .getDetails() + .stream() + .map(CallingServerErrorException::convert) + .collect(Collectors.toList()); + } + + return new CallingServerError( + communicationError.getMessage(), + communicationError.getCode(), + communicationError.getTarget(), + details, + convert(communicationError.getInnererror()) + ); + } + + @Override + public CallingServerError getValue() { + return (CallingServerError) super.getValue(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ChannelAffinity.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ChannelAffinity.java new file mode 100644 index 0000000000000..b66331970eb54 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ChannelAffinity.java @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** Channel affinity for a participant. */ +@Fluent +public final class ChannelAffinity { + /* + * Channel number to which bitstream from a particular participant will be + * written. + */ + @JsonProperty(value = "channel") + private final Integer channel; + + /* + * The identifier for the participant whose bitstream will be written to + * the channel + * represented by the channel number. + */ + @JsonProperty(value = "participant") + private final CommunicationIdentifier participant; + + /** + * Constructor + * + * @param channel Either a {@link GroupCallLocator} or {@link ServerCallLocator} for locating the call. + * @param participant Either a {@link GroupCallLocator} or {@link ServerCallLocator} for locating the call. + */ + public ChannelAffinity(Integer channel, CommunicationIdentifier participant) { + this.channel = channel; + this.participant = participant; + } + + /** + * Get the channel property: Channel number to which bitstream from a particular participant will be written. + * + * @return the channel value. + */ + public Integer getChannel() { + return this.channel; + } + + /** + * Get the participant property: The identifier for the participant whose bitstream will be written to the channel + * represented by the channel number. + * + * @return the participant value. + */ + public CommunicationIdentifier getParticipant() { + return this.participant; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallOptions.java new file mode 100644 index 0000000000000..b84eb48c0e3b8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallOptions.java @@ -0,0 +1,147 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Fluent; + +import java.util.List; + +/** + * The options for creating a call. + */ +@Fluent +public class CreateCallOptions { + /** + * The source property. + */ + private final CommunicationIdentifier source; + + /** + * The targets of the call. + */ + private final List targets; + + /** + * The call back URI. + */ + private final String callbackUrl; + + /** + * The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + */ + private String sourceCallerId; + + /** + * The subject + */ + private String subject; + + /** + * Media Streaming Configuration. + */ + private MediaStreamingConfiguration mediaStreamingConfiguration; + + /** + * Constructor + * + * @param source The source property. + * @param targets The targets of the call. + * @param callbackUrl The call back URI. + */ + public CreateCallOptions(CommunicationIdentifier source, List targets, String callbackUrl) { + this.source = source; + this.targets = targets; + this.callbackUrl = callbackUrl; + } + + /** + * Get the source. + * + * @return the source value. + */ + public CommunicationIdentifier getSource() { + return source; + } + + /** + * Get the targets. + * + * @return the targets list. + */ + public List getTargets() { + return targets; + } + + /** + * Get the call back uri. + * + * @return the call back uri. + */ + public String getCallbackUrl() { + return callbackUrl; + } + + /** + * Get the subject. + * + * @return the subject value. + */ + public String getSubject() { + return subject; + } + + /** + * Get the source caller Id that's shown to the PSTN participant being invited. + * + * @return the sourceCallerId value. + */ + public String getSourceCallerId() { + return sourceCallerId; + } + + /** + * Get the Media Streaming configuration. + * + * @return the mediaStreamingConfiguration. + */ + public MediaStreamingConfiguration getMediaStreamingConfiguration() { + return mediaStreamingConfiguration; + } + + /** + * Set the subject. + * + * @param subject the subject. + * @return the CreateCallOptions object itself. + */ + public CreateCallOptions setSubject(String subject) { + this.subject = subject; + return this; + } + + /** + * Set the sourceCallerId. + * + * @param sourceCallerId The source caller Id that's shown to the PSTN participant being invited. + * Required only when inviting a PSTN participant. + * @return the CreateCallOptions object itself. + */ + public CreateCallOptions setSourceCallerId(String sourceCallerId) { + this.sourceCallerId = sourceCallerId; + return this; + } + + /** + * Set the media streaming configuration. + * + * @param mediaStreamingConfiguration The media streaming configuration. + * @return the CreateCallOptions object itself. + */ + public CreateCallOptions setMediaStreamingConfiguration(MediaStreamingConfiguration mediaStreamingConfiguration) { + this.mediaStreamingConfiguration = mediaStreamingConfiguration; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallResult.java new file mode 100644 index 0000000000000..09cfff32ad624 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/CreateCallResult.java @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.CallConnection; +import com.azure.communication.callautomation.CallConnectionAsync; + +/** + * The result of answering a call + */ +public class CreateCallResult extends CallResult { + + /** + * Constructor + * + * @param callConnectionProperties The callConnectionProperties + * @param callConnection The callConnection + * @param callConnectionAsync The callConnectionAsync + */ + public CreateCallResult(CallConnectionProperties callConnectionProperties, CallConnection callConnection, CallConnectionAsync callConnectionAsync) { + super(callConnectionProperties, callConnection, callConnectionAsync); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DownloadToFileOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DownloadToFileOptions.java new file mode 100644 index 0000000000000..94602a3240571 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DownloadToFileOptions.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; + +/** + * The options for the downloadTo operations. + */ +@Fluent +public class DownloadToFileOptions { + + /** + * Parallel download options object. + */ + private ParallelDownloadOptions parallelDownloadOptions; + + /** + * Overwrite If file/stream exists + */ + private boolean overwrite; + + /** + * Get the ParallelDownloadOptions + * @return ParallelDownloadOptions + */ + public ParallelDownloadOptions getParallelDownloadOptions() { + return parallelDownloadOptions; + } + + /** + * Overwrite value. + * @return the overwrite value. + */ + public boolean isOverwrite() { + return overwrite; + } + + /** + * Set the parallel download options. + * + * @param parallelDownloadOptions parallel download options. + * @return the DownloadToOptions object itself. + */ + public DownloadToFileOptions setParallelDownloadOptions(ParallelDownloadOptions parallelDownloadOptions) { + this.parallelDownloadOptions = parallelDownloadOptions; + return this; + } + + /** + * Set the overwrite value. + * + * @param overwrite the overwrite value. + * @return the DownloadToOptions object itself. + */ + public DownloadToFileOptions setOverwrite(boolean overwrite) { + this.overwrite = overwrite; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DtmfConfigurations.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DtmfConfigurations.java new file mode 100644 index 0000000000000..224d8b3101ae0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/DtmfConfigurations.java @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.Duration; +import java.util.List; + +/** Options for DTMF recognition. */ +@Fluent +public final class DtmfConfigurations { + /* + * Time to wait between DTMF inputs to stop recognizing. + */ + @JsonProperty(value = "interToneTimeoutInSeconds") + private Duration interToneTimeoutInSeconds; + + /* + * Maximum number of DTMFs to be collected. + */ + @JsonProperty(value = "maxTonesToCollect") + private Integer maxTonesToCollect; + + /* + * List of tones that will stop recognizing. + */ + @JsonProperty(value = "stopTones") + private List stopTones; + + /** + * Get the interToneTimeoutInSeconds property: Time to wait between DTMF inputs to stop recognizing. + * + * @return the interToneTimeoutInSeconds value. + */ + public Duration getInterToneTimeoutInSeconds() { + return this.interToneTimeoutInSeconds; + } + + /** + * Set the interToneTimeoutInSeconds property: Time to wait between DTMF inputs to stop recognizing. + * + * @param interToneTimeoutInSeconds the interToneTimeoutInSeconds value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurations setInterToneTimeoutInSeconds(Duration interToneTimeoutInSeconds) { + this.interToneTimeoutInSeconds = interToneTimeoutInSeconds; + return this; + } + + /** + * Get the maxTonesToCollect property: Maximum number of DTMFs to be collected. + * + * @return the maxTonesToCollect value. + */ + public Integer getMaxTonesToCollect() { + return this.maxTonesToCollect; + } + + /** + * Set the maxTonesToCollect property: Maximum number of DTMFs to be collected. + * + * @param maxTonesToCollect the maxTonesToCollect value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurations setMaxTonesToCollect(Integer maxTonesToCollect) { + this.maxTonesToCollect = maxTonesToCollect; + return this; + } + + /** + * Get the stopTones property: List of tones that will stop recognizing. + * + * @return the stopTones value. + */ + public List getStopTones() { + return this.stopTones; + } + + /** + * Set the stopTones property: List of tones that will stop recognizing. + * + * @param stopTones the stopTones value to set. + * @return the DtmfConfigurationsInternal object itself. + */ + public DtmfConfigurations setStopTones(List stopTones) { + this.stopTones = stopTones; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/FileSource.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/FileSource.java new file mode 100644 index 0000000000000..98b1250ec0e9e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/FileSource.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The FileSource model. */ +@Fluent +public final class FileSource extends PlaySource { + /* + * Uri for the audio file to be played + */ + @JsonProperty(value = "uri", required = true) + private String uri; + + /** + * Get the uri property: Uri for the audio file to be played. + * + * @return the uri value. + */ + public String getUri() { + return this.uri; + } + + /** + * Set the uri property: Uri for the audio file to be played. + * + * @param uri the uri value to set. + * @return the FileSourceInternal object itself. + */ + public FileSource setUri(String uri) { + this.uri = uri; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/GroupCallLocator.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/GroupCallLocator.java new file mode 100644 index 0000000000000..f61081cd58255 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/GroupCallLocator.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Immutable; + +/** The locator used for joining or taking action on a call. */ +@Immutable +public final class GroupCallLocator extends CallLocator { + /* + * The group call id + */ + private final String groupCallId; + + /** + * Group call locator + * + * @param groupCallId Specify the group call id. + */ + public GroupCallLocator(String groupCallId) { + super(CallLocatorKind.GROUP_CALL_LOCATOR); + this.groupCallId = groupCallId; + } + + /** + * Get the groupCallId property: The group call id. + * + * @return the groupCallId value. + */ + public String getGroupCallId() { + return this.groupCallId; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ListParticipantsResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ListParticipantsResult.java new file mode 100644 index 0000000000000..af573e27e68ce --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ListParticipantsResult.java @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.ListParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.converters.CallParticipantConverter; +import com.azure.communication.callautomation.implementation.models.GetParticipantsResponseInternal; +import com.azure.core.annotation.Immutable; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** The ListParticipantsResult model. */ +@Immutable +public final class ListParticipantsResult { + /* + * The list of participants in the call. + */ + private final List values; + + static { + ListParticipantsResponseConstructorProxy.setAccessor( + new ListParticipantsResponseConstructorProxy.ListParticipantsResponseConstructorAccessor() { + @Override + public ListParticipantsResult create(GetParticipantsResponseInternal internalHeaders) { + return new ListParticipantsResult(internalHeaders); + } + }); + } + + /** + * Public constructor. + * + */ + public ListParticipantsResult() { + this.values = null; + } + + /** + * Package-private constructor of the class, used internally only. + * + * @param getParticipantsResponseInternal The response from the service. + */ + ListParticipantsResult(GetParticipantsResponseInternal getParticipantsResponseInternal) { + Objects.requireNonNull(getParticipantsResponseInternal, "transferCallResponseInternal must not be null"); + + this.values = getParticipantsResponseInternal + .getValues() + .stream() + .map(CallParticipantConverter::convert).collect(Collectors.toList()); + } + + /** + * Get the values property: The list of participants in the call. + * + * @return The list of participants in the call. + */ + public List getValues() { + return this.values; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingAudioChannelType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingAudioChannelType.java new file mode 100644 index 0000000000000..fb99061be9004 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingAudioChannelType.java @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingAudioChannelType. */ +public final class MediaStreamingAudioChannelType extends ExpandableStringEnum { + /** Static value mixed for MediaStreamingAudioChannelType. */ + public static final MediaStreamingAudioChannelType MIXED = fromString("mixed"); + + /** Static value unmixed for MediaStreamingAudioChannelType. */ + public static final MediaStreamingAudioChannelType UNMIXED = fromString("unmixed"); + + /** + * Creates or finds a MediaStreamingAudioChannelType from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingAudioChannelType. + */ + @JsonCreator + public static MediaStreamingAudioChannelType fromString(String name) { + return fromString(name, MediaStreamingAudioChannelType.class); + } + + /** @return known MediaStreamingAudioChannelType values. */ + public static Collection values() { + return values(MediaStreamingAudioChannelType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingConfiguration.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingConfiguration.java new file mode 100644 index 0000000000000..1d88352ef46da --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingConfiguration.java @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The MediaStreamingConfigurationInternal model. */ +@Fluent +public final class MediaStreamingConfiguration { + /* + * Transport URL for media streaming + */ + @JsonProperty(value = "transportUrl") + private final String transportUrl; + + /* + * The type of tranport to be used for media streaming, eg. Websocket + */ + @JsonProperty(value = "transportType") + private final MediaStreamingTransportType transportType; + + /* + * Content type to stream, eg. audio, audio/video + */ + @JsonProperty(value = "contentType") + private final MediaStreamingContentType contentType; + + /* + * Audio channel type to stream, eg. unmixed audio, mixed audio + */ + @JsonProperty(value = "audioChannelType") + private final MediaStreamingAudioChannelType audioChannelType; + + /** + * Creates a new instance of MediaStreamingConfiguration + * @param transportUrl - The Transport URL + * @param transportType - Transport type + * @param contentType - Content Type + * @param audioChannelType - Audio Channel Type + */ + public MediaStreamingConfiguration(String transportUrl, MediaStreamingTransportType transportType, MediaStreamingContentType contentType, MediaStreamingAudioChannelType audioChannelType) { + this.transportUrl = transportUrl; + this.transportType = transportType; + this.contentType = contentType; + this.audioChannelType = audioChannelType; + } + + /** + * Get the transportUrl property: Transport URL for media streaming. + * + * @return the transportUrl value. + */ + public String getTransportUrl() { + return this.transportUrl; + } + + /** + * Get the transportType property: The type of tranport to be used for media streaming, eg. Websocket. + * + * @return the transportType value. + */ + public MediaStreamingTransportType getTransportType() { + return this.transportType; + } + + /** + * Get the contentType property: Content type to stream, eg. audio, audio/video. + * + * @return the contentType value. + */ + public MediaStreamingContentType getContentType() { + return this.contentType; + } + + /** + * Get the audioChannelType property: Audio channel type to stream, eg. unmixed audio, mixed audio. + * + * @return the audioChannelType value. + */ + public MediaStreamingAudioChannelType getAudioChannelType() { + return this.audioChannelType; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingContentType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingContentType.java new file mode 100644 index 0000000000000..3e68a47902090 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingContentType.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingContentType. */ +public final class MediaStreamingContentType extends ExpandableStringEnum { + /** Static value audio for MediaStreamingContentType. */ + public static final MediaStreamingContentType AUDIO = fromString("audio"); + + /** + * Creates or finds a MediaStreamingContentType from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingContentType. + */ + @JsonCreator + public static MediaStreamingContentType fromString(String name) { + return fromString(name, MediaStreamingContentType.class); + } + + /** @return known MediaStreamingContentType values. */ + public static Collection values() { + return values(MediaStreamingContentType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingTransportType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingTransportType.java new file mode 100644 index 0000000000000..a697f68320ba9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/MediaStreamingTransportType.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for MediaStreamingTransportType. */ +public final class MediaStreamingTransportType extends ExpandableStringEnum { + /** Static value websocket for MediaStreamingTransportType. */ + public static final MediaStreamingTransportType WEBSOCKET = fromString("websocket"); + + /** + * Creates or finds a MediaStreamingTransportType from its string representation. + * + * @param name a name to look for. + * @return the corresponding MediaStreamingTransportType. + */ + @JsonCreator + public static MediaStreamingTransportType fromString(String name) { + return fromString(name, MediaStreamingTransportType.class); + } + + /** @return known MediaStreamingTransportType values. */ + public static Collection values() { + return values(MediaStreamingTransportType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ParallelDownloadOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ParallelDownloadOptions.java new file mode 100644 index 0000000000000..62b0c7eefd0dd --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ParallelDownloadOptions.java @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.Constants.ContentDownloader; +import com.azure.core.annotation.Fluent; +import com.azure.core.util.ProgressListener; + +import java.util.Locale; + +/** + * This class contains configuration used to parallelize data transfer operations. Note that not all values are used + * by every method which accepts this type. Please refer to the javadoc on specific methods for these cases. + */ +@Fluent +public final class ParallelDownloadOptions { + private static final String PARAMETER_NOT_IN_RANGE = "The value of the parameter '%s' should be between %s and %s."; + + private long blockSize; + private int maxConcurrency; + private ProgressListener progressListener; + + /** + * Creates a new {@link ParallelDownloadOptions} with default parameters applied. + */ + public ParallelDownloadOptions() { + maxConcurrency = 1; + blockSize = ContentDownloader.DEFAULT_BUFFER_SIZE; + } + + /** + * Gets the block size (chunk size) to transfer at a time. + * @return The block size. + */ + public Long getBlockSize() { + return blockSize; + } + + + /** + * Sets the block size. + * The block size is the size of each data chunk returned from the service. + * For both applications, If block size is large, download will make fewer network calls, but each + * individual call will receive more data and will therefore take longer. + * + * @param blockSize The block size. + * @return The ParallelDownloadOptions object itself. + */ + public ParallelDownloadOptions setBlockSize(long blockSize) { + assertInBounds("blockSize", blockSize, 1, Long.MAX_VALUE); + this.blockSize = blockSize; + return this; + } + + /** + * Gets the Progress listener for parallel reporting + * @return The progress listener + */ + public ProgressListener getProgressListener() { + return progressListener; + } + + /** + * Sets the {@link ProgressListener}. + * + * @param progressListener The {@link ProgressListener}. + * @return The ParallelDownloadOptions object itself. + */ + public ParallelDownloadOptions setProgressReceiver(ProgressListener progressListener) { + this.progressListener = progressListener; + return this; + } + + /** + * Gets the maximum number of parallel requests that will be issued at any given time. + * @return The max concurrency value. + */ + public int getMaxConcurrency() { + return maxConcurrency; + } + + /** + * @param maxConcurrency The maximum number of parallel requests that will be issued at any given time as a part of + * a single parallel transfer. This value applies per api. For example, if two calls to downloadTo are made at + * the same time, and each specifies a maxConcurrency of 5, there may be up to 10 outstanding, concurrent requests, + * up to 5 for each of the upload operations. + * The amount of memory consumed by methods which buffer may be up to blockSize * maxConcurrency. + * @return The ParallelDownloadOptions object itself. + */ + public ParallelDownloadOptions setMaxConcurrency(int maxConcurrency) { + assertInBounds("numBuffers", maxConcurrency, 1, Integer.MAX_VALUE); + this.maxConcurrency = maxConcurrency; + return this; + } + + /** + * Asserts that the specified number is in the valid range. The range is inclusive. + * + * @param param Name of the parameter + * @param value Value of the parameter + * @param min The minimum allowed value + * @param max The maximum allowed value + * @throws IllegalArgumentException If {@code value} is less than {@code min} or {@code value} is greater than + * {@code max}. + */ + static void assertInBounds(final String param, final long value, final long min, final long max) { + if (value < min || value > max) { + throw new IllegalArgumentException(String.format(Locale.ROOT, + PARAMETER_NOT_IN_RANGE, param, min, max)); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlayOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlayOptions.java new file mode 100644 index 0000000000000..15829d7a53631 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlayOptions.java @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; + +/** The PlayOptionsInternal model. */ +@Fluent +public final class PlayOptions { + /* + * The option to play the provided audio source in loop when set to true + */ + private boolean loop; + + /* + * The operation context + */ + private String operationContext; + + /** + * Get the loop property: The option to play the provided audio source in loop when set to true. + * + * @return the loop value. + */ + public boolean isLoop() { + return this.loop; + } + + /** + * Get the operationContext property. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the loop property: The option to play the provided audio source in loop when set to true. + * + * @param loop the loop value to set. + * @return the PlayOptionsInternal object itself. + */ + public PlayOptions setLoop(boolean loop) { + this.loop = loop; + return this; + } + + /** + * Set the operationContext property. + * + * @param operationContext the operationContext value to set. + * @return the PlayOptionsInternal object itself. + */ + public PlayOptions setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySource.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySource.java new file mode 100644 index 0000000000000..ff48d8fdec129 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySource.java @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PlaySource model. */ +@Fluent +public abstract class PlaySource { + /* + * Defines the identifier to be used for caching related media + */ + @JsonProperty(value = "playSourceId") + private String playSourceId; + + /** + * Get the playSourceId property: Defines the identifier to be used for caching related media. + * + * @return the playSourceId value. + */ + public String getPlaySourceId() { + return this.playSourceId; + } + + /** + * Set the playSourceId property: Defines the identifier to be used for caching related media. + * + * @param playSourceId the playSourceId value to set. + * @return the PlaySourceInternal object itself. + */ + public PlaySource setPlaySourceId(String playSourceId) { + this.playSourceId = playSourceId; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySourceType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySourceType.java new file mode 100644 index 0000000000000..bd38a8849f2c1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/PlaySourceType.java @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; + +import java.util.Collection; + +/** Defines values for PlaySourceType. */ +public final class PlaySourceType extends ExpandableStringEnum { + /** Static value file for PlaySourceType. */ + public static final PlaySourceType FILE = fromString("file"); + + /** + * Creates or finds a PlaySourceType from its string representation. + * + * @param name a name to look for. + * @return the corresponding PlaySourceType. + */ + public static PlaySourceType fromString(String name) { + return fromString(name, PlaySourceType.class); + } + + /** @return known PlaySourceType values. */ + public static Collection values() { + return values(PlaySourceType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeConfigurations.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeConfigurations.java new file mode 100644 index 0000000000000..748d1057c6ac8 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeConfigurations.java @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.Duration; + +/** The RecognizeConfigurations model. */ +@Fluent +public final class RecognizeConfigurations { + /* + * Determines if we interrupt the prompt and start recognizing. + */ + @JsonProperty(value = "interruptPromptAndStartRecognition") + private Boolean interruptPromptAndStartRecognition; + + /* + * Time to wait for first input after prompt (if any). + */ + @JsonProperty(value = "initialSilenceTimeoutInSeconds") + private Duration initialSilenceTimeoutInSeconds; + + /* + * Target participant of DTFM tone recognition. + */ + @JsonProperty(value = "targetParticipant") + private CommunicationIdentifier targetParticipant; + + /* + * Defines configurations for DTMF. + */ + @JsonProperty(value = "dtmfConfigurations") + private DtmfConfigurations dtmfConfigurations; + + /** + * Get the interruptPromptAndStartRecognition property: Determines if we interrupt the prompt and start recognizing. + * + * @return the interruptPromptAndStartRecognition value. + */ + public Boolean isInterruptPromptAndStartRecognition() { + return this.interruptPromptAndStartRecognition; + } + + /** + * Set the interruptPromptAndStartRecognition property: Determines if we interrupt the prompt and start recognizing. + * + * @param interruptPromptAndStartRecognition the interruptPromptAndStartRecognition value to set. + * @return the RecognizeConfigurations object itself. + */ + public RecognizeConfigurations setInterruptPromptAndStartRecognition( + Boolean interruptPromptAndStartRecognition) { + this.interruptPromptAndStartRecognition = interruptPromptAndStartRecognition; + return this; + } + + /** + * Get the initialSilenceTimeoutInSeconds property: Time to wait for first input after prompt (if any). + * + * @return the initialSilenceTimeoutInSeconds value. + */ + public Duration getInitialSilenceTimeoutInSeconds() { + return this.initialSilenceTimeoutInSeconds; + } + + /** + * Set the initialSilenceTimeoutInSeconds property: Time to wait for first input after prompt (if any). + * + * @param initialSilenceTimeoutInSeconds the initialSilenceTimeoutInSeconds value to set. + * @return the RecognizeConfigurations object itself. + */ + public RecognizeConfigurations setInitialSilenceTimeoutInSeconds(Duration initialSilenceTimeoutInSeconds) { + this.initialSilenceTimeoutInSeconds = initialSilenceTimeoutInSeconds; + return this; + } + + /** + * Get the targetParticipant property: Target participant of DTFM tone recognition. + * + * @return the targetParticipant value. + */ + public CommunicationIdentifier getTargetParticipant() { + return this.targetParticipant; + } + + /** + * Set the targetParticipant property: Target participant of DTFM tone recognition. + * + * @param targetParticipant the targetParticipant value to set. + * @return the RecognizeConfigurations object itself. + */ + public RecognizeConfigurations setTargetParticipant(CommunicationIdentifier targetParticipant) { + this.targetParticipant = targetParticipant; + return this; + } + + /** + * Get the dtmfConfigurations property: Defines configurations for DTMF. + * + * @return the dtmfConfigurations value. + */ + public DtmfConfigurations getDtmfConfigurations() { + return this.dtmfConfigurations; + } + + /** + * Set the dtmfConfigurations property: Defines configurations for DTMF. + * + * @param dtmfConfigurations the dtmfConfigurations value to set. + * @return the RecognizeConfigurations object itself. + */ + public RecognizeConfigurations setDtmfConfigurations(DtmfConfigurations dtmfConfigurations) { + this.dtmfConfigurations = dtmfConfigurations; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeInputType.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeInputType.java new file mode 100644 index 0000000000000..c9877d5277b4a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeInputType.java @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for RecognizeInputTypeInternal. */ +public final class RecognizeInputType extends ExpandableStringEnum { + /** Static value dtmf for RecognizeInputTypeInternal. */ + public static final RecognizeInputType DTMF = fromString("dtmf"); + + /** + * Creates or finds a RecognizeInputTypeInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecognizeInputTypeInternal. + */ + @JsonCreator + public static RecognizeInputType fromString(String name) { + return fromString(name, RecognizeInputType.class); + } + + /** @return known RecognizeInputTypeInternal values. */ + public static Collection values() { + return values(RecognizeInputType.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeOptions.java new file mode 100644 index 0000000000000..646ae34bc81ee --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecognizeOptions.java @@ -0,0 +1,153 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** Options to configure the Recognize operation **/ +public class RecognizeOptions { + /* + * Determines the type of the recognition. + */ + @JsonProperty(value = "recognizeInputType", required = true) + private RecognizeInputType recognizeInputType; + + /* + * The source of the audio to be played for recognition. + */ + @JsonProperty(value = "playPrompt") + private PlaySource playPrompt; + + /* + * If set recognize can barge into other existing + * queued-up/currently-processing requests. + */ + @JsonProperty(value = "stopCurrentOperations") + private Boolean stopCurrentOperations; + + /* + * Defines options for recognition. + */ + @JsonProperty(value = "recognizeConfiguration", required = true) + private RecognizeConfigurations recognizeConfiguration; + + /* + * The value to identify context of the operation. + */ + @JsonProperty(value = "operationContext") + private String operationContext; + + /** + * Initializes a RecognizeOptions object. + * @param recognizeInputType What input the operation should recognize. + * @param recognizeConfigurations Configurations for the recognize operations. + */ + public RecognizeOptions(RecognizeInputType recognizeInputType, RecognizeConfigurations recognizeConfigurations) { + this.recognizeInputType = recognizeInputType; + this.recognizeConfiguration = recognizeConfigurations; + } + + /** + * Get the recognizeInputType property: Determines the type of the recognition. + * + * @return the recognizeInputType value. + */ + public RecognizeInputType getRecognizeInputType() { + return this.recognizeInputType; + } + + /** + * Set the recognizeInputType property: Determines the type of the recognition. + * + * @param recognizeInputType the recognizeInputType value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeOptions setRecognizeInputType(RecognizeInputType recognizeInputType) { + this.recognizeInputType = recognizeInputType; + return this; + } + + /** + * Get the playPrompt property: The source of the audio to be played for recognition. + * + * @return the playPrompt value. + */ + public PlaySource getPlayPrompt() { + return this.playPrompt; + } + + /** + * Set the playPrompt property: The source of the audio to be played for recognition. + * + * @param playPrompt the playPrompt value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeOptions setPlayPrompt(PlaySource playPrompt) { + this.playPrompt = playPrompt; + return this; + } + + /** + * Get the stopCurrentOperations property: If set recognize can barge into other existing + * queued-up/currently-processing requests. + * + * @return the stopCurrentOperations value. + */ + public Boolean isStopCurrentOperations() { + return this.stopCurrentOperations; + } + + /** + * Set the stopCurrentOperations property: If set recognize can barge into other existing + * queued-up/currently-processing requests. + * + * @param stopCurrentOperations the stopCurrentOperations value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeOptions setStopCurrentOperations(Boolean stopCurrentOperations) { + this.stopCurrentOperations = stopCurrentOperations; + return this; + } + + /** + * Get the recognizeConfiguration property: Defines options for recognition. + * + * @return the recognizeConfiguration value. + */ + public RecognizeConfigurations getRecognizeConfiguration() { + return this.recognizeConfiguration; + } + + /** + * Set the recognizeConfiguration property: Defines options for recognition. + * + * @param recognizeConfiguration the recognizeConfiguration value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeOptions setRecognizeConfiguration(RecognizeConfigurations recognizeConfiguration) { + this.recognizeConfiguration = recognizeConfiguration; + return this; + } + + /** + * Get the operationContext property: The value to identify context of the operation. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Set the operationContext property: The value to identify context of the operation. + * + * @param operationContext the operationContext value to set. + * @return the RecognizeRequest object itself. + */ + public RecognizeOptions setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } + +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingChannel.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingChannel.java new file mode 100644 index 0000000000000..04c07477dcc05 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingChannel.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** Defines values for RecordingChannel. */ +public final class RecordingChannel extends ExpandableStringEnum { + /** Static value mixed for RecordingChannel. */ + public static final RecordingChannel MIXED = fromString("mixed"); + + /** Static value unmixed for RecordingChannel. */ + public static final RecordingChannel UNMIXED = fromString("unmixed"); + + /** + * Creates or finds a RecordingChannel from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingChannel. + */ + public static RecordingChannel fromString(String name) { + return fromString(name, RecordingChannel.class); + } + + /** @return known RecordingChannel values. */ + public static Collection values() { + return values(RecordingChannel.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingContent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingContent.java new file mode 100644 index 0000000000000..a71e4dc032295 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingContent.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** Defines values for RecordingContent. */ +public final class RecordingContent extends ExpandableStringEnum { + /** Static value audio for RecordingContent. */ + public static final RecordingContent AUDIO = fromString("audio"); + + /** Static value audioVideo for RecordingContent. */ + public static final RecordingContent AUDIO_VIDEO = fromString("audioVideo"); + + /** + * Creates or finds a RecordingContent from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingContent. + */ + public static RecordingContent fromString(String name) { + return fromString(name, RecordingContent.class); + } + + /** @return known RecordingContent values. */ + public static Collection values() { + return values(RecordingContent.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingFormat.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingFormat.java new file mode 100644 index 0000000000000..2ee6bb38fe753 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingFormat.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** Defines values for RecordingFormat. */ +public final class RecordingFormat extends ExpandableStringEnum { + /** Static value wav for RecordingFormat. */ + public static final RecordingFormat WAV = fromString("wav"); + + /** Static value mp3 for RecordingFormat. */ + public static final RecordingFormat MP3 = fromString("mp3"); + + /** Static value mp4 for RecordingFormat. */ + public static final RecordingFormat MP4 = fromString("mp4"); + + /** + * Creates or finds a RecordingFormat from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingFormat. + */ + public static RecordingFormat fromString(String name) { + return fromString(name, RecordingFormat.class); + } + + /** @return known RecordingFormat values. */ + public static Collection values() { + return values(RecordingFormat.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingState.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingState.java new file mode 100644 index 0000000000000..1e18c94ab7c14 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingState.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** Defines values for RecordingStateInternal. */ +public final class RecordingState extends ExpandableStringEnum { + /** Static value active for RecordingStateInternal. */ + public static final RecordingState ACTIVE = fromString("active"); + + /** Static value inactive for RecordingStateInternal. */ + public static final RecordingState INACTIVE = fromString("inactive"); + + /** + * Creates or finds a RecordingStateInternal from its string representation. + * + * @param name a name to look for. + * @return the corresponding RecordingStateInternal. + */ + public static RecordingState fromString(String name) { + return fromString(name, RecordingState.class); + } + + /** @return known RecordingStateInternal values. */ + public static Collection values() { + return values(RecordingState.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingStateResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingStateResult.java new file mode 100644 index 0000000000000..0f6da16fb54b9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RecordingStateResult.java @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.RecordingStateResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.models.RecordingStateResponseInternal; +import com.azure.core.annotation.Immutable; + +/** The response payload of start call recording operation. */ +@Immutable +public final class RecordingStateResult { + static { + RecordingStateResponseConstructorProxy.setAccessor(RecordingStateResult::new); + } + /* + * The recording id of the started recording + */ + private final String recordingId; + + private final RecordingState recordingState; + + /** + * Get the recordingId property: The recording id of the started recording. + * + * @return the recordingId value. + */ + public String getRecordingId() { + return this.recordingId; + } + + /** + * Get the RecordingState property: The recording status of the recording. + * + * @return the recordingState value. + */ + public RecordingState getRecordingState() { + return this.recordingState; + } + + /** + * Public constructor. + * + */ + public RecordingStateResult() { + this.recordingId = null; + this.recordingState = null; + } + + /** + * Package-private constructor of the class, used internally only. + * + * @param recordingStateResponseInternal The response from the service + */ + RecordingStateResult(RecordingStateResponseInternal recordingStateResponseInternal) { + this.recordingId = recordingStateResponseInternal.getRecordingId(); + this.recordingState = RecordingState.fromString(recordingStateResponseInternal.getRecordingState().toString()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RemoveParticipantsResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RemoveParticipantsResult.java new file mode 100644 index 0000000000000..80528a0b1897e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/RemoveParticipantsResult.java @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.RemoveParticipantsResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsResponseInternal; +import com.azure.core.annotation.Immutable; + +import java.util.Objects; + +/** The RemoveParticipantsResult model. */ +@Immutable +public final class RemoveParticipantsResult { + /* + * The operation context provided by client. + */ + private final String operationContext; + + static { + RemoveParticipantsResponseConstructorProxy.setAccessor( + new RemoveParticipantsResponseConstructorProxy.RemoveParticipantsResponseConstructorAccessor() { + @Override + public RemoveParticipantsResult create(RemoveParticipantsResponseInternal internalHeaders) { + return new RemoveParticipantsResult(internalHeaders); + } + }); + } + + /** + * Public constructor. + * + */ + public RemoveParticipantsResult() { + this.operationContext = null; + } + + /** + * Package-private constructor of the class, used internally only. + * + * @param removeParticipantsResponseInternal The response from the service + */ + RemoveParticipantsResult(RemoveParticipantsResponseInternal removeParticipantsResponseInternal) { + Objects.requireNonNull(removeParticipantsResponseInternal, "removeParticipantsResponseInternal must not be null"); + + this.operationContext = removeParticipantsResponseInternal.getOperationContext(); + } + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ServerCallLocator.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ServerCallLocator.java new file mode 100644 index 0000000000000..1d4add76d3d69 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/ServerCallLocator.java @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Immutable; + +/** The locator used for joining or taking action on a call. */ +@Immutable +public final class ServerCallLocator extends CallLocator { + /* + * The server call id + */ + private final String serverCallId; + + /** + * Group call locator + * + * @param serverCallId Specify the group call id. + */ + public ServerCallLocator(String serverCallId) { + super(CallLocatorKind.SERVER_CALL_LOCATOR); + this.serverCallId = serverCallId; + } + + /** + * Get the serverCallId property: The server call id. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StartRecordingOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StartRecordingOptions.java new file mode 100644 index 0000000000000..fce18924339dd --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StartRecordingOptions.java @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.annotation.Fluent; + +import java.util.List; +import java.util.Objects; + +/** + * The options for creating a call. + */ +@Fluent +public class StartRecordingOptions { + /** + * Either a {@link GroupCallLocator} or {@link ServerCallLocator} for locating the call. + */ + private final CallLocator callLocator; + + private String recordingStateCallbackUrl; + + private RecordingChannel recordingChannel; + + private RecordingContent recordingContent; + + private RecordingFormat recordingFormat; + + private List channelAffinity; + + /** + * Constructor + * + * @param callLocator Either a {@link GroupCallLocator} or {@link ServerCallLocator} for locating the call. + */ + public StartRecordingOptions(CallLocator callLocator) { + Objects.requireNonNull(callLocator, "'callLocator' cannot be null."); + + this.callLocator = callLocator; + } + + /** + * Get the call locator. + * + * @return the call locator. + */ + public CallLocator getCallLocator() { + return this.callLocator; + } + + /** + * Uri to send state change callbacks. + * + * @return url to send state change callbacks. + */ + public String getRecordingStateCallbackUrl() { + return recordingStateCallbackUrl; + } + + /** + * Set the recordingStateCallbackUrl + * + * @param recordingStateCallbackUrl to send state change callbacks. + * @return the {@link StartRecordingOptions} + */ + public StartRecordingOptions setRecordingStateCallbackUrl(String recordingStateCallbackUrl) { + this.recordingStateCallbackUrl = recordingStateCallbackUrl; + return this; + } + + /** + * Get the channel property. + * + * @return the channel property. + */ + public RecordingChannel getRecordingChannel() { + return recordingChannel; + } + + /** + * Set the channel property. + * + * @param recordingChannel the {@link RecordingChannel}. + * @return the {@link StartRecordingOptions} + */ + public StartRecordingOptions setRecordingChannel(RecordingChannel recordingChannel) { + this.recordingChannel = recordingChannel; + return this; + } + + /** + * Get the content property. + * + * @return the content property. + */ + public RecordingContent getRecordingContent() { + return recordingContent; + } + + /** + * Set the content property. + * + * @param recordingContent the {@link RecordingContent}. + * @return the {@link StartRecordingOptions} + */ + public StartRecordingOptions setRecordingContent(RecordingContent recordingContent) { + this.recordingContent = recordingContent; + return this; + } + + /** + * Get the recording format. + * + * @return the recording format. + */ + public RecordingFormat getRecordingFormat() { + return recordingFormat; + } + + /** + * Set the recording format property. + * + * @param recordingFormat the {@link RecordingFormat}. + * @return the {@link StartRecordingOptions} + */ + public StartRecordingOptions setRecordingFormat(RecordingFormat recordingFormat) { + this.recordingFormat = recordingFormat; + return this; + } + + /** + * Get the channel affinity. + * + * @return the channel affinity. + */ + public List getChannelAffinity() { + return channelAffinity; + } + + /** + * Sets the channel affinity. + * + * @param channelAffinity the list of {@link ChannelAffinity}. + * @return the {@link StartRecordingOptions} + */ + public StartRecordingOptions setChannelAffinity(List channelAffinity) { + this.channelAffinity = channelAffinity; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StopTones.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StopTones.java new file mode 100644 index 0000000000000..653ad61416f4e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/StopTones.java @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.core.util.ExpandableStringEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import java.util.Collection; + +/** Defines values for StopTones. */ +public final class StopTones extends ExpandableStringEnum { + /** Static value zero for StopTones. */ + public static final StopTones ZERO = fromString("zero"); + + /** Static value one for StopTones. */ + public static final StopTones ONE = fromString("one"); + + /** Static value two for StopTones. */ + public static final StopTones TWO = fromString("two"); + + /** Static value three for StopTones. */ + public static final StopTones THREE = fromString("three"); + + /** Static value four for StopTones. */ + public static final StopTones FOUR = fromString("four"); + + /** Static value five for StopTones. */ + public static final StopTones FIVE = fromString("five"); + + /** Static value six for StopTones. */ + public static final StopTones SIX = fromString("six"); + + /** Static value seven for StopTones. */ + public static final StopTones SEVEN = fromString("seven"); + + /** Static value eight for StopTones. */ + public static final StopTones EIGHT = fromString("eight"); + + /** Static value nine for StopTones. */ + public static final StopTones NINE = fromString("nine"); + + /** Static value a for StopTones. */ + public static final StopTones A = fromString("a"); + + /** Static value b for StopTones. */ + public static final StopTones B = fromString("b"); + + /** Static value c for StopTones. */ + public static final StopTones C = fromString("c"); + + /** Static value d for StopTones. */ + public static final StopTones D = fromString("d"); + + /** Static value pound for StopTones. */ + public static final StopTones POUND = fromString("pound"); + + /** Static value asterisk for StopTones. */ + public static final StopTones ASTERISK = fromString("asterisk"); + + /** + * Creates or finds a StopTones from its string representation. + * + * @param name a name to look for. + * @return the corresponding StopTones. + */ + @JsonCreator + public static StopTones fromString(String name) { + return fromString(name, StopTones.class); + } + + /** @return known StopTones values. */ + public static Collection values() { + return values(StopTones.class); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferCallResult.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferCallResult.java new file mode 100644 index 0000000000000..0be8087caebf7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferCallResult.java @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.callautomation.implementation.accesshelpers.TransferCallResponseConstructorProxy; +import com.azure.communication.callautomation.implementation.models.TransferCallResponseInternal; +import com.azure.core.annotation.Immutable; + +import java.util.Objects; + +/** The TransferCallResult model. */ +@Immutable +public final class TransferCallResult { + /* + * The operation context provided by client. + */ + private final String operationContext; + + static { + TransferCallResponseConstructorProxy.setAccessor( + new TransferCallResponseConstructorProxy.TransferCallResponseConstructorAccessor() { + @Override + public TransferCallResult create(TransferCallResponseInternal internalHeaders) { + return new TransferCallResult(internalHeaders); + } + }); + } + + /** + * Public constructor. + * + */ + public TransferCallResult() { + this.operationContext = null; + } + + /** + * Package-private constructor of the class, used internally only. + * + * @param transferCallResponseInternal The response from the service. + */ + TransferCallResult(TransferCallResponseInternal transferCallResponseInternal) { + Objects.requireNonNull(transferCallResponseInternal, "transferCallResponseInternal must not be null"); + + this.operationContext = transferCallResponseInternal.getOperationContext(); + } + + /** + * Get the operationContext property: The operation context provided by client. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferToParticipantCallOptions.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferToParticipantCallOptions.java new file mode 100644 index 0000000000000..ef7c36c407ae6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/TransferToParticipantCallOptions.java @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models; + +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.PhoneNumberIdentifier; +import com.azure.core.annotation.Fluent; + +/** + * The options for adding participants. + */ +@Fluent +public class TransferToParticipantCallOptions { + /** + * A {@link CommunicationIdentifier} representing the target participant of this transfer. + */ + private final CommunicationIdentifier targetParticipant; + + /** + * The operational context + */ + private String operationContext; + + /** + * A {@link PhoneNumberIdentifier} representing the caller ID of the transferee, if transferring to a pstn number. + */ + private PhoneNumberIdentifier transfereeCallerId; + + /** + * The user to user information. + */ + private String userToUserInformation; + + /** + * Constructor + * + * @param targetParticipant A {@link CommunicationIdentifier} representing the target participant of this transfer. + */ + public TransferToParticipantCallOptions(CommunicationIdentifier targetParticipant) { + this.targetParticipant = targetParticipant; + } + + /** + * Get the target participant. + * + * @return the target participant. + */ + public CommunicationIdentifier getTargetParticipant() { + return targetParticipant; + } + + /** + * Get the operationContext. + * + * @return the operationContext + */ + public String getOperationContext() { + return operationContext; + } + + /** + * Get the transfereeCallerId. + * + * @return the transfereeCallerId. + */ + public PhoneNumberIdentifier getTransfereeCallerId() { + return transfereeCallerId; + } + + /** + * Get the userToUserInformation. + * + * @return the userToUserInformation + */ + public String getUserToUserInformation() { + return userToUserInformation; + } + + /** + * Set the operationContext. + * + * @param operationContext the operationContext to set + * @return the TransferToParticipantCallOptions object itself. + */ + public TransferToParticipantCallOptions setOperationContext(String operationContext) { + this.operationContext = operationContext; + return this; + } + + /** + * Set the transfereeCallerId. + * + * @param transfereeCallerId A {@link PhoneNumberIdentifier} representing the caller ID of the transferee + * if transferring to a pstn number. + * @return the TransferToParticipantCallOptions object itself. + */ + public TransferToParticipantCallOptions setSourceCallerId(PhoneNumberIdentifier transfereeCallerId) { + this.transfereeCallerId = transfereeCallerId; + return this; + } + + /** + * Set the invitationTimeoutInSeconds. + * + * @param userToUserInformation The user to user information. + * @return the TransferToParticipantCallOptions object itself. + */ + public TransferToParticipantCallOptions setUserToUserInformation(String userToUserInformation) { + this.userToUserInformation = userToUserInformation; + return this; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsFailedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsFailedEvent.java new file mode 100644 index 0000000000000..ee70cedb827f0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsFailedEvent.java @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +package com.azure.communication.callautomation.models.events; + +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** The AddParticipantsFailedEvent model. */ +@Immutable +public final class AddParticipantsFailedEvent extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + /* + * Participants failed to be added + */ + @JsonIgnore + private final List participants; + + @JsonCreator + private AddParticipantsFailedEvent(@JsonProperty("participants") List> participants) { + this.operationContext = null; + this.resultInfo = null; + + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + this.participants = participants + .stream() + .map(item -> mapper.convertValue(item, CommunicationIdentifierModel.class)) + .collect(Collectors.toList()) + .stream() + .map(CommunicationIdentifierConverter::convert) + .collect(Collectors.toList()); + } + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } + + /** + * Get the participants property: Participants failed to be added. + * + * @return the participants value. + */ + public List getParticipants() { + return this.participants; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsSucceededEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsSucceededEvent.java new file mode 100644 index 0000000000000..3ecc9e609977e --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/AddParticipantsSucceededEvent.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** The AddParticipantsSucceededEvent model. */ +@Immutable +public final class AddParticipantsSucceededEvent extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + /* + * Participants added + */ + @JsonIgnore + private final List participants; + + @JsonCreator + private AddParticipantsSucceededEvent(@JsonProperty("participants") List> participants) { + this.operationContext = null; + this.resultInfo = null; + + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + this.participants = participants + .stream() + .map(item -> mapper.convertValue(item, CommunicationIdentifierModel.class)) + .collect(Collectors.toList()) + .stream() + .map(CommunicationIdentifierConverter::convert) + .collect(Collectors.toList()); + } + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } + + /** + * Get the participants property: Participants added. + * + * @return the participants value. + */ + public List getParticipants() { + return this.participants; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallAutomationEventBase.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallAutomationEventBase.java new file mode 100644 index 0000000000000..c5dccd0b3949a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallAutomationEventBase.java @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The base event interface. */ +public abstract class CallAutomationEventBase { + /* + * Call connection ID. + */ + @JsonProperty(value = "callConnectionId") + private final String callConnectionId; + + /* + * Server call ID. + */ + @JsonProperty(value = "serverCallId") + private final String serverCallId; + + /* + * Correlation ID for event to call correlation. Also called ChainId for + * skype chain ID. + */ + @JsonProperty(value = "correlationId") + private final String correlationId; + + CallAutomationEventBase() { + this.serverCallId = null; + this.callConnectionId = null; + this.correlationId = null; + } + + /** + * Get the callConnectionId property: Call connection ID. + * + * @return the callConnectionId value. + */ + public String getCallConnectionId() { + return this.callConnectionId; + } + + /** + * Get the serverCallId property: Server call ID. + * + * @return the serverCallId value. + */ + public String getServerCallId() { + return this.serverCallId; + } + + /** + * Get the correlationId property: Correlation ID for event to call correlation. Also called ChainId for skype chain + * ID. + * + * @return the correlationId value. + */ + public String getCorrelationId() { + return this.correlationId; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallConnectedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallConnectedEvent.java new file mode 100644 index 0000000000000..f94b3881c6660 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallConnectedEvent.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; + +/** The CallConnectedEvent model. */ +@Immutable +public final class CallConnectedEvent extends CallAutomationEventBase { + private CallConnectedEvent() { + super(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallDisconnectedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallDisconnectedEvent.java new file mode 100644 index 0000000000000..1956285d3ea8d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallDisconnectedEvent.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; + +/** The CallDisconnectedEvent model. */ +@Immutable +public final class CallDisconnectedEvent extends CallAutomationEventBase { + private CallDisconnectedEvent() { + super(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferAcceptedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferAcceptedEvent.java new file mode 100644 index 0000000000000..4ff483b7770ae --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferAcceptedEvent.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CallTransferAcceptedEvent model. */ +@Immutable +public final class CallTransferAcceptedEvent extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + private CallTransferAcceptedEvent() { + this.resultInfo = null; + this.operationContext = null; + } + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferFailedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferFailedEvent.java new file mode 100644 index 0000000000000..6b40f4b7965b7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/CallTransferFailedEvent.java @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The CallTransferFailedEvent model. */ +@Immutable +public final class CallTransferFailedEvent extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + private CallTransferFailedEvent() { + this.resultInfo = null; + this.operationContext = null; + } + + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ParticipantsUpdatedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ParticipantsUpdatedEvent.java new file mode 100644 index 0000000000000..4bdaa1cd8d256 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ParticipantsUpdatedEvent.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.communication.callautomation.implementation.converters.CommunicationIdentifierConverter; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** The ParticipantsUpdatedEvent model. */ +@Immutable +public final class ParticipantsUpdatedEvent extends CallAutomationEventBase { + /* + * List of current participants in the call. + */ + @JsonIgnore + private final List participants; + + @JsonCreator + private ParticipantsUpdatedEvent(@JsonProperty("participants") List> participants) { + + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + this.participants = participants + .stream() + .map(item -> mapper.convertValue(item, CommunicationIdentifierModel.class)) + .collect(Collectors.toList()) + .stream() + .map(CommunicationIdentifierConverter::convert) + .collect(Collectors.toList()); + } + + /** + * Get the participants property: List of current participants in the call. + * + * @return the participants value. + */ + public List getParticipants() { + return this.participants; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayCompleted.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayCompleted.java new file mode 100644 index 0000000000000..68ed1b6a51ffe --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayCompleted.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PlayCompleted model. */ +@Immutable +public final class PlayCompleted extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + private PlayCompleted() { + this.operationContext = null; + this.resultInfo = null; + } + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayFailed.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayFailed.java new file mode 100644 index 0000000000000..59daa4c2affb1 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/PlayFailed.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The PlayFailed model. */ +@Immutable +public final class PlayFailed extends CallAutomationEventBase { + /* + * Operation context + */ + @JsonProperty(value = "operationContext") + private final String operationContext; + + /* + * The resultInfo property. + */ + @JsonProperty(value = "resultInfo") + private final ResultInfo resultInfo; + + private PlayFailed() { + this.operationContext = null; + this.resultInfo = null; + } + /** + * Get the operationContext property: Operation context. + * + * @return the operationContext value. + */ + public String getOperationContext() { + return this.operationContext; + } + + /** + * Get the resultInfo property: The resultInfo property. + * + * @return the resultInfo value. + */ + public ResultInfo getResultInfo() { + return this.resultInfo; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/RecordingStateChangedEvent.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/RecordingStateChangedEvent.java new file mode 100644 index 0000000000000..f25a0fbcbc838 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/RecordingStateChangedEvent.java @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; + +/** The RecordingStateChangedEvent model. */ +@Immutable +public final class RecordingStateChangedEvent extends CallAutomationEventBase { + + /** + * Recording Id. + */ + @JsonProperty(value = "recordingId") + private final String recordingId; + + /** + * Recording state. + */ + @JsonProperty(value = "state") + private final RecordingState recordingState; + + /** + * Time of when it started recording. + */ + @JsonIgnore + private final OffsetDateTime startDateTime; + + @JsonCreator + private RecordingStateChangedEvent(@JsonProperty("startDateTime") String startDateTime) { + this.startDateTime = OffsetDateTime.parse(startDateTime, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + recordingId = null; + recordingState = null; + } + + /** + * Get the recordingId property: Recording Id. + * + * @return the recordingId value. + */ + public String getRecordingId() { + return recordingId; + } + + /** + * Get the recordingState property: Recording State. + * + * @return the recordingState value. + */ + public RecordingState getRecordingState() { + return recordingState; + } + + /** + * Get the startDateTime property: Start Date time. + * + * @return the startDateTime value. + */ + public OffsetDateTime getStartDateTime() { + return startDateTime; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ResultInfo.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ResultInfo.java new file mode 100644 index 0000000000000..7b323d8b9f9a6 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/ResultInfo.java @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation.models.events; + +import com.azure.core.annotation.Immutable; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** The ResultInfo model. */ +@Immutable +public final class ResultInfo { + /* + * The code property. + */ + @JsonProperty(value = "code") + private final Integer code; + + /* + * The subCode property. + */ + @JsonProperty(value = "subCode") + private final Integer subCode; + + /* + * The message property. + */ + @JsonProperty(value = "message") + private final String message; + + private ResultInfo() { + code = null; + subCode = null; + message = null; + } + + /** + * Get the code property: The code property. + * + * @return the code value. + */ + public Integer getCode() { + return this.code; + } + + /** + * Get the subCode property: The subCode property. + * + * @return the subCode value. + */ + public Integer getSubCode() { + return this.subCode; + } + + /** + * Get the message property: The message property. + * + * @return the message value. + */ + public String getMessage() { + return this.message; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/package-info.java new file mode 100644 index 0000000000000..703ff1771a66b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/events/package-info.java @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** Package containing events for AzureCommunicationCallingServerService. null. */ +package com.azure.communication.callautomation.models.events; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/package-info.java new file mode 100644 index 0000000000000..e296da2d795ff --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/models/package-info.java @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) AutoRest Code Generator. + +/** Package containing classes for AzureCommunicationCallAutomationService. null. */ +package com.azure.communication.callautomation.models; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/package-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/package-info.java new file mode 100644 index 0000000000000..d68dc022d79ff --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/com/azure/communication/callautomation/package-info.java @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/** Package containing the classes for AzureCommunicationCallingServer. Azure Communication CallingServer Service. */ +package com.azure.communication.callautomation; diff --git a/sdk/communication/azure-communication-callautomation/src/main/java/module-info.java b/sdk/communication/azure-communication-callautomation/src/main/java/module-info.java new file mode 100644 index 0000000000000..111d573a9f212 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/java/module-info.java @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +module com.azure.communication.callautomation { + + requires transitive com.azure.communication.common; + + // public API surface area + exports com.azure.communication.callautomation; + exports com.azure.communication.callautomation.models; + exports com.azure.communication.callautomation.models.events; + + // exporting some packages specifically for Jackson + opens com.azure.communication.callautomation.implementation.models to com.fasterxml.jackson.databind, com.azure.core; + opens com.azure.communication.callautomation to com.fasterxml.jackson.databind; + opens com.azure.communication.callautomation.models to com.azure.core, com.fasterxml.jackson.databind; + opens com.azure.communication.callautomation.models.events to com.fasterxml.jackson.databind; +} diff --git a/sdk/communication/azure-communication-callautomation/src/main/resources/azure-communication-callautomation.properties b/sdk/communication/azure-communication-callautomation/src/main/resources/azure-communication-callautomation.properties new file mode 100644 index 0000000000000..ca812989b4f27 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/main/resources/azure-communication-callautomation.properties @@ -0,0 +1,2 @@ +name=${project.artifactId} +version=${project.version} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationAsyncClientUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationAsyncClientUnitTests.java new file mode 100644 index 0000000000000..d1179e525a322 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationAsyncClientUnitTests.java @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.AnswerCallResult; +import com.azure.communication.callautomation.models.CallRejectReason; +import com.azure.communication.callautomation.models.CreateCallOptions; +import com.azure.communication.callautomation.models.CreateCallResult; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.http.rest.Response; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class CallAutomationAsyncClientUnitTests extends CallAutomationUnitTestBase { + @Test + public void createCall() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 201) + ))); + CommunicationUserIdentifier caller = new CommunicationUserIdentifier(CALL_CALLER_ID); + List targets = new ArrayList<>(Collections.singletonList(new CommunicationUserIdentifier(CALL_TARGET_ID))); + CreateCallOptions callOptions = new CreateCallOptions(caller, targets, CALL_CALLBACK_URL); + callOptions.setSubject(CALL_SUBJECT); + + CreateCallResult createCallResult = callAutomationAsyncClient.createCall(callOptions).block(); + + assertNotNull(createCallResult); + } + + @Test + public void createCallWithResponse() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 201) + ))); + CommunicationUserIdentifier caller = new CommunicationUserIdentifier(CALL_CALLER_ID); + List targets = new ArrayList<>(Collections.singletonList(new CommunicationUserIdentifier(CALL_TARGET_ID))); + CreateCallOptions callOptions = new CreateCallOptions(caller, targets, CALL_CALLBACK_URL); + callOptions.setSubject(CALL_SUBJECT); + callOptions.setMediaStreamingConfiguration(MEDIA_STREAMING_CONFIGURATION); + + Response createCallResult = callAutomationAsyncClient.createCallWithResponse(callOptions).block(); + + assertNotNull(createCallResult); + assertEquals(201, createCallResult.getStatusCode()); + assertNotNull(createCallResult.getValue()); + } + + @Test + public void answerCall() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))); + + AnswerCallResult answerCallResult = callAutomationAsyncClient.answerCall(CALL_INCOMING_CALL_CONTEXT, CALL_CALLBACK_URL).block(); + + assertNotNull(answerCallResult); + } + + @Test + public void answerCallWithResponse() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))); + + Response answerCallResult = callAutomationAsyncClient.answerCallWithResponse( + CALL_INCOMING_CALL_CONTEXT, CALL_CALLBACK_URL, MEDIA_STREAMING_CONFIGURATION).block(); + + assertNotNull(answerCallResult); + assertEquals(200, answerCallResult.getStatusCode()); + assertNotNull(answerCallResult.getValue()); + } + + @Test + public void redirectCall() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>("", 204) + )) + ); + CommunicationUserIdentifier target = new CommunicationUserIdentifier(CALL_TARGET_ID); + + callAutomationAsyncClient.redirectCall(CALL_INCOMING_CALL_CONTEXT, target); + } + + @Test + public void redirectCallWithResponse() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>("", 204) + )) + ); + CommunicationUserIdentifier target = new CommunicationUserIdentifier(CALL_TARGET_ID); + + Response redirectCallResponse = callAutomationAsyncClient.redirectCallWithResponse( + CALL_INCOMING_CALL_CONTEXT, target).block(); + + assertNotNull(redirectCallResponse); + assertEquals(204, redirectCallResponse.getStatusCode()); + } + + @Test + public void rejectCall() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>("", 204) + )) + ); + + callAutomationAsyncClient.rejectCall(CALL_INCOMING_CALL_CONTEXT, CallRejectReason.BUSY); + } + + @Test + public void rejectCallWithResponse() { + CallAutomationAsyncClient callAutomationAsyncClient = getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new AbstractMap.SimpleEntry<>("", 204) + )) + ); + + Response rejectCallResponse = callAutomationAsyncClient.rejectCallWithResponse(CALL_INCOMING_CALL_CONTEXT, + CallRejectReason.BUSY).block(); + + assertNotNull(rejectCallResponse); + assertEquals(204, rejectCallResponse.getStatusCode()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientBuilderUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientBuilderUnitTests.java new file mode 100644 index 0000000000000..5b0059340aed2 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientBuilderUnitTests.java @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.communication.callautomation; + +import com.azure.communication.common.implementation.HmacAuthenticationPolicy; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.ExponentialBackoffOptions; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.util.ClientOptions; +import com.azure.identity.DefaultAzureCredentialBuilder; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class CallAutomationClientBuilderUnitTests { + static final String MOCK_URL = "https://REDACTED.communication.azure.com"; + static final String MOCK_ACCESS_KEY = "eyKfcHciOiJIUzI1NiIsInR5cCI6IkqXVCJ9eyJzdWIiOiIxMjM0NTY5ODkwIiwibmFtZSI7IkpvaGfQSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadUs4s5d"; + static final String MOCK_CONNECTION_STRING = "endpoint=https://REDACTED.communication.azure.com/;accesskey=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaGfQSflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadQssw5c"; + private static final String APPLICATION_ID = "833bad32-4432-4d41-8bb4"; + private final CallAutomationClientBuilder builder = new CallAutomationClientBuilder(); + + static class NoOpHttpClient implements HttpClient { + @Override + public Mono send(HttpRequest request) { + return Mono.empty(); // NOP + } + } + + @Test + public void missingTokenCredentialTest() throws NullPointerException { + builder + .endpoint(MOCK_URL) + .httpClient(new NoOpHttpClient()); + assertThrows(Exception.class, builder::buildAsyncClient); + } + + @Test + public void missingUrlTest() + throws NullPointerException { + builder + .credential(new AzureKeyCredential(MOCK_ACCESS_KEY)) + .httpClient(new NoOpHttpClient()); + assertThrows(Exception.class, builder::buildAsyncClient); + } + + @Test + public void nullPipelineTest() { + assertThrows(NullPointerException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .pipeline(null)); + } + + @Test + public void nullCustomPolicyTest() { + assertThrows(NullPointerException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .addPolicy(null)); + } + + @Test + public void nullConfigurationTest() { + assertThrows(NullPointerException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .configuration(null)); + } + + @Test + public void nullHttpLogOptionsTest() { + assertThrows(NullPointerException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .httpLogOptions(null)); + } + + @Test + public void nullRetryPolicyTest() { + assertThrows( + NullPointerException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .retryPolicy(null)); + } + + @Test + public void buildPipelineForClient() { + CallAutomationAsyncClient callAutomationAsyncClient = builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .pipeline(new HttpPipelineBuilder().build()) + .buildAsyncClient(); + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void setHttpLogOptions() { + HttpLogOptions options = new HttpLogOptions().setApplicationId(APPLICATION_ID); + CallAutomationAsyncClient callAutomationAsyncClient = builder + .connectionString(MOCK_CONNECTION_STRING) + .httpLogOptions(options) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient(); + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void setClientOptions() { + ClientOptions options = new ClientOptions().setApplicationId(APPLICATION_ID); + CallAutomationAsyncClient callAutomationAsyncClient = builder + .connectionString(MOCK_CONNECTION_STRING) + .clientOptions(options) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient(); + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void noClientOptionsNoPipeline() { + CallAutomationAsyncClient callAutomationAsyncClient = builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient(); + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void addPolicy() { + AzureKeyCredential credential = new AzureKeyCredential("key"); + CallAutomationAsyncClient callAutomationAsyncClient = + builder + .connectionString(MOCK_CONNECTION_STRING) + .addPolicy(new HmacAuthenticationPolicy(credential)) + .httpClient(new NoOpHttpClient()) + .pipeline(new HttpPipelineBuilder().build()) + .retryPolicy(new RetryPolicy()) + .buildAsyncClient(); + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void argumentExceptionOnConnectionStringAndEndpoint() { + assertThrows(IllegalArgumentException.class, + () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .endpoint(MOCK_URL) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void argumentExceptionOnEmptyConnectionString() { + assertThrows(NullPointerException.class, + () -> builder + .connectionString("") + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void argumentExceptionOnConnectionStringAndAzureKeyCredential() { + AzureKeyCredential credential = new AzureKeyCredential("key"); + assertThrows( + IllegalArgumentException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .credential(credential) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void argumentExceptionOnConnectionStringAndTokenCredential() { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + assertThrows( + IllegalArgumentException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .credential(tokenCredential) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void argumentExceptionOnAzureKeyCredentialAndTokenCredential() { + AzureKeyCredential credential = new AzureKeyCredential("key"); + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + assertThrows( + IllegalArgumentException.class, () -> builder + .credential(credential) + .credential(tokenCredential) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void noPipelineWithToken() { + TokenCredential tokenCredential = new DefaultAzureCredentialBuilder().build(); + CallAutomationAsyncClient callAutomationAsyncClient = builder + .endpoint(MOCK_URL) + .credential(tokenCredential) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient(); + + assertNotNull(callAutomationAsyncClient); + } + + @Test + public void noCredential() { + assertThrows( + IllegalArgumentException.class, () -> builder + .endpoint(MOCK_URL) + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void noEndpoint() { + assertThrows( + NullPointerException.class, () -> builder + .httpClient(new NoOpHttpClient()) + .buildAsyncClient()); + } + + @Test + public void bothRetryOptionsAndRetryPolicySet() { + assertThrows(IllegalStateException.class, () -> builder + .connectionString(MOCK_CONNECTION_STRING) + .httpClient(new NoOpHttpClient()) + .retryOptions(new RetryOptions(new ExponentialBackoffOptions())) + .retryPolicy(new RetryPolicy()) + .buildClient()); + } +} + diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientUnitTests.java new file mode 100644 index 0000000000000..277c63e724578 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationClientUnitTests.java @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.AnswerCallResult; +import com.azure.communication.callautomation.models.CallRejectReason; +import com.azure.communication.callautomation.models.CreateCallOptions; +import com.azure.communication.callautomation.models.CreateCallResult; +import com.azure.communication.common.CommunicationIdentifier; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +public class CallAutomationClientUnitTests extends CallAutomationUnitTestBase { + + @Test + public void createCall() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 201) + ))); + CommunicationUserIdentifier caller = new CommunicationUserIdentifier(CALL_CALLER_ID); + List targets = new ArrayList<>(Collections.singletonList(new CommunicationUserIdentifier(CALL_TARGET_ID))); + CreateCallOptions callOptions = new CreateCallOptions(caller, targets, CALL_CALLBACK_URL); + callOptions.setSubject(CALL_SUBJECT); + + CreateCallResult createCallResult = callAutomationClient.createCall(callOptions); + + assertNotNull(createCallResult); + } + + @Test + public void createCallWithResponse() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 201) + ))); + CommunicationUserIdentifier caller = new CommunicationUserIdentifier(CALL_CALLER_ID); + List targets = new ArrayList<>(Collections.singletonList(new CommunicationUserIdentifier(CALL_TARGET_ID))); + CreateCallOptions callOptions = new CreateCallOptions(caller, targets, CALL_CALLBACK_URL); + callOptions.setSubject(CALL_SUBJECT); + + Response createCallResult = callAutomationClient.createCallWithResponse(callOptions, Context.NONE); + + assertNotNull(createCallResult); + assertEquals(201, createCallResult.getStatusCode()); + assertNotNull(createCallResult.getValue()); + } + + @Test + public void answerCall() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))); + + AnswerCallResult answerCallResult = callAutomationClient.answerCall(CALL_INCOMING_CALL_CONTEXT, CALL_CALLBACK_URL); + + assertNotNull(answerCallResult); + } + + @Test + public void answerCallWithResponse() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))); + + Response answerCallResult = callAutomationClient.answerCallWithResponse( + CALL_INCOMING_CALL_CONTEXT, CALL_CALLBACK_URL, MEDIA_STREAMING_CONFIGURATION, Context.NONE); + + assertNotNull(answerCallResult); + assertEquals(200, answerCallResult.getStatusCode()); + assertNotNull(answerCallResult.getValue()); + } + + @Test + public void redirectCall() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>("", 204) + )) + ); + CommunicationUserIdentifier target = new CommunicationUserIdentifier(CALL_TARGET_ID); + + callAutomationClient.redirectCall(CALL_INCOMING_CALL_CONTEXT, target); + } + + @Test + public void redirectCallWithResponse() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>("", 204) + )) + ); + CommunicationUserIdentifier target = new CommunicationUserIdentifier(CALL_TARGET_ID); + + Response redirectCallResponse = callAutomationClient.redirectCallWithResponse( + CALL_INCOMING_CALL_CONTEXT, target, Context.NONE); + + assertEquals(204, redirectCallResponse.getStatusCode()); + } + + @Test + public void rejectCall() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>("", 204) + )) + ); + + callAutomationClient.rejectCall(CALL_INCOMING_CALL_CONTEXT, CallRejectReason.BUSY); + } + + @Test + public void rejectCallWithResponse() { + CallAutomationClient callAutomationClient = getCallAutomationClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>("", 204) + )) + ); + + Response rejectCallResponse = callAutomationClient.rejectCallWithResponse(CALL_INCOMING_CALL_CONTEXT, + CallRejectReason.BUSY, Context.NONE); + + assertEquals(204, rejectCallResponse.getStatusCode()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationLiveTestBase.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationLiveTestBase.java new file mode 100644 index 0000000000000..8132a98746895 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationLiveTestBase.java @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.core.credential.AccessToken; +import com.azure.core.credential.TokenCredential; +import com.azure.core.credential.TokenRequestContext; +import com.azure.core.http.HttpClient; +import com.azure.core.test.TestBase; +import com.azure.core.test.TestMode; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.identity.DefaultAzureCredentialBuilder; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import reactor.core.publisher.Mono; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; + +public class CallAutomationLiveTestBase extends TestBase { + protected static final String CONNECTION_STRING = Configuration.getGlobalConfiguration() + .get("COMMUNICATION_LIVETEST_STATIC_CONNECTION_STRING", + "endpoint=https://REDACTED.communication.azure.com/;accesskey=QWNjZXNzS2V5"); + + protected static final String ENDPOINT = Configuration.getGlobalConfiguration().get("COMMUNICATION_LIVETEST_STATIC_ENDPOINT", + "https://REDACTED.communication.azure.com/"); + + protected static final String ENDPOINT_401 = Configuration.getGlobalConfiguration().get("COMMUNICATION_LIVETEST_STATIC_ENDPOINT_401", + "https://REDACTED.communication.azure.com/"); + + protected static final String METADATA_URL = Configuration.getGlobalConfiguration() + .get("METADATA_URL", "https://storage.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata"); + + protected static final String VIDEO_URL = Configuration.getGlobalConfiguration() + .get("VIDEO_URL", "https://storage.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/video"); + + protected static final String CONTENT_URL_404 = Configuration.getGlobalConfiguration() + .get("CONTENT_URL_404", "https://storage.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141d/content/acsmetadata"); + + protected static final String RECORDING_DELETE_URL = Configuration.getGlobalConfiguration() + .get("RECORDING_DELETE_URL", "https://storage.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22"); + + protected static final String RECORDING_DELETE_URL_404 = Configuration.getGlobalConfiguration() + .get("RECORDING_DELETE_URL_404", "https://storage.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c"); + + private static final StringJoiner JSON_PROPERTIES_TO_REDACT + = new StringJoiner("\":\"|\"", "\"", "\":\"") + .add("to"); + + private static final Pattern JSON_PROPERTY_VALUE_REDACTION_PATTERN + = Pattern.compile(String.format("(?:%s)(.*?)(?:\",|\"})", JSON_PROPERTIES_TO_REDACT), + Pattern.CASE_INSENSITIVE); + + protected CallAutomationClientBuilder getCallingServerClientUsingConnectionString(HttpClient httpClient) { + CallAutomationClientBuilder builder = new CallAutomationClientBuilder() + .connectionString(CONNECTION_STRING) + .httpClient(httpClient == null ? interceptorManager.getPlaybackClient() : httpClient); + + if (getTestMode() == TestMode.RECORD) { + List> redactors = new ArrayList<>(); + redactors.add(data -> redact(data, JSON_PROPERTY_VALUE_REDACTION_PATTERN.matcher(data))); + builder.addPolicy(interceptorManager.getRecordPolicy(redactors)); + } + return builder; + } + + protected CallAutomationClientBuilder getCallingServerClientUsingTokenCredential(HttpClient httpClient) { + TokenCredential tokenCredential = getTestMode() == TestMode.PLAYBACK ? new FakeCredentials() : new DefaultAzureCredentialBuilder().build(); + + CallAutomationClientBuilder builder = new CallAutomationClientBuilder() + .endpoint(ENDPOINT) + .credential(tokenCredential) + .httpClient(httpClient == null ? interceptorManager.getPlaybackClient() : httpClient); + + if (getTestMode() == TestMode.RECORD) { + List> redactors = new ArrayList<>(); + redactors.add(data -> redact(data, JSON_PROPERTY_VALUE_REDACTION_PATTERN.matcher(data))); + builder.addPolicy(interceptorManager.getRecordPolicy(redactors)); + } + return builder; + } + + protected CallAutomationClientBuilder getCallingServerClientUsingInvalidTokenCredential(HttpClient httpClient) { + TokenCredential tokenCredential = getTestMode() == TestMode.PLAYBACK ? new FakeCredentials() : new DefaultAzureCredentialBuilder().build(); + + CallAutomationClientBuilder builder = new CallAutomationClientBuilder() + .credential(tokenCredential) + .endpoint(ENDPOINT_401) + .httpClient(httpClient == null ? interceptorManager.getPlaybackClient() : httpClient); + + if (getTestMode() == TestMode.RECORD) { + List> redactors = new ArrayList<>(); + redactors.add(data -> redact(data, JSON_PROPERTY_VALUE_REDACTION_PATTERN.matcher(data))); + builder.addPolicy(interceptorManager.getRecordPolicy(redactors)); + } + return builder; + } + + protected Mono logHeaders(String testName, HttpPipelineNextPolicy next) { + return next.process() + .flatMap(httpResponse -> { + final HttpResponse bufferedResponse = httpResponse.buffer(); + + /* Should sanitize printed response url */ + System.out.println("Chain-ID header for " + testName + " request " + + bufferedResponse.getRequest().getUrl() + + ": " + bufferedResponse.getHeaderValue("X-Microsoft-Skype-Chain-ID")); + return Mono.just(bufferedResponse); + }); + } + + static class FakeCredentials implements TokenCredential { + @Override + public Mono getToken(TokenRequestContext tokenRequestContext) { + return Mono.just(new AccessToken("someFakeToken", OffsetDateTime.MAX)); + } + } + + private String redact(String content, Matcher matcher) { + while (matcher.find()) { + String captureGroup = matcher.group(1); + if (!CoreUtils.isNullOrEmpty(captureGroup)) { + content = content.replace(matcher.group(1), "REDACTED"); + } + } + return content; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationUnitTestBase.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationUnitTestBase.java new file mode 100644 index 0000000000000..e1d68d9302f39 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallAutomationUnitTestBase.java @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.communication.callautomation; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.AbstractMap.SimpleEntry; +import java.util.Arrays; +import java.util.Collections; + +import com.azure.communication.callautomation.implementation.models.AcsCallParticipantInternal; +import com.azure.communication.callautomation.implementation.models.AddParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.CallConnectionPropertiesInternal; +import com.azure.communication.callautomation.implementation.models.CallConnectionStateModelInternal; +import com.azure.communication.callautomation.implementation.models.CallSourceInternal; +import com.azure.communication.callautomation.implementation.models.GetParticipantsResponseInternal; +import com.azure.communication.callautomation.models.MediaStreamingAudioChannelType; +import com.azure.communication.callautomation.models.MediaStreamingConfiguration; +import com.azure.communication.callautomation.models.MediaStreamingContentType; +import com.azure.communication.callautomation.models.MediaStreamingTransportType; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class CallAutomationUnitTestBase { + static final String MOCK_ENDPOINT = "https://REDACTED.communication.azure.com/"; + static final String MOCK_CONNECTION_STRING = String.format("endpoint=%s;accesskey=eyJhbG", MOCK_ENDPOINT); + static final String CALL_CONNECTION_ID = "callConnectionId"; + static final String CALL_SERVER_CALL_ID = "serverCallId"; + static final String CALL_CALLER_ID = "callerId"; + static final String CALL_TARGET_ID = "targetId"; + static final String CALL_CONNECTION_STATE = "connected"; + static final String CALL_SUBJECT = "subject"; + static final String CALL_CALLBACK_URL = "https://REDACTED.com/events"; + static final String CALL_INCOMING_CALL_CONTEXT = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.REDACTED"; + static final String CALL_OPERATION_CONTEXT = "operationContext"; + + static final MediaStreamingConfiguration MEDIA_STREAMING_CONFIGURATION = new MediaStreamingConfiguration( + "https://websocket.url.com", + MediaStreamingTransportType.WEBSOCKET, + MediaStreamingContentType.AUDIO, + MediaStreamingAudioChannelType.MIXED + ); + + public static String generateDownloadResult(String content) { + return content; + } + + public static String generateCallProperties(String callConnectionId, String serverCallId, String callerId, + String targetId, String connectionState, String subject, String callbackUri) { + CallConnectionPropertiesInternal result = new CallConnectionPropertiesInternal() + .setCallConnectionId(callConnectionId) + .setServerCallId(serverCallId) + .setCallbackUri(callbackUri) + .setSubject(subject) + .setCallConnectionState(CallConnectionStateModelInternal.fromString(connectionState)) + .setSource(new CallSourceInternal() + .setIdentifier(ModelGenerator.generateUserIdentifierModel(callerId))) + .setTargets(new ArrayList<>(Collections.singletonList(ModelGenerator.generateUserIdentifierModel(targetId))) + ); + + return serializeObject(result); + } + + public static String generateGetParticipantResponse(String callerId, boolean isMuted) { + AcsCallParticipantInternal callParticipant = ModelGenerator.generateAcsCallParticipantInternal(callerId, isMuted); + return serializeObject(callParticipant); + } + + public static String generateListParticipantsResponse() { + GetParticipantsResponseInternal getParticipantsResponseInternal = new GetParticipantsResponseInternal() + .setValues(new ArrayList<>(Arrays.asList( + ModelGenerator.generateAcsCallParticipantInternal(CALL_CALLER_ID, false), + ModelGenerator.generateAcsCallParticipantInternal(CALL_TARGET_ID, true)))) + .setNextLink(""); + + return serializeObject(getParticipantsResponseInternal); + } + + public static String generateAddParticipantsResponse() { + AddParticipantsResponseInternal addParticipantsResponseInternal = new AddParticipantsResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT) + .setParticipants(new ArrayList<>(Collections.singletonList( + ModelGenerator.generateAcsCallParticipantInternal(CALL_TARGET_ID, false)))); + + return serializeObject(addParticipantsResponseInternal); + } + + public static CallAutomationAsyncClient getCallAutomationAsyncClient(ArrayList> responses) { + HttpClient mockHttpClient = new MockHttpClient(responses); + + return new CallAutomationClientBuilder() + .httpClient(mockHttpClient) + .connectionString(MOCK_CONNECTION_STRING) + .buildAsyncClient(); + } + + public static CallAutomationClient getCallAutomationClient(ArrayList> responses) { + HttpClient mockHttpClient = new MockHttpClient(responses); + + return new CallAutomationClientBuilder() + .httpClient(mockHttpClient) + .connectionString(MOCK_CONNECTION_STRING) + .buildClient(); + } + + public static CallConnection getCallConnection(ArrayList> responses) { + CallAutomationClient callAutomationClient = getCallAutomationClient(responses); + return callAutomationClient.getCallConnection("callConnectionId"); + } + + public static CallConnectionAsync getCallConnectionAsync(ArrayList> responses) { + CallAutomationAsyncClient callingServerClient = getCallAutomationAsyncClient(responses); + return callingServerClient.getCallConnectionAsync("callConnectionId"); + } + + public static HttpResponse generateMockResponse(String body, HttpRequest request, int statusCode) { + return new HttpResponse(request) { + @Override + public int getStatusCode() { + return statusCode; + } + + @Override + public String getHeaderValue(String name) { + return null; + } + + @Override + public HttpHeaders getHeaders() { + return new HttpHeaders(); + } + + @Override + public Flux getBody() { + return Flux.just(ByteBuffer.wrap(body.getBytes(StandardCharsets.UTF_8))); + } + + @Override + public Mono getBodyAsByteArray() { + return Mono.just(body.getBytes(StandardCharsets.UTF_8)); + } + + @Override + public Mono getBodyAsString() { + return Mono.just(body); + } + + @Override + public Mono getBodyAsString(Charset charset) { + return Mono.just(body); + } + }; + } + + static String serializeObject(Object o) { + ObjectMapper mapper = new ObjectMapper(); + String body = null; + try { + body = mapper.writeValueAsString(o); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return body; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionAsyncUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionAsyncUnitTests.java new file mode 100644 index 0000000000000..95e7715ff5379 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionAsyncUnitTests.java @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.TransferCallResponseInternal; +import com.azure.communication.callautomation.models.AddParticipantsOptions; +import com.azure.communication.callautomation.models.AddParticipantsResult; +import com.azure.communication.callautomation.models.CallConnectionProperties; +import com.azure.communication.callautomation.models.CallParticipant; +import com.azure.communication.callautomation.models.ListParticipantsResult; +import com.azure.communication.callautomation.models.RemoveParticipantsResult; +import com.azure.communication.callautomation.models.TransferCallResult; +import com.azure.communication.callautomation.models.TransferToParticipantCallOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.http.rest.Response; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class CallConnectionAsyncUnitTests extends CallAutomationUnitTestBase { + @Test + public void getCallProperties() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + CallConnectionProperties callConnectionProperties = callConnectionAsync.getCallProperties().block(); + + assertNotNull(callConnectionProperties); + } + + @Test + public void getCallPropertiesWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response callConnectionProperties = callConnectionAsync.getCallPropertiesWithResponse().block(); + + assertNotNull(callConnectionProperties); + assertEquals(200, callConnectionProperties.getStatusCode()); + assertNotNull(callConnectionProperties.getValue()); + } + + @Test + public void hangUp() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + callConnectionAsync.hangUp(false); + } + + @Test + public void hangUpWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response hangUpResponse = callConnectionAsync.hangUpWithResponse(false).block(); + + assertNotNull(hangUpResponse); + assertEquals(204, hangUpResponse.getStatusCode()); + } + + @Test + public void hangUpWithResponseForEveryone() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response hangUpResponse = callConnectionAsync.hangUpWithResponse(true).block(); + + assertNotNull(hangUpResponse); + assertEquals(204, hangUpResponse.getStatusCode()); + } + + @Test + public void getParticipant() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateGetParticipantResponse(CALL_CALLER_ID, false), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + CallParticipant callParticipant = callConnectionAsync.getParticipant(CALL_CALLER_ID).block(); + + assertNotNull(callParticipant); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) callParticipant.getIdentifier()).getId()); + } + + @Test + public void getParticipantWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateGetParticipantResponse(CALL_CALLER_ID, false), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response callParticipantResponse = callConnectionAsync.getParticipantWithResponse(CALL_CALLER_ID).block(); + + assertNotNull(callParticipantResponse); + assertEquals(200, callParticipantResponse.getStatusCode()); + assertNotNull(callParticipantResponse.getValue()); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) callParticipantResponse.getValue().getIdentifier()).getId()); + } + + @Test + public void listParticipants() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateListParticipantsResponse(), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + ListParticipantsResult listParticipants = callConnectionAsync.listParticipants().block(); + + assertNotNull(listParticipants); + assertNotNull(listParticipants.getValues()); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) listParticipants.getValues().get(0).getIdentifier()).getId()); + } + + @Test + public void listParticipantsWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateListParticipantsResponse(), 200) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response listParticipantsResultResponse = callConnectionAsync.listParticipantsWithResponse().block(); + + assertNotNull(listParticipantsResultResponse); + assertEquals(200, listParticipantsResultResponse.getStatusCode()); + assertNotNull(listParticipantsResultResponse.getValue()); + assertEquals(CALL_TARGET_ID, ((CommunicationUserIdentifier) listParticipantsResultResponse + .getValue() + .getValues() + .get(1) + .getIdentifier()) + .getId()); + } + + @Test + public void transferToParticipantCall() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new TransferCallResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + TransferCallResult transferCallResult = callConnectionAsync.transferToParticipantCall( + new TransferToParticipantCallOptions(new CommunicationUserIdentifier(CALL_TARGET_ID)) + .setOperationContext(CALL_OPERATION_CONTEXT) + ).block(); + + assertNotNull(transferCallResult); + assertEquals(CALL_OPERATION_CONTEXT, transferCallResult.getOperationContext()); + } + + @Test + public void transferToParticipantCallWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new TransferCallResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response transferCallResultResponse = callConnectionAsync.transferToParticipantCallWithResponse( + new TransferToParticipantCallOptions(new CommunicationUserIdentifier(CALL_TARGET_ID)) + .setOperationContext(CALL_OPERATION_CONTEXT)).block(); + + assertNotNull(transferCallResultResponse); + assertEquals(202, transferCallResultResponse.getStatusCode()); + assertNotNull(transferCallResultResponse.getValue()); + } + + @Test + public void addParticipants() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateAddParticipantsResponse(), 202) + ) + )).getCallConnectionAsync(CALL_CONNECTION_ID); + + AddParticipantsResult addParticipantsResult = callConnectionAsync.addParticipants( + new AddParticipantsOptions(new ArrayList<>(Arrays.asList( + new CommunicationUserIdentifier(CALL_TARGET_ID)))) + .setOperationContext(CALL_OPERATION_CONTEXT) + ).block(); + + assertNotNull(addParticipantsResult); + assertEquals(CALL_TARGET_ID, ((CommunicationUserIdentifier) addParticipantsResult + .getParticipants() + .get(0) + .getIdentifier()) + .getId()); + } + + @Test + public void addParticipantsWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateAddParticipantsResponse(), 202) + ) + )).getCallConnectionAsync(CALL_CONNECTION_ID); + + Response addParticipantsResultResponse = callConnectionAsync.addParticipantsWithResponse( + new AddParticipantsOptions(new ArrayList<>(Arrays.asList( + new CommunicationUserIdentifier(CALL_TARGET_ID)))) + .setOperationContext(CALL_OPERATION_CONTEXT)).block(); + + assertNotNull(addParticipantsResultResponse); + assertEquals(202, addParticipantsResultResponse.getStatusCode()); + assertNotNull(addParticipantsResultResponse.getValue()); + } + + @Test + public void removeParticipants() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new RemoveParticipantsResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + RemoveParticipantsResult removeParticipantsResult = callConnectionAsync.removeParticipants( + new ArrayList<>(Arrays.asList(new CommunicationUserIdentifier(CALL_TARGET_ID))), CALL_OPERATION_CONTEXT).block(); + + assertNotNull(removeParticipantsResult); + assertEquals(CALL_OPERATION_CONTEXT, removeParticipantsResult.getOperationContext()); + } + + @Test + public void removeParticipantsWithResponse() { + CallConnectionAsync callConnectionAsync = getCallAutomationAsyncClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new RemoveParticipantsResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnectionAsync(CALL_CONNECTION_ID); + + Response removeParticipantsResultResponse = callConnectionAsync.removeParticipantsWithResponse( + new ArrayList<>(Arrays.asList(new CommunicationUserIdentifier(CALL_TARGET_ID))), + CALL_OPERATION_CONTEXT).block(); + + + assertNotNull(removeParticipantsResultResponse); + assertEquals(202, removeParticipantsResultResponse.getStatusCode()); + assertNotNull(removeParticipantsResultResponse.getValue()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionUnitTests.java new file mode 100644 index 0000000000000..d381dacecd8f7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallConnectionUnitTests.java @@ -0,0 +1,275 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.models.RemoveParticipantsResponseInternal; +import com.azure.communication.callautomation.implementation.models.TransferCallResponseInternal; +import com.azure.communication.callautomation.models.AddParticipantsOptions; +import com.azure.communication.callautomation.models.AddParticipantsResult; +import com.azure.communication.callautomation.models.CallConnectionProperties; +import com.azure.communication.callautomation.models.CallParticipant; +import com.azure.communication.callautomation.models.ListParticipantsResult; +import com.azure.communication.callautomation.models.RemoveParticipantsResult; +import com.azure.communication.callautomation.models.TransferCallResult; +import com.azure.communication.callautomation.models.TransferToParticipantCallOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +import java.util.AbstractMap.SimpleEntry; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class CallConnectionUnitTests extends CallAutomationUnitTestBase { + @Test + public void getCallProperties() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + CallConnectionProperties callConnectionProperties = callConnection.getCallProperties(); + + assertNotNull(callConnectionProperties); + } + + @Test + public void getCallPropertiesWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateCallProperties(CALL_CONNECTION_ID, CALL_SERVER_CALL_ID, + CALL_CALLER_ID, CALL_TARGET_ID, CALL_CONNECTION_STATE, CALL_SUBJECT, CALL_CALLBACK_URL), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response callConnectionProperties = callConnection.getCallPropertiesWithResponse(Context.NONE); + + assertNotNull(callConnectionProperties); + assertEquals(200, callConnectionProperties.getStatusCode()); + assertNotNull(callConnectionProperties.getValue()); + } + + @Test + public void hangUp() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + callConnection.hangUp(false); + } + + @Test + public void hangUpWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response hangUpResponse = callConnection.hangUpWithResponse(false, Context.NONE); + + assertNotNull(hangUpResponse); + assertEquals(204, hangUpResponse.getStatusCode()); + } + + @Test + public void hangUpWithResponseForEveryone() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry("", 204) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response hangUpResponse = callConnection.hangUpWithResponse(true, Context.NONE); + + assertNotNull(hangUpResponse); + assertEquals(204, hangUpResponse.getStatusCode()); + } + + @Test + public void getParticipant() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateGetParticipantResponse(CALL_CALLER_ID, false), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + CallParticipant callParticipant = callConnection.getParticipant(CALL_CALLER_ID); + + assertNotNull(callParticipant); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) callParticipant.getIdentifier()).getId()); + } + + @Test + public void getParticipantWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateGetParticipantResponse(CALL_CALLER_ID, false), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response callParticipantResponse = callConnection.getParticipantWithResponse(CALL_CALLER_ID, Context.NONE); + + assertNotNull(callParticipantResponse); + assertEquals(200, callParticipantResponse.getStatusCode()); + assertNotNull(callParticipantResponse.getValue()); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) callParticipantResponse.getValue().getIdentifier()).getId()); + } + + @Test + public void listParticipants() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateListParticipantsResponse(), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + ListParticipantsResult listParticipants = callConnection.listParticipants(); + + assertNotNull(listParticipants); + assertNotNull(listParticipants.getValues()); + assertEquals(CALL_CALLER_ID, ((CommunicationUserIdentifier) listParticipants.getValues().get(0).getIdentifier()).getId()); + } + + @Test + public void listParticipantsWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateListParticipantsResponse(), 200) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response listParticipantsResultResponse = callConnection.listParticipantsWithResponse(Context.NONE); + + assertNotNull(listParticipantsResultResponse); + assertEquals(200, listParticipantsResultResponse.getStatusCode()); + assertNotNull(listParticipantsResultResponse.getValue()); + assertEquals(CALL_TARGET_ID, ((CommunicationUserIdentifier) listParticipantsResultResponse + .getValue() + .getValues() + .get(1) + .getIdentifier()) + .getId()); + } + + @Test + public void transferToParticipantCall() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new TransferCallResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + TransferCallResult transferCallResult = callConnection.transferToParticipantCall( + new TransferToParticipantCallOptions(new CommunicationUserIdentifier(CALL_TARGET_ID)) + .setOperationContext(CALL_OPERATION_CONTEXT) + ); + + assertNotNull(transferCallResult); + assertEquals(CALL_OPERATION_CONTEXT, transferCallResult.getOperationContext()); + } + + @Test + public void transferToParticipantCallWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new TransferCallResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response transferCallResultResponse = callConnection.transferToParticipantCallWithResponse( + new TransferToParticipantCallOptions(new CommunicationUserIdentifier(CALL_TARGET_ID)) + .setOperationContext(CALL_OPERATION_CONTEXT), Context.NONE); + + assertNotNull(transferCallResultResponse); + assertEquals(202, transferCallResultResponse.getStatusCode()); + assertNotNull(transferCallResultResponse.getValue()); + } + + @Test + public void addParticipants() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateAddParticipantsResponse(), 202) + ) + )).getCallConnection(CALL_CONNECTION_ID); + + AddParticipantsResult addParticipantsResult = callConnection.addParticipants( + new AddParticipantsOptions(new ArrayList<>(Arrays.asList( + new CommunicationUserIdentifier(CALL_TARGET_ID)))) + .setOperationContext(CALL_OPERATION_CONTEXT) + ); + + assertNotNull(addParticipantsResult); + assertEquals(CALL_TARGET_ID, ((CommunicationUserIdentifier) addParticipantsResult + .getParticipants() + .get(0) + .getIdentifier()) + .getId()); + } + + @Test + public void addParticipantsWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(generateAddParticipantsResponse(), 202) + ) + )).getCallConnection(CALL_CONNECTION_ID); + + Response addParticipantsResultResponse = callConnection.addParticipantsWithResponse( + new AddParticipantsOptions(new ArrayList<>(Arrays.asList( + new CommunicationUserIdentifier(CALL_TARGET_ID)))) + .setOperationContext(CALL_OPERATION_CONTEXT), Context.NONE); + + assertNotNull(addParticipantsResultResponse); + assertEquals(202, addParticipantsResultResponse.getStatusCode()); + assertNotNull(addParticipantsResultResponse.getValue()); + } + + @Test + public void removeParticipants() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new RemoveParticipantsResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + RemoveParticipantsResult removeParticipantsResult = callConnection.removeParticipants( + new ArrayList<>(Arrays.asList(new CommunicationUserIdentifier(CALL_TARGET_ID))), CALL_OPERATION_CONTEXT); + + assertNotNull(removeParticipantsResult); + assertEquals(CALL_OPERATION_CONTEXT, removeParticipantsResult.getOperationContext()); + } + + @Test + public void removeParticipantsWithResponse() { + CallConnection callConnection = getCallAutomationClient(new ArrayList>( + Arrays.asList( + new SimpleEntry(serializeObject(new RemoveParticipantsResponseInternal() + .setOperationContext(CALL_OPERATION_CONTEXT)), 202) + ))) + .getCallConnection(CALL_CONNECTION_ID); + + Response removeParticipantsResultResponse = callConnection.removeParticipantsWithResponse( + new ArrayList<>(Arrays.asList(new CommunicationUserIdentifier(CALL_TARGET_ID))), + CALL_OPERATION_CONTEXT, Context.NONE); + + + assertNotNull(removeParticipantsResultResponse); + assertEquals(202, removeParticipantsResultResponse.getStatusCode()); + assertNotNull(removeParticipantsResultResponse.getValue()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaAsyncUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaAsyncUnitTests.java new file mode 100644 index 0000000000000..e0bea1d4c3717 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaAsyncUnitTests.java @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.FileSource; +import com.azure.communication.callautomation.models.PlayOptions; +import com.azure.communication.callautomation.models.RecognizeConfigurations; +import com.azure.communication.callautomation.models.RecognizeInputType; +import com.azure.communication.callautomation.models.RecognizeOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallMediaAsyncUnitTests { + + private CallMediaAsync callMedia; + private FileSource playSource; + + private PlayOptions playOptions; + + @BeforeEach + public void setup() { + CallConnectionAsync callConnection = + CallAutomationUnitTestBase.getCallConnectionAsync(new ArrayList<>( + Collections.singletonList(new AbstractMap.SimpleEntry<>("", 202))) + ); + callMedia = callConnection.getCallMediaAsync(); + + playSource = new FileSource(); + playSource.setPlaySourceId("playSourceId"); + playSource.setUri("filePath"); + + playOptions = new PlayOptions() + .setLoop(false) + .setOperationContext("operationContext"); + } + + @Test + public void playFileWithResponseTest() { + StepVerifier.create( + callMedia.playWithResponse(playSource, + Collections.singletonList(new CommunicationUserIdentifier("id")), playOptions)) + .consumeNextWith(response -> assertEquals(202, response.getStatusCode())) + .verifyComplete(); + } + + @Test + public void playFileToAllWithResponseTest() { + StepVerifier.create( + callMedia.playToAllWithResponse(playSource, playOptions)) + .consumeNextWith(response -> assertEquals(202, response.getStatusCode())) + .verifyComplete(); + } + + @Test + public void cancelAllOperationsWithResponse() { + StepVerifier.create( + callMedia.cancelAllMediaOperationsWithResponse()) + .consumeNextWith(response -> assertEquals(202, response.getStatusCode())) + .verifyComplete(); + } + + @Test + public void recognizeWithResponse() { + RecognizeOptions recognizeOptions = new RecognizeOptions(RecognizeInputType.DTMF, new RecognizeConfigurations()); + StepVerifier.create( + callMedia.recognizeWithResponse(recognizeOptions)) + .consumeNextWith(response -> assertEquals(202, response.getStatusCode())) + .verifyComplete(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaUnitTests.java new file mode 100644 index 0000000000000..e21cb6f694922 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallMediaUnitTests.java @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.FileSource; +import com.azure.communication.callautomation.models.PlayOptions; +import com.azure.communication.callautomation.models.RecognizeConfigurations; +import com.azure.communication.callautomation.models.RecognizeInputType; +import com.azure.communication.callautomation.models.RecognizeOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallMediaUnitTests { + + private CallMedia callMedia; + private FileSource playSource; + private PlayOptions playOptions; + + @BeforeEach + public void setup() { + CallConnection callConnection = + CallAutomationUnitTestBase.getCallConnection(new ArrayList<>( + Collections.singletonList(new AbstractMap.SimpleEntry<>("", 202))) + ); + callMedia = callConnection.getCallMedia(); + + playSource = new FileSource(); + playSource.setPlaySourceId("playSourceId"); + playSource.setUri("filePath"); + + playOptions = new PlayOptions() + .setLoop(false) + .setOperationContext("operationContext"); + } + + @Test + public void playFileWithResponseTest() { + Response response = callMedia.playWithResponse(playSource, + Collections.singletonList(new CommunicationUserIdentifier("id")), playOptions, Context.NONE); + assertEquals(response.getStatusCode(), 202); + } + + @Test + public void playFileToAllWithResponseTest() { + Response response = callMedia.playToAllWithResponse(playSource, playOptions, Context.NONE); + assertEquals(response.getStatusCode(), 202); + } + + @Test + public void cancelAllOperationsWithResponse() { + Response response = callMedia.cancelAllMediaOperationsWithResponse(Context.NONE); + assertEquals(response.getStatusCode(), 202); + } + + @Test + public void recognizeWithResponseTest() { + RecognizeOptions recognizeOptions = new RecognizeOptions(RecognizeInputType.DTMF, new RecognizeConfigurations()); + Response response = callMedia.recognizeWithResponse(recognizeOptions, Context.NONE); + assertEquals(response.getStatusCode(), 202); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncLiveTests.java new file mode 100644 index 0000000000000..abb817f8afc40 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncLiveTests.java @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.ServerCallLocator; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.core.http.HttpClient; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +public class CallRecordingAsyncLiveTests extends CallAutomationLiveTestBase { + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void recordingOperations(HttpClient httpClient) { + CallAutomationAsyncClient client = getCallingServerClientUsingConnectionString(httpClient) + .addPolicy((context, next) -> logHeaders("recordingOperationsAsync", next)) + .buildAsyncClient(); + + try { + String ngrok = "https://localhost"; + String serverCallId = "serverCallId"; + CallRecordingAsync callRecording = client.getCallRecordingAsync(); + RecordingStateResult recordingResponse = callRecording.startRecording( + new StartRecordingOptions(new ServerCallLocator(serverCallId)) + .setRecordingStateCallbackUrl(ngrok)) + .block(); + assertNotNull(recordingResponse); + String recordingId = recordingResponse.getRecordingId(); + assertNotNull(recordingId); + + recordingResponse = callRecording.getRecordingState(recordingId).block(); + assertNotNull(recordingResponse); + assertEquals(RecordingState.ACTIVE, recordingResponse.getRecordingState()); + + callRecording.pauseRecording(recordingId); + recordingResponse = callRecording.getRecordingState(recordingId).block(); + assertNotNull(recordingResponse); + assertEquals(RecordingState.INACTIVE, recordingResponse.getRecordingState()); + + callRecording.resumeRecording(recordingId); + recordingResponse = callRecording.getRecordingState(recordingId).block(); + assertNotNull(recordingResponse); + assertEquals(RecordingState.ACTIVE, recordingResponse.getRecordingState()); + + callRecording.stopRecording(recordingId).block(); + assertThrows(CallingServerErrorException.class, () -> callRecording.getRecordingState(recordingId).block()); + } catch (Exception ex) { + fail("Unexpected exception received", ex); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncUnitTests.java new file mode 100644 index 0000000000000..b9305990e1fa3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingAsyncUnitTests.java @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.ChannelAffinity; +import com.azure.communication.callautomation.models.RecordingChannel; +import com.azure.communication.callautomation.models.RecordingContent; +import com.azure.communication.callautomation.models.RecordingFormat; +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.ServerCallLocator; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; +import reactor.test.StepVerifier; + +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CallRecordingAsyncUnitTests extends CallRecordingUnitTestBase { + private CallRecordingAsync callRecording; + + @BeforeEach + public void setup() { + CallAutomationAsyncClient callingServerClient = CallAutomationUnitTestBase.getCallAutomationAsyncClient(new ArrayList<>()); + callRecording = callingServerClient.getCallRecordingAsync(); + } + + @Test + public void startRecordingRelativeUriFails() { + validateError(InvalidParameterException.class, + callRecording.startRecording(new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingStateCallbackUrl("/not/absolute/uri") + )); + } + + @Test + public void startRecordingWithFullParamsFails() { + StartRecordingOptions startRecordingOptions = new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingContent(RecordingContent.AUDIO_VIDEO) + .setRecordingChannel(RecordingChannel.MIXED) + .setRecordingFormat(RecordingFormat.MP4) + .setRecordingStateCallbackUrl("/not/absolute/uri") + .setChannelAffinity(new ArrayList(Arrays.asList( + new ChannelAffinity(0, new CommunicationUserIdentifier("rawId1")), + new ChannelAffinity(1, new CommunicationUserIdentifier("rawId2"))))); + + validateError(InvalidParameterException.class, callRecording.startRecordingWithResponse(startRecordingOptions)); + } + + @Test + public void recordingOperationsTest() { + CallAutomationAsyncClient callingServerClient = CallAutomationUnitTestBase.getCallAutomationAsyncClient( + recordingOperationsResponses + ); + callRecording = callingServerClient.getCallRecordingAsync(); + + validateRecordingState( + callRecording.startRecording(new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingStateCallbackUrl("https://localhost/")), + RecordingState.ACTIVE + ); + + validateOperationWithRecordingState(callRecording.pauseRecording(RECORDING_ID), + RecordingState.INACTIVE + ); + + validateOperationWithRecordingState(callRecording.resumeRecording(RECORDING_ID), + RecordingState.ACTIVE); + + validateOperation(callRecording.stopRecording(RECORDING_ID)); + validateError(CallingServerErrorException.class, callRecording.getRecordingState(RECORDING_ID)); + } + + private void validateRecordingState(Publisher publisher, RecordingState status) { + StepVerifier.create(publisher) + .consumeNextWith(recordingStateResponse -> validateRecording(recordingStateResponse, status)) + .verifyComplete(); + } + + private void validateOperationWithRecordingState(Publisher operation, RecordingState expectedRecordingState) { + validateOperation(operation); + validateRecordingState( + callRecording.getRecordingState(RECORDING_ID), + expectedRecordingState + ); + } + + private void validateOperation(Publisher operation) { + StepVerifier.create(operation).verifyComplete(); + } + + private void validateError(Class exception, Publisher publisher) { + StepVerifier.create(publisher) + .consumeErrorWith(error -> assertEquals(error.getClass().toString(), + exception.toString())) + .verify(); + } + + private void validateRecording(RecordingStateResult recordingState, RecordingState expectedStatus) { + assertEquals(RECORDING_ID, recordingState.getRecordingId()); + assertEquals(expectedStatus, recordingState.getRecordingState()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingLiveTests.java new file mode 100644 index 0000000000000..041d1c1691b42 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingLiveTests.java @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.ServerCallLocator; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.core.http.HttpClient; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +public class CallRecordingLiveTests extends CallAutomationLiveTestBase { + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void recordingOperations(HttpClient httpClient) { + CallAutomationClient client = getCallingServerClientUsingConnectionString(httpClient) + .addPolicy((context, next) -> logHeaders("recordingOperations", next)) + .buildClient(); + + try { + String ngrok = "https://localhost"; + String serverCallId = "serverCallId"; + CallRecording callRecording = client.getCallRecording(); + RecordingStateResult recordingResponse = callRecording.startRecording( + new StartRecordingOptions(new ServerCallLocator(serverCallId)) + .setRecordingStateCallbackUrl(ngrok)); + assertNotNull(recordingResponse); + String recordingId = recordingResponse.getRecordingId(); + assertNotNull(recordingId); + + recordingResponse = callRecording.getRecordingState(recordingId); + assertNotNull(recordingResponse); + assertEquals(RecordingState.ACTIVE, recordingResponse.getRecordingState()); + + callRecording.pauseRecording(recordingId); + recordingResponse = callRecording.getRecordingState(recordingId); + assertNotNull(recordingResponse); + assertEquals(RecordingState.INACTIVE, recordingResponse.getRecordingState()); + + callRecording.resumeRecording(recordingId); + recordingResponse = callRecording.getRecordingState(recordingId); + assertNotNull(recordingResponse); + assertEquals(RecordingState.ACTIVE, recordingResponse.getRecordingState()); + + callRecording.stopRecording(recordingId); + assertThrows(CallingServerErrorException.class, () -> callRecording.getRecordingState(recordingId)); + } catch (Exception ex) { + fail("Unexpected exception received", ex); + } + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTestBase.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTestBase.java new file mode 100644 index 0000000000000..4c585148e90c4 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTestBase.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.models.RecordingStateInternal; +import com.azure.communication.callautomation.implementation.models.RecordingStateResponseInternal; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; + +public class CallRecordingUnitTestBase { + static final String SERVER_CALL_ID = "aHR0cHM6Ly9jb252LXVzd2UtMDguY29udi5za3lwZS5jb20vY29udi8tby1FWjVpMHJrS3RFTDBNd0FST1J3P2k9ODgmZT02Mzc1Nzc0MTY4MDc4MjQyOTM"; + + static final String RECORDING_ID = "recordingId"; + private final RecordingStateResponseInternal recordingState = new RecordingStateResponseInternal().setRecordingId(RECORDING_ID); + private final String recordingActive = serializeObject(recordingState.setRecordingState(RecordingStateInternal.ACTIVE)); + private final String recordingInactive = serializeObject(recordingState.setRecordingState(RecordingStateInternal.INACTIVE)); + + ArrayList> recordingOperationsResponses = new ArrayList<>(Arrays.asList( + new AbstractMap.SimpleEntry<>(recordingActive, 200), //startRecording + new AbstractMap.SimpleEntry<>("", 202), //pauseRecording + new AbstractMap.SimpleEntry<>(recordingInactive, 200), //getRecordingState + new AbstractMap.SimpleEntry<>("", 202), //resumeRecording + new AbstractMap.SimpleEntry<>(recordingActive, 200), //getRecordingState + new AbstractMap.SimpleEntry<>("", 204), //stopRecording + new AbstractMap.SimpleEntry<>("", 404) //getRecordingState + )); + + private String serializeObject(Object o) { + ObjectMapper mapper = new ObjectMapper(); + String body = null; + try { + body = mapper.writeValueAsString(o); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return body; + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTests.java new file mode 100644 index 0000000000000..377e2ab141163 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/CallRecordingUnitTests.java @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.ChannelAffinity; +import com.azure.communication.callautomation.models.RecordingChannel; +import com.azure.communication.callautomation.models.RecordingContent; +import com.azure.communication.callautomation.models.RecordingFormat; +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.communication.callautomation.models.RecordingStateResult; +import com.azure.communication.callautomation.models.ServerCallLocator; +import com.azure.communication.callautomation.models.StartRecordingOptions; +import com.azure.communication.common.CommunicationUserIdentifier; +import com.azure.core.util.Context; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.security.InvalidParameterException; +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class CallRecordingUnitTests extends CallRecordingUnitTestBase { + private CallRecording callRecording; + + @BeforeEach + public void setup() { + CallAutomationClient callAutomationClient = CallAutomationUnitTestBase.getCallAutomationClient(new ArrayList<>()); + callRecording = callAutomationClient.getCallRecording(); + } + @Test + public void startRecordingRelativeUriFails() { + assertThrows( + InvalidParameterException.class, + () -> callRecording.startRecording(new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingStateCallbackUrl("/not/absolute/uri") + )); + } + + @Test + public void startRecordingWithFullParamsFails() { + StartRecordingOptions startRecordingOptions = new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingContent(RecordingContent.AUDIO_VIDEO) + .setRecordingChannel(RecordingChannel.MIXED) + .setRecordingFormat(RecordingFormat.MP4) + .setRecordingStateCallbackUrl("/not/absolute/uri") + .setChannelAffinity(new ArrayList(Arrays.asList( + new ChannelAffinity(0, new CommunicationUserIdentifier("rawId1")), + new ChannelAffinity(1, new CommunicationUserIdentifier("rawId2"))))); + + assertThrows( + InvalidParameterException.class, + () -> callRecording.startRecordingWithResponse(startRecordingOptions, Context.NONE) + ); + } + + @Test + public void recordingOperationsTest() { + + CallAutomationClient callAutomationClient = CallAutomationUnitTestBase.getCallAutomationClient( + recordingOperationsResponses + ); + callRecording = callAutomationClient.getCallRecording(); + + validateRecording( + callRecording.startRecording(new StartRecordingOptions(new ServerCallLocator(SERVER_CALL_ID)) + .setRecordingStateCallbackUrl("https://localhost/")), + RecordingState.ACTIVE + ); + + verifyOperationWithRecordingState( + () -> callRecording.pauseRecording(RECORDING_ID), + RecordingState.INACTIVE + ); + + verifyOperationWithRecordingState( + () -> callRecording.resumeRecording(RECORDING_ID), + RecordingState.ACTIVE + ); + + callRecording.stopRecording(RECORDING_ID); + assertThrows(CallingServerErrorException.class, () -> callRecording.getRecordingState(RECORDING_ID)); + } + + private void verifyOperationWithRecordingState(Runnable operation, RecordingState expectedStatus) { + operation.run(); + RecordingStateResult recordingState = callRecording.getRecordingState(RECORDING_ID); + validateRecording(recordingState, expectedStatus); + } + + private void validateRecording(RecordingStateResult recordingState, RecordingState expectedStatus) { + assertEquals(RECORDING_ID, recordingState.getRecordingId()); + assertEquals(expectedStatus, recordingState.getRecordingState()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteAsyncLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteAsyncLiveTests.java new file mode 100644 index 0000000000000..347eec9d1986f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteAsyncLiveTests.java @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.core.http.HttpClient; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import reactor.test.StepVerifier; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; + + +public class DeleteAsyncLiveTests extends CallAutomationLiveTestBase { + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecordingWithConnectionStringAsyncClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient callAutomationAsyncClient = setupAsyncClient(builder, "deleteRecordingWithConnectionStringAsyncClient"); + deleteRecording(callAutomationAsyncClient); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecordingWithTokenCredentialAsyncClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingTokenCredential(httpClient); + CallAutomationAsyncClient callAutomationAsyncClient = setupAsyncClient(builder, "deleteRecordingWithTokenCredentialAsyncClient"); + deleteRecording(callAutomationAsyncClient); + } + + private void deleteRecording(CallAutomationAsyncClient callAutomationAsyncClient) { + StepVerifier.create(callAutomationAsyncClient + .getCallRecordingAsync() + .deleteRecordingWithResponse(RECORDING_DELETE_URL)) + .consumeNextWith(response -> assertThat(response.getStatusCode(), is(equalTo(200)))) + .verifyComplete(); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecording401Async(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingInvalidTokenCredential(httpClient); + CallAutomationAsyncClient callAutomationAsyncClient = setupAsyncClient(builder, "deleteRecording404Async"); + StepVerifier.create(callAutomationAsyncClient + .getCallRecordingAsync() + .deleteRecordingWithResponse(RECORDING_DELETE_URL)) + .consumeNextWith(response -> assertThat(response.getStatusCode(), is(equalTo(401)))) + .verifyComplete(); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecording404Async(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient callAutomationAsyncClient = setupAsyncClient(builder, "deleteRecording404Async"); + StepVerifier.create(callAutomationAsyncClient + .getCallRecordingAsync() + .deleteRecordingWithResponse(RECORDING_DELETE_URL_404)) + .consumeNextWith(response -> assertThat(response.getStatusCode(), is(equalTo(404)))) + .verifyComplete(); + } + + private CallAutomationAsyncClient setupAsyncClient(CallAutomationClientBuilder builder, String testName) { + return addLoggingPolicy(builder, testName).buildAsyncClient(); + } + + protected CallAutomationClientBuilder addLoggingPolicy(CallAutomationClientBuilder builder, String testName) { + return builder.addPolicy((context, next) -> logHeaders(testName, next)); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteLiveTests.java new file mode 100644 index 0000000000000..3e3bbc6953ce3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DeleteLiveTests.java @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.core.http.HttpClient; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.fail; + + +public class DeleteLiveTests extends CallAutomationLiveTestBase { + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecordingWithConnectionStringClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient callAutomationClient = setupClient(builder, "deleteRecordingWithConnectionStringClient"); + deleteRecording(callAutomationClient); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecordingWithTokenCredentialClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingTokenCredential(httpClient); + CallAutomationClient callAutomationClient = setupClient(builder, "deleteRecordingWithTokenCredentialClient"); + deleteRecording(callAutomationClient); + } + + private void deleteRecording(CallAutomationClient callingServerAsyncClient) { + try { + Response response = callingServerAsyncClient + .getCallRecording() + .deleteRecordingWithResponse(RECORDING_DELETE_URL, Context.NONE); + assertThat(response.getStatusCode(), is(equalTo(200))); + } catch (Exception e) { + fail("Unexpected exception received", e); + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecording401(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingInvalidTokenCredential(httpClient); + CallAutomationClient callAutomationClient = setupClient(builder, "deleteRecording404Async"); + Response response = callAutomationClient + .getCallRecording() + .deleteRecordingWithResponse(RECORDING_DELETE_URL, Context.NONE); + assertThat(response.getStatusCode(), is(equalTo(401))); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void deleteRecording404(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient callAutomationClient = setupClient(builder, "deleteRecording404Async"); + Response response = callAutomationClient + .getCallRecording() + .deleteRecordingWithResponse(RECORDING_DELETE_URL_404, Context.NONE); + assertThat(response.getStatusCode(), is(equalTo(404))); + } + + private CallAutomationClient setupClient(CallAutomationClientBuilder builder, String testName) { + return addLoggingPolicy(builder, testName).buildClient(); + } + + protected CallAutomationClientBuilder addLoggingPolicy(CallAutomationClientBuilder builder, String testName) { + return builder.addPolicy((context, next) -> logHeaders(testName, next)); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncLiveTests.java new file mode 100644 index 0000000000000..f09bb67f39ddb --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncLiveTests.java @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.communication.callautomation.models.DownloadToFileOptions; +import com.azure.communication.callautomation.models.ParallelDownloadOptions; +import com.azure.core.http.HttpClient; +import com.azure.core.util.Context; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousFileChannel; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; + +public class DownloadContentAsyncLiveTests extends CallAutomationLiveTestBase { + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadMetadataWithConnectionStringAsyncClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadMetadataWithConnectionStringAsyncClient"); + downloadMetadata(conversationAsyncClient); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadMetadataWithTokenCredentialAsyncClient(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingTokenCredential(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadMetadataWithTokenCredentialAsyncClient"); + downloadMetadata(conversationAsyncClient); + } + + private void downloadMetadata(CallAutomationAsyncClient conversationAsyncClient) { + + try { + validateMetadata(conversationAsyncClient.getCallRecordingAsync().downloadStream(METADATA_URL)); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + throw e; + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadMetadataRetryingAsync(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadMetadataRetryingAsync"); + + try { + validateMetadata(conversationAsyncClient.getCallRecordingAsync().downloadStream(METADATA_URL)); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + throw e; + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadVideoAsync(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadVideoAsync"); + + try { + StepVerifier.create(conversationAsyncClient.getCallRecordingAsync() + .downloadStreamWithResponse(VIDEO_URL, null)) + .consumeNextWith(response -> StepVerifier.create(response.getValue()) + .consumeNextWith(byteBuffer -> + assertThat(Integer.parseInt(response.getHeaders().getValue("Content-Length")), + is(equalTo(byteBuffer.array().length)))) + .verifyComplete()) + .verifyComplete(); + } catch (Exception e) { + System.out.println("Error: " + e.getMessage()); + throw e; + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadToFileAsync(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadToFileAsync"); + AsynchronousFileChannel channel = Mockito.mock(AsynchronousFileChannel.class); + + doAnswer(invocation -> { + ByteBuffer stream = invocation.getArgument(0); + CompletionHandler completionHandler = invocation.getArgument(3); + completionHandler.completed(439, stream.position(stream.limit())); + return null; + }).doAnswer(invocation -> { + ByteBuffer stream = invocation.getArgument(0); + CompletionHandler completionHandler = invocation.getArgument(3); + completionHandler.completed(438, stream.position(stream.limit())); + return null; + }).when(channel).write(any(ByteBuffer.class), + anyLong(), + any(), + any()); + + ParallelDownloadOptions parallelOptions = new ParallelDownloadOptions().setBlockSize(479L); + DownloadToFileOptions options = new DownloadToFileOptions().setParallelDownloadOptions(parallelOptions); + conversationAsyncClient + .getCallRecordingAsync() + .downloadToWithResponse(METADATA_URL, + Paths.get("dummyPath"), + channel, + options, + Context.NONE).block(); + + Mockito.verify(channel, times(2)).write(any(ByteBuffer.class), anyLong(), + any(), any()); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadToFileRetryingAsync(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadToFileRetryingAsync"); + AsynchronousFileChannel channel = Mockito.mock(AsynchronousFileChannel.class); + + doAnswer(invocation -> { + ByteBuffer stream = invocation.getArgument(0); + String metadata = new String(stream.array(), StandardCharsets.UTF_8); + assertTrue(metadata.contains("0-eus-d2-3cca2175891f21c6c9a5975a12c0141c")); + CompletionHandler completionHandler = invocation.getArgument(3); + completionHandler.completed(957, stream.position(stream.limit())); + return null; + }).when(channel).write(any(ByteBuffer.class), + anyLong(), + any(), + any()); + + + conversationAsyncClient + .getCallRecordingAsync() + .downloadToWithResponse(METADATA_URL, + Paths.get("dummyPath"), + channel, + new DownloadToFileOptions(), + Context.NONE).block(); + + Mockito.verify(channel).write(any(ByteBuffer.class), anyLong(), + any(), any()); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadContent404Async(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationAsyncClient conversationAsyncClient = setupAsyncClient(builder, "downloadContent404Async"); + StepVerifier.create(conversationAsyncClient + .getCallRecordingAsync() + .downloadStreamWithResponse(CONTENT_URL_404, null)) + .consumeNextWith(response -> { + assertThat(response.getStatusCode(), is(equalTo(404))); + StepVerifier.create(response.getValue()).verifyError(CallingServerErrorException.class); + }) + .verifyComplete(); + } + + private CallAutomationAsyncClient setupAsyncClient(CallAutomationClientBuilder builder, String testName) { + return addLoggingPolicy(builder, testName).buildAsyncClient(); + } + + protected CallAutomationClientBuilder addLoggingPolicy(CallAutomationClientBuilder builder, String testName) { + return builder.addPolicy((context, next) -> logHeaders(testName, next)); + } + + private void validateMetadata(Flux metadataByteBuffer) { + StepVerifier.create(metadataByteBuffer) + .consumeNextWith(byteBuffer -> { + String metadata = new String(byteBuffer.array(), StandardCharsets.UTF_8); + assertThat(metadata.contains("0-eus-d2-3cca2175891f21c6c9a5975a12c0141c"), is(true)); + }) + .verifyComplete(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncUnitTests.java new file mode 100644 index 0000000000000..afa3836531b1d --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentAsyncUnitTests.java @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.UUID; +import java.util.AbstractMap.SimpleEntry; + +import com.azure.communication.callautomation.models.DownloadToFileOptions; +import com.azure.communication.callautomation.models.ParallelDownloadOptions; +import com.azure.core.http.HttpRange; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +public class DownloadContentAsyncUnitTests { + + private static final String CONTENTS = "VideoContents"; + private static final String AMS_ENDPOINT = "https://url.com"; + + private CallRecordingAsync callRecording; + + @BeforeEach + public void setup() { + CallAutomationAsyncClient callingServerClient = + CallAutomationUnitTestBase.getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(CallAutomationUnitTestBase.generateDownloadResult(CONTENTS), 200) + ))); + callRecording = callingServerClient.getCallRecordingAsync(); + } + + @Test + public void downloadStream() { + StepVerifier.create( + callRecording.downloadStream(AMS_ENDPOINT) + ).consumeNextWith(byteBuffer -> { + String resultContents = new String(byteBuffer.array(), StandardCharsets.UTF_8); + assertEquals(CONTENTS, resultContents); + }).verifyComplete(); + } + + @Test + public void downloadStreamWithResponse() { + StepVerifier.create( + callRecording.downloadStreamWithResponse( + AMS_ENDPOINT, + new HttpRange(CONTENTS.length())) + ).consumeNextWith(response -> { + assertEquals(200, response.getStatusCode()); + verifyContents(response.getValue()); + }).verifyComplete(); + } + + @Test + public void downloadStreamWithResponseThrowException() { + CallAutomationAsyncClient callingServerClient = + CallAutomationUnitTestBase.getCallAutomationAsyncClient(new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>("", 416) + ))); + callRecording = callingServerClient.getCallRecordingAsync(); + + StepVerifier.create( + callRecording.downloadStreamWithResponse(AMS_ENDPOINT, new HttpRange(CONTENTS.length())) + ).consumeNextWith(response -> + StepVerifier.create(response.getValue()).verifyError(NullPointerException.class)); + } + + @Test + public void downloadToWithResponse() throws IOException { + String fileName = "./" + UUID.randomUUID().toString().replace("-", "") + ".txt"; + Path path = FileSystems.getDefault().getPath(fileName); + ParallelDownloadOptions parallelOptions = new ParallelDownloadOptions().setMaxConcurrency(1).setBlockSize(512L); + DownloadToFileOptions options = new DownloadToFileOptions().setParallelDownloadOptions(parallelOptions).setOverwrite(true); + File file = null; + + try { + StepVerifier.create(callRecording.downloadToWithResponse(AMS_ENDPOINT, path, options)) + .consumeNextWith(response -> assertEquals(200, response.getStatusCode())).verifyComplete(); + + file = path.toFile(); + assertTrue(file.exists(), "file does not exist"); + BufferedReader br = new BufferedReader(new FileReader(file)); + assertEquals(CONTENTS, br.readLine()); + br.close(); + } finally { + if (file != null && file.exists()) { + assertTrue(file.delete()); + } + } + } + + private void verifyContents(Flux response) { + StepVerifier.create(response) + .consumeNextWith(byteBuffer -> { + String resultContents = new String(byteBuffer.array(), StandardCharsets.UTF_8); + assertEquals(CONTENTS, resultContents); + }).verifyComplete(); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentLiveTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentLiveTests.java new file mode 100644 index 0000000000000..848791753225a --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentLiveTests.java @@ -0,0 +1,152 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.CallingServerErrorException; +import com.azure.core.http.HttpClient; +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; +import org.junit.jupiter.api.condition.DisabledIfEnvironmentVariable; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mockito; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.doThrow; + +public class DownloadContentLiveTests extends CallAutomationLiveTestBase { + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadMetadataWithConnectionStringClient(HttpClient httpClient) throws UnsupportedEncodingException { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadMetadataWithConnectionStringClient"); + downloadMetadata(conversationClient.getCallRecording()); + } + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadMetadataWithTokenCredentialClient(HttpClient httpClient) throws UnsupportedEncodingException { + CallAutomationClientBuilder builder = getCallingServerClientUsingTokenCredential(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadMetadataWithTokenCredentialClient"); + downloadMetadata(conversationClient.getCallRecording()); + } + + private void downloadMetadata(CallRecording callRecording) throws UnsupportedEncodingException { + try { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + callRecording.downloadTo(METADATA_URL, byteArrayOutputStream); + String metadata = byteArrayOutputStream.toString(StandardCharsets.UTF_8.name()); + assertThat(metadata.contains("0-eus-d2-3cca2175891f21c6c9a5975a12c0141c"), is(true)); + } catch (Exception e) { + fail("Unexpected exception received", e); + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadVideo(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadVideo"); + + try { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + Response response = conversationClient + .getCallRecording() + .downloadToWithResponse(VIDEO_URL, byteArrayOutputStream, null, Context.NONE); + assertThat(response, is(notNullValue())); + assertThat( + response.getHeaders().getValue("Content-Type"), + is(equalTo("application/octet-stream"))); + assertThat( + Integer.parseInt(response.getHeaders().getValue("Content-Length")), + is(equalTo(byteArrayOutputStream.size()))); + } catch (Exception e) { + fail("Unexpected exception received", e); + } + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadContent404(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadContent404"); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + CallingServerErrorException ex = assertThrows(CallingServerErrorException.class, + () -> conversationClient + .getCallRecording() + .downloadTo(CONTENT_URL_404, byteArrayOutputStream)); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + public void downloadContentWrongUrl(HttpClient httpClient) { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadContentWrongUrl"); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + IllegalArgumentException ex = + assertThrows( + IllegalArgumentException.class, + () -> conversationClient + .getCallRecording() + .downloadTo("wrongurl", byteArrayOutputStream)); + assertThat(ex, is(notNullValue())); + } + + @ParameterizedTest + @MethodSource("com.azure.core.test.TestBase#getHttpClients") + @DisabledIfEnvironmentVariable( + named = "SKIP_LIVE_TEST", + matches = "(?i)(true)", + disabledReason = "Requires human intervention") + public void downloadContentStreamFailure(HttpClient httpClient) throws IOException { + CallAutomationClientBuilder builder = getCallingServerClientUsingConnectionString(httpClient); + CallAutomationClient conversationClient = setupClient(builder, "downloadContent404"); + + OutputStream outputStream = Mockito.mock(OutputStream.class); + doThrow(IOException.class).when(outputStream).write(Mockito.any(), Mockito.anyInt(), Mockito.anyInt()); + assertThrows( + UncheckedIOException.class, + () -> conversationClient + .getCallRecording() + .downloadTo(METADATA_URL, outputStream)); + } + + private CallAutomationClient setupClient(CallAutomationClientBuilder builder, String testName) { + return addLoggingPolicy(builder, testName).buildClient(); + } + + protected CallAutomationClientBuilder addLoggingPolicy(CallAutomationClientBuilder builder, String testName) { + return builder.addPolicy((context, next) -> logHeaders(testName, next)); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentUnitTests.java new file mode 100644 index 0000000000000..31d655463ec43 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/DownloadContentUnitTests.java @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.AbstractMap.SimpleEntry; +import java.util.Collections; + +import com.azure.core.http.rest.Response; +import com.azure.core.util.Context; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class DownloadContentUnitTests { + + private static final String CONTENT = "VideoContents"; + private static final String AMS_ENDPOINT = "https://url.com"; + private CallRecording callRecording; + + @BeforeEach + public void setUp() { + CallAutomationClient callAutomationClient = CallAutomationUnitTestBase.getCallAutomationClient( + new ArrayList<>( + Collections.singletonList( + new SimpleEntry<>(CallAutomationUnitTestBase.generateDownloadResult(CONTENT), 200) + ))); + callRecording = callAutomationClient.getCallRecording(); + } + + @Test + public void downloadTo() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + callRecording.downloadTo(AMS_ENDPOINT, stream); + Reader reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray())); + BufferedReader b = new BufferedReader(reader); + assertEquals(CONTENT, b.readLine()); + } + + @Test + public void downloadToWithResponse() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + Response response = callRecording.downloadToWithResponse(AMS_ENDPOINT, stream, null, Context.NONE); + assertEquals(200, response.getStatusCode()); + Reader reader = new InputStreamReader(new ByteArrayInputStream(stream.toByteArray())); + BufferedReader b = new BufferedReader(reader); + assertEquals(CONTENT, b.readLine()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/EventHandlerUnitTests.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/EventHandlerUnitTests.java new file mode 100644 index 0000000000000..54dcf4c7eb3a9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/EventHandlerUnitTests.java @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.models.RecordingState; +import com.azure.communication.callautomation.models.events.CallAutomationEventBase; +import com.azure.communication.callautomation.models.events.CallConnectedEvent; +import com.azure.communication.callautomation.models.events.ParticipantsUpdatedEvent; +import com.azure.communication.callautomation.models.events.PlayCompleted; +import com.azure.communication.callautomation.models.events.PlayFailed; +import com.azure.communication.callautomation.models.events.RecordingStateChangedEvent; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class EventHandlerUnitTests { + static final String EVENT_PARTICIPANT_UPDATED = "{\"id\":\"61069ef9-5ca9-457f-ac36-e2bb5e8400ca\",\"source\":\"calling/callConnections/401f3500-62bd-46a9-8c09-9e1b06caca01/ParticipantsUpdated\",\"type\":\"Microsoft.Communication.ParticipantsUpdated\",\"data\":{\"participants\":[{\"rawId\":\"8:acs:816df1ca-971b-44d7-b8b1-8fba90748500_00000013-2ff6-dd51-54b7-a43a0d001998\",\"kind\":\"communicationUser\",\"communicationUser\":{\"id\":\"8:acs:816df1ca-971b-44d7-b8b1-8fba90748500_00000013-2ff6-dd51-54b7-a43a0d001998\"}},{\"rawId\":\"8:acs:816df1ca-971b-44d7-b8b1-8fba90748500_00000013-2ff7-1579-99bf-a43a0d0010bc\",\"kind\":\"communicationUser\",\"communicationUser\":{\"id\":\"8:acs:816df1ca-971b-44d7-b8b1-8fba90748500_00000013-2ff7-1579-99bf-a43a0d0010bc\"}}],\"type\":\"participantsUpdated\",\"callConnectionId\":\"401f3500-62bd-46a9-8c09-9e1b06caca01\",\"correlationId\":\"ebd8bf1f-0794-494f-bdda-913042c06ef7\"},\"time\":\"2022-08-12T03:35:07.9129474+00:00\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"subject\":\"calling/callConnections/401f3500-62bd-46a9-8c09-9e1b06caca01/ParticipantsUpdated\"}"; + static final String EVENT_CALL_CONNECTED = "{\"id\":\"46116fb7-27e0-4a99-9478-a659c8fd4815\",\"source\":\"calling/callConnections/401f3500-62bd-46a9-8c09-9e1b06caca01/CallConnected\",\"type\":\"Microsoft.Communication.CallConnected\",\"data\":{\"type\":\"callConnected\",\"callConnectionId\":\"401f3500-62bd-46a9-8c09-9e1b06caca01\",\"correlationId\":\"ebd8bf1f-0794-494f-bdda-913042c06ef7\"},\"time\":\"2022-08-12T03:35:07.8174402+00:00\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"subject\":\"calling/callConnections/401f3500-62bd-46a9-8c09-9e1b06caca01/CallConnected\"}"; + + @Test + public void parseEvent() { + CallAutomationEventBase callAutomationEventBase = EventHandler.parseEvent(EVENT_PARTICIPANT_UPDATED); + + assertNotNull(callAutomationEventBase); + assertEquals(callAutomationEventBase.getClass(), ParticipantsUpdatedEvent.class); + assertNotNull(((ParticipantsUpdatedEvent) callAutomationEventBase).getParticipants()); + } + + @Test + public void parseEventList() { + List callAutomationEventBaseList = EventHandler.parseEventList("[" + + EVENT_CALL_CONNECTED + "," + EVENT_PARTICIPANT_UPDATED + "]"); + + assertNotNull(callAutomationEventBaseList); + assertEquals(callAutomationEventBaseList.get(0).getClass(), CallConnectedEvent.class); + assertEquals(callAutomationEventBaseList.get(1).getClass(), ParticipantsUpdatedEvent.class); + assertNotNull(callAutomationEventBaseList.get(0).getCallConnectionId()); + } + + @Test + public void parseRecordingStateChangedEvent() { + String receivedEvent = "[\n" + + " {\n" + + " \"id\": \"bf59843a-888f-47ca-8d1c-885c1f5e71dc\",\n" + + " \"source\": \"calling/recordings/serverCallId/recordingId/recordingId/RecordingStateChanged\",\n" + + " \"type\": \"Microsoft.Communication.CallRecordingStateChanged\",\n" + + " \"data\": {\n" + + " \"type\": \"recordingStateChanged\",\n" + + " \"recordingId\": \"recordingId\",\n" + + " \"state\": \"active\",\n" + + " \"startDateTime\": \"2022-08-11T23:42:45.4394211+00:00\",\n" + + " \"callConnectionId\": \"callConnectionId\",\n" + + " \"serverCallId\": \"serverCallId\",\n" + + " \"correlationId\": \"correlationId\"\n" + + " },\n" + + " \"time\": \"2022-08-11T23:42:45.5346632+00:00\",\n" + + " \"specversion\": \"1.0\",\n" + + " \"datacontenttype\": \"application/json\",\n" + + " \"subject\": \"calling/recordings/serverCallId/recordingId/recordingId/RecordingStateChanged\"\n" + + " }\n" + + "]"; + CallAutomationEventBase event = EventHandler.parseEvent(receivedEvent); + assertNotNull(event); + RecordingStateChangedEvent recordingEvent = (RecordingStateChangedEvent) event; + assertNotNull(recordingEvent); + assertEquals("serverCallId", recordingEvent.getServerCallId()); + assertEquals("recordingId", recordingEvent.getRecordingId()); + assertEquals(RecordingState.ACTIVE, recordingEvent.getRecordingState()); + } + + @Test + public void parsePlayCompletedEvent() { + String receivedEvent = "[{\n" + + "\"id\": \"704a7a96-4d74-4ebe-9cd0-b7cc39c3d7b1\",\n" + + "\"source\": \"calling/callConnections/callConnectionId/PlayCompleted\",\n" + + "\"type\": \"Microsoft.Communication.PlayCompleted\",\n" + + "\"data\": {\n" + + "\"resultInfo\": {\n" + + "\"code\": 200,\n" + + "\"subCode\": 0,\n" + + "\"message\": \"Action completed successfully.\"\n" + + "},\n" + + "\"type\": \"playCompleted\",\n" + + "\"callConnectionId\": \"callConnectionId\",\n" + + "\"serverCallId\": \"serverCallId\",\n" + + "\"correlationId\": \"correlationId\"\n" + + "},\n" + + "\"time\": \"2022-08-12T03:13:25.0252763+00:00\",\n" + + "\"specversion\": \"1.0\",\n" + + "\"datacontenttype\": \"application/json\",\n" + + "\"subject\": \"calling/callConnections/callConnectionId/PlayCompleted\"\n" + + "}]"; + CallAutomationEventBase event = EventHandler.parseEvent(receivedEvent); + assertNotNull(event); + PlayCompleted playCompleted = (PlayCompleted) event; + assertNotNull(playCompleted); + assertEquals("serverCallId", playCompleted.getServerCallId()); + assertEquals(200, playCompleted.getResultInfo().getCode()); + } + + @Test + public void parsePlayFailedEvent() { + String receivedEvent = "[{\n" + + "\"id\": \"704a7a96-4d74-4ebe-9cd0-b7cc39c3d7b1\",\n" + + "\"source\": \"calling/callConnections/callConnectionId/PlayFailed\",\n" + + "\"type\": \"Microsoft.Communication.PlayFailed\",\n" + + "\"data\": {\n" + + "\"resultInfo\": {\n" + + "\"code\": 404,\n" + + "\"subCode\": 0,\n" + + "\"message\": \"File source was not found\"\n" + + "},\n" + + "\"type\": \"playFailed\",\n" + + "\"callConnectionId\": \"callConnectionId\",\n" + + "\"serverCallId\": \"serverCallId\",\n" + + "\"correlationId\": \"correlationId\"\n" + + "},\n" + + "\"time\": \"2022-08-12T03:13:25.0252763+00:00\",\n" + + "\"specversion\": \"1.0\",\n" + + "\"datacontenttype\": \"application/json\",\n" + + "\"subject\": \"calling/callConnections/callConnectionId/PlayFailed\"\n" + + "}]"; + CallAutomationEventBase event = EventHandler.parseEvent(receivedEvent); + assertNotNull(event); + PlayFailed playFailed = (PlayFailed) event; + assertNotNull(playFailed); + assertEquals("serverCallId", playFailed.getServerCallId()); + assertEquals(404, playFailed.getResultInfo().getCode()); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/MockHttpClient.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/MockHttpClient.java new file mode 100644 index 0000000000000..c7c184f151822 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/MockHttpClient.java @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import java.util.ArrayList; +import java.util.List; +import java.util.AbstractMap.SimpleEntry; + +import com.azure.communication.callautomation.implementation.accesshelpers.ErrorConstructorProxy; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; + +import com.azure.core.test.http.NoOpHttpClient; +import reactor.core.publisher.Mono; + +public class MockHttpClient extends NoOpHttpClient { + public static final String THROW_TEST_EXCEPTION = "exception"; + private ArrayList> responses = new ArrayList>(); + private final ArrayList requests = new ArrayList(); + + public MockHttpClient(ArrayList> responses) { + this.responses = responses; + } + + public List getRequests() { + return requests; + } + + @Override + public Mono send(HttpRequest request) { + requests.add(request); + + if (responses.size() > 0) { + SimpleEntry entry = responses.get(0); + responses.remove(entry); + HttpResponse response = CallAutomationUnitTestBase.generateMockResponse(entry.getKey(), request, entry.getValue()); + if (entry.getKey().startsWith(THROW_TEST_EXCEPTION)) { + return Mono.error(ErrorConstructorProxy.create(new HttpResponseException("Mock error", response))); + } + + return Mono.just(CallAutomationUnitTestBase.generateMockResponse(entry.getKey(), request, entry.getValue())); + } + + return Mono.just(CallAutomationUnitTestBase.generateMockResponse("", request, 500)); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/ModelGenerator.java b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/ModelGenerator.java new file mode 100644 index 0000000000000..5669d416cc4e7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/java/com/azure/communication/callautomation/ModelGenerator.java @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.communication.callautomation; + +import com.azure.communication.callautomation.implementation.models.AcsCallParticipantInternal; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModel; +import com.azure.communication.callautomation.implementation.models.CommunicationIdentifierModelKind; +import com.azure.communication.callautomation.implementation.models.CommunicationUserIdentifierModel; + + +public class ModelGenerator { + static CommunicationIdentifierModel generateUserIdentifierModel(String userId) { + return new CommunicationIdentifierModel() + .setRawId("rawId") + .setKind(CommunicationIdentifierModelKind.COMMUNICATION_USER) + .setCommunicationUser(new CommunicationUserIdentifierModel() + .setId(userId)); + } + + static AcsCallParticipantInternal generateAcsCallParticipantInternal(String callerId, boolean isMuted) { + return new AcsCallParticipantInternal() + .setIdentifier(ModelGenerator.generateUserIdentifierModel(callerId)) + .setIsMuted(isMuted); + } +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingAsyncLiveTests.recordingOperations[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingAsyncLiveTests.recordingOperations[1].json new file mode 100644 index 0000000000000..04f2a0ff09a04 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingAsyncLiveTests.recordingOperations[1].json @@ -0,0 +1,158 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "2947534d-6ccd-4401-adf4-3aa0b3ca76f9", + "Content-Type" : "application/json" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "209", + "retry-after" : "0", + "X-Azure-Ref" : "02vHzYgAAAACDNRqtlGyIQZtdg2w6fexPV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "8e89a51d-529b-4143-b64a-25d6dc090387", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"inactive\"}", + "x-ms-client-request-id" : "2947534d-6ccd-4401-adf4-3aa0b3ca76f9", + "Date" : "Wed, 10 Aug 2022 17:58:53 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "1d6f88a6-14d8-44ea-8537-7698de40617f" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "207", + "retry-after" : "0", + "X-Azure-Ref" : "06PHzYgAAAADrl48+N0oSRZvcdb3H65HaV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"active\"}", + "x-ms-client-request-id" : "1d6f88a6-14d8-44ea-8537-7698de40617f", + "Date" : "Wed, 10 Aug 2022 17:59:03 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ:pause?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "43377c88-daaa-4577-8264-29c047cf72a8" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "0", + "retry-after" : "0", + "X-Azure-Ref" : "06PHzYgAAAAC2nOg0rzaBRpBooGVCBw76V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "202", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "43377c88-daaa-4577-8264-29c047cf72a8", + "Date" : "Wed, 10 Aug 2022 17:59:03 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "d14cccef-4d2a-45dc-8b48-0b831370fc07" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "209", + "retry-after" : "0", + "X-Azure-Ref" : "08vHzYgAAAAAGeZ4E3Ag8RpQwNVbI7on/V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"inactive\"}", + "x-ms-client-request-id" : "d14cccef-4d2a-45dc-8b48-0b831370fc07", + "Date" : "Wed, 10 Aug 2022 17:59:13 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ:resume?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "5a34ce19-4ab0-49bd-80f5-2b12ac253319" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "0", + "retry-after" : "0", + "X-Azure-Ref" : "08vHzYgAAAACpbrHjgfEkQKOAr65Z5JpiV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "202", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "5a34ce19-4ab0-49bd-80f5-2b12ac253319", + "Date" : "Wed, 10 Aug 2022 17:59:14 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "2b0d9119-b27d-44ae-a559-d010431186ea" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "207", + "retry-after" : "0", + "X-Azure-Ref" : "0/PHzYgAAAAC5oykuX4TXTbOuVAhUc8QoV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"active\"}", + "x-ms-client-request-id" : "2b0d9119-b27d-44ae-a559-d010431186ea", + "Date" : "Wed, 10 Aug 2022 17:59:24 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "a185ddbb-df2f-49e4-8eb6-beb9465b35e0" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "retry-after" : "0", + "X-Azure-Ref" : "0/PHzYgAAAADv5sVDEbq6RLGv5YHunKv/V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "204", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "a185ddbb-df2f-49e4-8eb6-beb9465b35e0", + "Date" : "Wed, 10 Aug 2022 17:59:27 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "ac2a5cf5-3a14-4998-be02-bdec8c1d4e94" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "58", + "retry-after" : "0", + "X-Azure-Ref" : "0CfLzYgAAAAAN5EWdKxF/S5YtHv49dFaXV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "404", + "X-Microsoft-Skype-Chain-ID" : "1584f947-7aca-412f-96ea-f696ed2dc9e6", + "Body" : "{\"error\":{\"code\":\"8522\",\"message\":\"Recording not found.\"}}", + "x-ms-client-request-id" : "ac2a5cf5-3a14-4998-be02-bdec8c1d4e94", + "Date" : "Wed, 10 Aug 2022 17:59:37 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingLiveTests.recordingOperations[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingLiveTests.recordingOperations[1].json new file mode 100644 index 0000000000000..04f2a0ff09a04 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/CallRecordingLiveTests.recordingOperations[1].json @@ -0,0 +1,158 @@ +{ + "networkCallRecords" : [ { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "2947534d-6ccd-4401-adf4-3aa0b3ca76f9", + "Content-Type" : "application/json" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "209", + "retry-after" : "0", + "X-Azure-Ref" : "02vHzYgAAAACDNRqtlGyIQZtdg2w6fexPV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "8e89a51d-529b-4143-b64a-25d6dc090387", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"inactive\"}", + "x-ms-client-request-id" : "2947534d-6ccd-4401-adf4-3aa0b3ca76f9", + "Date" : "Wed, 10 Aug 2022 17:58:53 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "1d6f88a6-14d8-44ea-8537-7698de40617f" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "207", + "retry-after" : "0", + "X-Azure-Ref" : "06PHzYgAAAADrl48+N0oSRZvcdb3H65HaV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"active\"}", + "x-ms-client-request-id" : "1d6f88a6-14d8-44ea-8537-7698de40617f", + "Date" : "Wed, 10 Aug 2022 17:59:03 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ:pause?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "43377c88-daaa-4577-8264-29c047cf72a8" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "0", + "retry-after" : "0", + "X-Azure-Ref" : "06PHzYgAAAAC2nOg0rzaBRpBooGVCBw76V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "202", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "43377c88-daaa-4577-8264-29c047cf72a8", + "Date" : "Wed, 10 Aug 2022 17:59:03 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "d14cccef-4d2a-45dc-8b48-0b831370fc07" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "209", + "retry-after" : "0", + "X-Azure-Ref" : "08vHzYgAAAAAGeZ4E3Ag8RpQwNVbI7on/V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"inactive\"}", + "x-ms-client-request-id" : "d14cccef-4d2a-45dc-8b48-0b831370fc07", + "Date" : "Wed, 10 Aug 2022 17:59:13 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "POST", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ:resume?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "5a34ce19-4ab0-49bd-80f5-2b12ac253319" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "0", + "retry-after" : "0", + "X-Azure-Ref" : "08vHzYgAAAACpbrHjgfEkQKOAr65Z5JpiV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "202", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "5a34ce19-4ab0-49bd-80f5-2b12ac253319", + "Date" : "Wed, 10 Aug 2022 17:59:14 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "2b0d9119-b27d-44ae-a559-d010431186ea" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "207", + "retry-after" : "0", + "X-Azure-Ref" : "0/PHzYgAAAAC5oykuX4TXTbOuVAhUc8QoV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "200", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "Body" : "{\"recordingId\":\"eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ\",\"recordingState\":\"active\"}", + "x-ms-client-request-id" : "2b0d9119-b27d-44ae-a559-d010431186ea", + "Date" : "Wed, 10 Aug 2022 17:59:24 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + }, { + "Method" : "DELETE", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "a185ddbb-df2f-49e4-8eb6-beb9465b35e0" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "retry-after" : "0", + "X-Azure-Ref" : "0/PHzYgAAAADv5sVDEbq6RLGv5YHunKv/V1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "204", + "X-Microsoft-Skype-Chain-ID" : "ee30ff86-b372-46b3-8a9f-ecb5b8aeafcb", + "x-ms-client-request-id" : "a185ddbb-df2f-49e4-8eb6-beb9465b35e0", + "Date" : "Wed, 10 Aug 2022 17:59:27 GMT" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.communication.azure.com/calling/recordings/eyJQbGF0Zm9ybUVuZHBvaW50SWQiOiI0MjFmMGIwMC1kOTliLTQwYjctYjIxMy0yYzJiZDQxMDhlYWQiLCJSZXNvdXJjZVNwZWNpZmljSWQiOiI4MzEwMTNmNS01Y2I2LTRlOTEtOTQwMC1jZmVhMjM2Y2YwNmQifQ?api-version=2022-04-07-preview", + "Headers" : { + "User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.15; Mac OS X; 12.5)", + "x-ms-client-request-id" : "ac2a5cf5-3a14-4998-be02-bdec8c1d4e94" + }, + "Response" : { + "X-Cache" : "CONFIG_NOCACHE", + "content-length" : "58", + "retry-after" : "0", + "X-Azure-Ref" : "0CfLzYgAAAAAN5EWdKxF/S5YtHv49dFaXV1NURURHRTA4MTAAOWZjN2I1MTktYThjYy00Zjg5LTkzNWUtYzkxNDhhZTA5ZTgx", + "StatusCode" : "404", + "X-Microsoft-Skype-Chain-ID" : "1584f947-7aca-412f-96ea-f696ed2dc9e6", + "Body" : "{\"error\":{\"code\":\"8522\",\"message\":\"Recording not found.\"}}", + "x-ms-client-request-id" : "ac2a5cf5-3a14-4998-be02-bdec8c1d4e94", + "Date" : "Wed, 10 Aug 2022 17:59:37 GMT", + "Content-Type" : "application/json; charset=utf-8" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording401Async[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording401Async[1].json new file mode 100644 index 0000000000000..37016f5526520 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording401Async[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://storage.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "00171fd8-e31d-4b8d-86a6-936e8cc456ea" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "401", + "Date" : "Tue, 28 Sep 2021 23:33:55 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording404Async[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording404Async[1].json new file mode 100644 index 0000000000000..325c5a267254b --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecording404Async[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "729b8f2a-093a-455a-b937-2d8976f2673e" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "404", + "Date" : "Tue, 28 Sep 2021 23:31:51 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithConnectionStringAsyncClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithConnectionStringAsyncClient[1].json new file mode 100644 index 0000000000000..93780d4acf714 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithConnectionStringAsyncClient[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "e545559d-d1d8-4439-ab2e-97d4741af52b" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Tue, 19 Oct 2021 23:01:36 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithTokenCredentialAsyncClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithTokenCredentialAsyncClient[1].json new file mode 100644 index 0000000000000..93780d4acf714 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteAsyncLiveTests.deleteRecordingWithTokenCredentialAsyncClient[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "e545559d-d1d8-4439-ab2e-97d4741af52b" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Tue, 19 Oct 2021 23:01:36 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording401[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording401[1].json new file mode 100644 index 0000000000000..572a9125af8ec --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording401[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "79a06e02-32f1-4c79-9d07-36313d4ae318" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "401", + "Date" : "Tue, 28 Sep 2021 23:44:28 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording404[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording404[1].json new file mode 100644 index 0000000000000..06682b897f6a0 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecording404[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "21368ecd-59ee-49c4-a0af-f22511335e89" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "404", + "Date" : "Tue, 28 Sep 2021 23:44:28 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithConnectionStringClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithConnectionStringClient[1].json new file mode 100644 index 0000000000000..93780d4acf714 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithConnectionStringClient[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "e545559d-d1d8-4439-ab2e-97d4741af52b" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Tue, 19 Oct 2021 23:01:36 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithTokenCredentialClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithTokenCredentialClient[1].json new file mode 100644 index 0000000000000..93780d4acf714 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DeleteLiveTests.deleteRecordingWithTokenCredentialClient[1].json @@ -0,0 +1,20 @@ +{ + "networkCallRecords" : [ { + "Method" : "DELETE", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d10-598a3ea36bfbc27e68c026b17982af22", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.4 (1.8.0_291; Windows 10; 10.0)", + "x-ms-client-request-id" : "e545559d-d1d8-4439-ab2e-97d4741af52b" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "Date" : "Tue, 19 Oct 2021 23:01:36 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadContent404Async[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadContent404Async[1].json new file mode 100644 index 0000000000000..f5acfb4257f47 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadContent404Async[1].json @@ -0,0 +1,19 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141d/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "404", + "Date" : "Thu, 03 Jun 2021 00:22:03 GMT" + }, + "Exception" : null + }], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataRetryingAsync[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataRetryingAsync[1].json new file mode 100644 index 0000000000000..ad02b5a4d4bba --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataRetryingAsync[1].json @@ -0,0 +1,39 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "416", + "Date" : "Thu, 03 Jun 2021 00:22:03 GMT" + }, + "Exception" : null + }, + { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithConnectionStringAsyncClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithConnectionStringAsyncClient[1].json new file mode 100644 index 0000000000000..bf579406f6fb3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithConnectionStringAsyncClient[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithRedirectAsync[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithRedirectAsync[1].json new file mode 100644 index 0000000000000..94c74352116b9 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithRedirectAsync[1].json @@ -0,0 +1,41 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.3 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "302", + "Body" : "", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Location": "https://REDACTED.as.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata" + }, + "Exception" : null + },{ + "Method" : "GET", + "Uri" : "https://REDACTED.as.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.3 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithTokenCredentialAsyncClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithTokenCredentialAsyncClient[1].json new file mode 100644 index 0000000000000..bf579406f6fb3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadMetadataWithTokenCredentialAsyncClient[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileAsync[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileAsync[1].json new file mode 100644 index 0000000000000..91c843e728526 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileAsync[1].json @@ -0,0 +1,43 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "439", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-438/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogIC", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + }, + { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "438", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 439-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "AgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileRetryingAsync[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileRetryingAsync[1].json new file mode 100644 index 0000000000000..c5e0928df33d3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadToFileRetryingAsync[1].json @@ -0,0 +1,40 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes */957", + "retry-after" : "0", + "StatusCode" : "416", + "Date" : "Thu, 03 Jun 2021 00:22:03 GMT" + }, + "Exception" : null + }, + { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadVideoAsync[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadVideoAsync[1].json new file mode 100644 index 0000000000000..45738f241e328 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentAsyncLiveTests.downloadVideoAsync[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/video", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "89666", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-89665/89666", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "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MCBhbmFseXNlPTA6MCBtZT1kaWEgc3VibWU9MCBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTAgd2VpZ2h0cD0wIGtleWludD00OCBrZXlpbnRfbWluPTQgc2NlbmVjdXQ9MCBpbnRyYV9yZWZyZXNoPTAgcmM9YWJyIG1idHJlZT0wIGJpdHJhdGU9MTAwMCByYXRldG9sPTEuMCBxY29tcD0wLjYwIHFwbWluPTIwIHFwbWF4PTUxIHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MACAAAAYDmWIhAZImKAARk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5Ouuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu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/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5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UX+O9//x8P9Zs0sWld/xlV1XBl+P31F/xfCi0Xucgwp//T5DQPjXi6pVT0EDT8R1B/kD7UkeGMHB5XllXFr4qxV/+O2J5iPP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P4hcQuIXELiFxC4jxHn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/iFxC4heIXELiFxHn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/hPAHujio/wJqfcl5ypnV198lPbC8v51MkT9/mE//5mwaX8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8J4LNLf+ELt+iXbG/nulJIL18T+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz/yWIb7bfC3zEfjs6f//+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fwn/4cZ8//iPN08KppMfwdu/x8/z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fxHiPP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/Eefz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fwAAAHCNBmuAkuAgP//////////////////////////////////////////////////////////////////////////////////////////////////+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+f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/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/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fz+fz+fz+fz+fz+fz+fg9O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+IXELiF+IXELxC4hc65/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5++LgDCV/Q+blLaAxuE9j9vq7gsNwl34G2A1N2f/efL4j+PweeDk75/CeAC5NgctEfDj9L/AAkyfx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K0v/xRxMEHnJMz3wf/JrqDcf/c1YP7Hwd8EsOuzIX2N+ItZ+nP5AAC0SeoCygAAAHmJBm0BaB71f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+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P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+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/PZwARggBwEYIAcAAAAIQZpgagAP8MAAAAAIQZqAagAP8MAAAAAIQZqgagAP8MAAAAAIQZrAagAP8MAAAAAIQZrgagAP8MAAAAAIQZsAagAP8MAAAAAIQZsgagAP8MAAABpnQZtAageicUAAtifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4ng9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz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/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fwngAWIRMND7Rvcsfse+v8ABxMKQ2/4hrUsJ4PQMoAkd0ii7f4OoMBLABpQILNObl1cXif9gTyxFpADwOigIv/8Bc1IAAQAgAwmE5/IqsT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp/CeAAk02mk02mv4ADmNlLEqJXrrn8p/D/Ck0AVgeVl6GqjgDtLffyAB3uAAAG8J48oAb4ria+toAb38HgAG54ABueAAbigAG4oABuKAAbigAG4oABuKAAbigAG44A7P/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8R5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/ARggBwEYIAc=", + "Date" : "Thu, 03 Jun 2021 00:33:58 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContent404[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContent404[1].json new file mode 100644 index 0000000000000..e2e9ab0246e8c --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContent404[1].json @@ -0,0 +1,19 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141d/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "0", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "404", + "Date" : "Thu, 03 Jun 2021 00:22:03 GMT" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentStreamFailure[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentStreamFailure[1].json new file mode 100644 index 0000000000000..ecbbf0fa831d7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentStreamFailure[1].json @@ -0,0 +1,22 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "retry-after" : "0", + "StatusCode" : "200", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + }], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentWrongUrl[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentWrongUrl[1].json new file mode 100644 index 0000000000000..6b9e994a3c258 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadContentWrongUrl[1].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithConnectionStringClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithConnectionStringClient[1].json new file mode 100644 index 0000000000000..bf579406f6fb3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithConnectionStringClient[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithTokenCredentialClient[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithTokenCredentialClient[1].json new file mode 100644 index 0000000000000..bf579406f6fb3 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadMetadataWithTokenCredentialClient[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/acsmetadata", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "957", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-956/957", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "ew0KICAicmVzb3VyY2VJZCI6ICI2MzFmYThkOC1hYWI1LTRhYzUtOGUxNS0yNjFhYTI1OTA3NTAiLA0KICAiY2FsbElkIjogImEzMjdhOGU0LTRjMjQtNGM4NC05ZmUyLTA5ZmZlNjIzYzg1OCIsDQogICJjaHVua0RvY3VtZW50SWQiOiAiMC1ldXMtZDItM2NjYTIxNzU4OTFmMjFjNmM5YTU5NzVhMTJjMDE0MWMiLA0KICAiY2h1bmtJbmRleCI6IDAsDQogICJjaHVua1N0YXJ0VGltZSI6ICIyMDIxLTA2LTAyVDIxOjQ1OjQxLjY0OTQyMjRaIiwNCiAgImNodW5rRHVyYXRpb24iOiA1NTgwLjAsDQogICJwYXVzZVJlc3VtZUludGVydmFscyI6IFtdLA0KICAicmVjb3JkaW5nSW5mbyI6IHsNCiAgICAiY29udGVudFR5cGUiOiAibWl4ZWQiLA0KICAgICJjaGFubmVsVHlwZSI6ICJhdWRpb1ZpZGVvIiwNCiAgICAiZm9ybWF0IjogIm1wNCIsDQogICAgImF1ZGlvQ29uZmlndXJhdGlvbiI6IHsNCiAgICAgICJzYW1wbGVSYXRlIjogMTYwMDAsDQogICAgICAiYml0UmF0ZSI6IDEyODAwMCwNCiAgICAgICJjaGFubmVscyI6IDENCiAgICB9LA0KICAgICJ2aWRlb0NvbmZpZ3VyYXRpb24iOiB7DQogICAgICAibG9uZ2VyU2lkZUxlbmd0aCI6IDE5MjAsDQogICAgICAic2hvcnRlclNpZGVMZW5ndGgiOiAxMDgwLA0KICAgICAgImZyYW1lcmF0ZSI6IDgsDQogICAgICAiYml0UmF0ZSI6IDEwMDAwMDANCiAgICB9DQogIH0sDQogICJwYXJ0aWNpcGFudHMiOiBbDQogICAgew0KICAgICAgInBhcnRpY2lwYW50SWQiOiAiODphY3M6NjMxZmE4ZDgtYWFiNS00YWM1LThlMTUtMjYxYWEyNTkwNzUwXzAwMDAwMDBhLTZlOGItYjMzYy1kZWZkLThiM2EwZDAwNTFjYiINCiAgICB9LA0KICAgIHsNCiAgICAgICJwYXJ0aWNpcGFudElkIjogIjg6YWNzOjYzMWZhOGQ4LWFhYjUtNGFjNS04ZTE1LTI2MWFhMjU5MDc1MF8wMDAwMDAwYS02ZThiLWNhMTctZGVmZC04YjNhMGQwMDUxY2QiDQogICAgfQ0KICBdDQp9", + "Date" : "Thu, 03 Jun 2021 00:07:30 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadVideo[1].json b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadVideo[1].json new file mode 100644 index 0000000000000..45738f241e328 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/src/test/resources/session-records/DownloadContentLiveTests.downloadVideo[1].json @@ -0,0 +1,23 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.asm.skype.com/v1/objects/0-eus-d2-3cca2175891f21c6c9a5975a12c0141c/content/video", + "Headers" : { + "User-Agent" : "azsdk-java-azure-communication-callautomation/1.0.0-beta.1 (11.0.11; Windows 10; 10.0)" + }, + "Response" : { + "content-length" : "89666", + "Strict-Transport-Security" : "max-age=31536000; includeSubDomains", + "Cache-Control" : "no-cache, max-age=0, s-maxage=0, private", + "Server" : "Microsoft-HTTPAPI/2.0", + "Content-Range" : "bytes 0-89665/89666", + "retry-after" : "0", + "StatusCode" : "206", + "Body" : "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MCBhbmFseXNlPTA6MCBtZT1kaWEgc3VibWU9MCBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTAgd2VpZ2h0cD0wIGtleWludD00OCBrZXlpbnRfbWluPTQgc2NlbmVjdXQ9MCBpbnRyYV9yZWZyZXNoPTAgcmM9YWJyIG1idHJlZT0wIGJpdHJhdGU9MTAwMCByYXRldG9sPTEuMCBxY29tcD0wLjYwIHFwbWluPTIwIHFwbWF4PTUxIHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MACAAAAYDmWIhAZImKAARk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5Ouuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu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/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5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UX+O9//x8P9Zs0sWld/xlV1XBl+P31F/xfCi0Xucgwp//T5DQPjXi6pVT0EDT8R1B/kD7UkeGMHB5XllXFr4qxV/+O2J5iPP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P4hcQuIXELiFxC4jxHn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/iFxC4heIXELiFxHn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/hPAHujio/wJqfcl5ypnV198lPbC8v51MkT9/mE//5mwaX8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8J4LNLf+ELt+iXbG/nulJIL18T+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz/yWIb7bfC3zEfjs6f//+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fwn/4cZ8//iPN08KppMfwdu/x8/z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fxHiPP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/Eefz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fwAAAHCNBmuAkuAgP//////////////////////////////////////////////////////////////////////////////////////////////////+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+f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/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/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fz+fz+fz+fz+fz+fz+fg9O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+IXELiF+IXELxC4hc65/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D075/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5++LgDCV/Q+blLaAxuE9j9vq7gsNwl34G2A1N2f/efL4j+PweeDk75/CeAC5NgctEfDj9L/AAkyfx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K0v/xRxMEHnJMz3wf/JrqDcf/c1YP7Hwd8EsOuzIX2N+ItZ+nP5AAC0SeoCygAAAHmJBm0BaB71f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q/1f6v9X+r/V/q8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8O8bVVVVVcCP+fpnAfhsaPxtlDWfXC2L/4yqqqqqkVs3Y8QG13Dad/Fz4AjesDYX/+WRUD1/jaqqqqqojfIpwT6PdKa6CvBu9/l4lej/vR4cO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+E///wBgerzt4R06fsfHwM4SYp5QwSHj8FEiux8hQXwTfAiyed58FFQicEWeAgRZj5DufBRgNJ6STBDJ8YWE3/+AIv7p3H/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/Pw3xlVVVVQEjdr16xoAASH8/yjl7yLT7vwUx4Lra4Qbl4BI6AHWhB6v8YeH76+zrnX6t8E9AbBjQCZrx1v8PpIm+NlIlI8G0AAlI2kWAQ6t5XgQ+sAAJTlwBjQPDhPhtIj/DZ3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz/wj4+6dEHItyG0/nXcPtP/hWwCUVSwZo3cfLJVWe56kOOrL/PabTb/89ptNv/rb6++CegKV5QAhI7rnOLJ5ByC+EKBoGtCvAaGK3cMwHAZCKBoZf5BEoTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4a4Kaqqx1EATv/X+fQlMUGgACVhZi+rfX2fz+fzr9Su+CLIG3nvkV8IUMH4NrA9oEXVqgVesBE7yhBMNHfP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/4R2MPoIpj42KpEmz3pP/ghjUH/b6tn8/nXP/UrvqRXwpD27HdYEJaMtm9ddbAgW61AB9bAwrgp6zvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/DPG1VVV1HgQVVVRouk6FyIT54bkpY6k0K3f+GZrx9t/7V/f/9Y2d8/n8/n8/n/hrDCeA4tdjXf/C2KPACNMwbVAl6FZsrlo0l/hk75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/4X8IHBFR+avpb9caOZY309/+CGHId1/2+ubO+fz+fz+fz/wRYkal48fFrvh3xKYID6qHkLcqBQ3hhUe7P/875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+GeMjKCDUoHAABznqCYpgk6HwLggCRXj/9+CYpgmKYKN/Z/P/Dmc/GwTN4R+W/w/jIQFaHA+h8qVPY6OAFYXDf6UinldH/jcdenUhAXQK4wXD1or1geVwPArwuKmM8RG1X/q2d8/9W+P0sPl8bjIOG15yauPmWbPeoMnfP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P/GyKUBkUrAMJuw+NgtFMEEmD8x6wM0ERTBMUwSjOv/9bZ1z/w5nPxsEzeEflv8bU4wxoUFBlCWEHd9D4eU6HyUcAK4u/n0b3For/8bNExbT7ux9Nx8WyWHym7A3XnC4sg0W3J/4I70NKi1u2fz+f+HrEtD4xUSeLvokdoolAIRWDVRSsb1/zvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Z42auFXNUPGLVDFMEoQQRO1QZhqhimCYpgtofFc/8/n8/8EkgRhFh8y9fC04QtYQ2sIbWA1Jy1htHHLP/hfmDj75YvIvCbE5NocNVX+CbjcA9gPCHhUuzvn8/8NaJC8pFeMwfsNFc/+WGuz1Cfhg75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P/BJlYmx/q2fz+f+KmPS2qAagi2fAf+FoQuD+SDcvBuXgw1JzBtY45Z/8L9QDQbGIwmJticm0OGqr/UX2d8/n/rG+COHelvlfP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/Pwxx9V1CRw7x02D6oQK4MFH8/n/gi4+Uc1xfuFTvh7Vw+WrYGBd/HxQTfBmCjh5vzmTpbAZ5r/w7zJwzBUigkB3Sxmc0CHmIZ8qztIbX+GbPMHD8zzWS1+fz+f+rfGWBdRoACyqquo4cyqqoYO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz/wT7AcbOZoxPKikyf6zZ3z+f+CLgTPQ2nzdL9wQb4e1cPlk0GBdj88eFCR2hn5Rw83OczloyVa/8byE+M/KoWyAqWQ/6BDzEM6WFS+o92kNr/DMaIuYYduPNZLX5/P5/OvwTcbPWjd7rhNb5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+GOCfYo4Lg1RU3KzFnfP5/4YsDDUEWRn4Yh8tNuB3WkXwgouuXS78QuIXEL8MdmGkPlBK2Bs/oH5WYXHPQ/nfP5/4UpLFKGXFlVVUS8mUjEnWqut1kKGDvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/8E+ik5mjhy+4QZERvnfnfP/DFgYagi0+VDEPlptwO60i+EFrl0u/ELiFxC/DFVZhpD5QStgbP6B+VmFxz0P53z+f+CauE1sCDHQQmoMt8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/DPGyDFCBM2B2D4IilCYpgjLDP1BMBbwixTBMUwR9Hr+5T+fz/w9gRPw/yvCCM2v1tf8Mwfh8cGpXG4SIyH/F46OBEh8v738N8PIlojeY+MbhXL/89vBX9/gj8IXg674ZqJ3/fOCPwE2Lyim2bqnV0kTx/zvn/hfCfjd3YB4YTQYMCnQ3KbDdco7c+GTvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/9X+FJBhWqqqjhbyiQ+VLF0FWVIbP5/4/BC8OlfFft8/+NiwhDwfy85hLy3HRwIkPl58N8PIlojeY+MbhXL/8EnIDh4w3xfYRBC9LqQIjQ0fpeGcJ3/2gI/YEHQGUU2zdU6ukieP+d8/8E+EzFmVIFHQMMxCjBg2uxfBN2XuXuX7L3z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8M8PSqGAAYyCFgkJFD4GC0IPIirxDhfNP53z/1b4V42CvqoVgex0VtqDYIZX/39FKZofiPNmOgkKA4D4V9fvDsXeYcf0vaKs9P4jL5/P/GeH0upAWkQtPoIwBXAcO+4ZO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+f+HsE4IAoSJF3wSEqD5BLxJwTEBjheTjQ0+8Q/53z/1b4JeNgr6Nri8sG+CHfuEBYeHwS9prgnzAy4McH/DF8EtdSSd+w7F3wB9vq2d8/8O+BI9b5jRh+o/eg7U67gO8ZC5cgrrMY1NT/1fP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/PwzycCXePU8+H/x8/zFxupYEsemKokvHtGe6Ca+fz/1b6t9W+rZ/P/C98PJ3YZgG+AM0clx2xzrhh/3HTLgat8/hk75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/57473/wpWCB4aIvVUUOjUgw7QA8gICuGd8/9W+rZ1zrnXP/GXd3e4IXh3+XBP4BbgJdPZgLqqwN+B/wzeDeR/a/xjv/OTn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4a5L5sDjg4/D/Ejef/l/HyFK52a/a+0IBDSCd+5rG/fO+fz+fz+f+CDxuIzgAI8DhD6LkaBrANVtx7zL/x0waHQZmHvQGDV3BCbedjb/yHfP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P53z+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+f+CKNFv4yDBf43gSfrDsPz3d3twyhBBaPStyBAEwYB05eN++d8/n8/n8/8EHjh3jEab4O9YYQ3TRdo1W16497/wrQFpBUAwvfu/3hbrvh/1fP5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+HONh6GhJV92R9LPzqxiKCE/30cP4dqVIGkf/xtV6rmzjrSQfC5eauGYPlxeBux/+FKrqvh1LXWvnED8Bly9vgoqsBNvgNLZVzPlcV5vjarqvIZbmHomCqEF9eB9L/jePiyaMEIdtIDuReKg07RytBsGYguIJGh6NyT/mO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n/gizLv8u/xtJC2EZ9np/kCwwFOq5RIcDXlKkNv/lmzjdUuAa/wUcOznIkrzpbXwHG+GOgYegi92B2f2Xc+n3/BRU4eYQ4YQPtUi/h8P8gIAhmGyGDCjfzhgnI8GPm1v/wpXgYA6kGg6D1IJSDQdBvIvI7yLyO/1/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P/V/q/1f6v9Xzr9Xz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4Jzvn8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n875/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+Cc75/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/O+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fgnO+fz+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/PZwARggBwEYIAcAAAAIQZpgagAP8MAAAAAIQZqAagAP8MAAAAAIQZqgagAP8MAAAAAIQZrAagAP8MAAAAAIQZrgagAP8MAAAAAIQZsAagAP8MAAAAAIQZsgagAP8MAAABpnQZtAageicUAAtifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4nxPifE+J8T4ng9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz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/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fg9P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n8/n4PT+fwngAWIRMND7Rvcsfse+v8ABxMKQ2/4hrUsJ4PQMoAkd0ii7f4OoMBLABpQILNObl1cXif9gTyxFpADwOigIv/8Bc1IAAQAgAwmE5/IqsT+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz+fz8Hp/CeAAk02mk02mv4ADmNlLEqJXrrn8p/D/Ck0AVgeVl6GqjgDtLffyAB3uAAAG8J48oAb4ria+toAb38HgAG54ABueAAbigAG4oABuKAAbigAG4oABuKAAbigAG44A7P/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5+D0/n8R5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/P5/ARggBwEYIAc=", + "Date" : "Thu, 03 Jun 2021 00:33:58 GMT", + "Content-Type" : "application/octet-stream" + }, + "Exception" : null + } ], + "variables" : [ ] +} diff --git a/sdk/communication/azure-communication-callautomation/swagger/README.md b/sdk/communication/azure-communication-callautomation/swagger/README.md new file mode 100644 index 0000000000000..65614bfedda8f --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/swagger/README.md @@ -0,0 +1,278 @@ +# Azure Communication Calling Service client library for Java + +> see https://aka.ms/autorest +## Getting Started + +To build the SDK for Server Calling Client, simply Install AutoRest and in this folder, run: + +### Setup +```ps +Fork and clone https://github.com/Azure/autorest.java +git checkout main +git submodule update --init --recursive +mvn package -Dlocal +npm install +npm install -g autorest +``` + +### Generation + +There is one swagger for Calling management APIs. + +```ps +cd +autorest README.md --java --v4 --use=@autorest/java@4.0.20 --use=@autorest/modelerfour@4.15.442 +``` + +## Update generated files for server calling service +To update generated files for calling service, run the following command + +> autorest README.md --java --v4 --use=@autorest/java@4.0.20 --use=@autorest/modelerfour@4.15.442 + +### Code generation settings +``` yaml +tag: package-2022-04-07-preview +require: + - https://github.com/richardcho-msft/azure-rest-api-specs/blob/dev-communication-CallingServer-2022-04-07-preview/specification/communication/data-plane/CallingServer/readme.md +java: true +output-folder: ..\ +license-header: MICROSOFT_MIT_SMALL +namespace: com.azure.communication.callautomation +custom-types: ToneValue,OperationStatus,CallRecordingState,CallConnectionState,EventSubscriptionType,MediaType,RecordingChannelType,RecordingContentType,RecordingFormatType +custom-types-subpackage: models +generate-client-as-impl: true +service-interface-as-public: true +models-subpackage: implementation.models +sync-methods: all +add-context-parameter: true +context-client-method-parameter: true +title: Azure Communication Call Automation Service +directive: +- rename-model: + from: AcsCallParticipant + to: AcsCallParticipantInternal +- rename-model: + from: AddParticipantsRequest + to: AddParticipantsRequestInternal +- rename-model: + from: AddParticipantsResponse + to: AddParticipantsResponseInternal +- rename-model: + from: CallConnectionProperties + to: CallConnectionPropertiesInternal +- rename-model: + from: CallingOperationResultDetails + to: CallingOperationResultDetailsInternal +- rename-model: + from: CallingOperationStatus + to: CallingOperationStatusInternal +- rename-model: + from: CallSource + to: CallSourceInternal +- rename-model: + from: CommunicationCloudEnvironmentModel + to: CommunicationCloudEnvironmentInternal +- rename-model: + from: GetParticipantsResponse + to: GetParticipantsResponseInternal +- rename-model: + from: RemoveParticipantsRequest + to: RemoveParticipantsRequestInternal +- rename-model: + from: RemoveParticipantsResponse + to: RemoveParticipantsResponseInternal +- rename-model: + from: TransferCallResponse + to: TransferCallResponseInternal +- rename-model: + from: TransferToParticipantRequest + to: TransferToParticipantRequestInternal +- rename-model: + from: CreateCallRequest + to: CreateCallRequestInternal +- rename-model: + from: AnswerCallRequest + to: AnswerCallRequestInternal +- rename-model: + from: RedirectCallRequest + to: RedirectCallRequestInternal +- rename-model: + from: RejectCallRequest + to: RejectCallRequestInternal +- rename-model: + from: CallLocator + to: CallLocatorInternal +- rename-model: + from: RecordingIdResponse + to: RecordingIdResponseInternal +- rename-model: + from: RecordingStateResponse + to: RecordingStateResponseInternal +- rename-model: + from: PlayResponse + to: PlayResponseInternal +- rename-model: + from: PlaySource + to: PlaySourceInternal +- rename-model: + from: FileSource + to: FileSourceInternal +- rename-model: + from: PlayOptions + to: PlayOptionsInternal +- rename-model: + from: StartCallRecordingRequest + to: StartCallRecordingRequestInternal +- rename-model: + from: ChannelAffinity + to: ChannelAffinityInternal +- rename-model: + from: DtmfConfigurations + to: DtmfConfigurationsInternal +- rename-model: + from: RecognizeConfigurations + to: RecognizeConfigurationsInternal +- rename-model: + from: MediaStreamingConfiguration + to: MediaStreamingConfigurationInternal + +# Remove models +- remove-model: AddParticipantsFailedEvent +- remove-model: AddParticipantsSucceededEvent +- remove-model: CallConnectedEvent +- remove-model: CallDisconnectedEvent +- remove-model: CallTransferAcceptedEvent +- remove-model: CallTransferFailedEvent +- remove-model: ParticipantsUpdatedEvent +- remove-model: RecordingStateChangedEvent +- remove-model: PlayCompleted +- remove-model: PlayFailed +- remove-model: ResultInfo +``` + +### Rename RecordingChannelType to RecordingChannelInternal +``` yaml +directive: + - from: swagger-document + where: $.definitions.RecordingChannelType + transform: > + $["x-ms-enum"].name = "RecordingChannelInternal"; +``` + +### Rename RecordingContentType to RecordingContentInternal +``` yaml +directive: + - from: swagger-document + where: $.definitions.RecordingContentType + transform: > + $["x-ms-enum"].name = "RecordingContentInternal"; +``` + +### Rename RecordingFormatType to RecordingFormatInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.RecordingFormatType["x-ms-enum"] + transform: > + $.name = "RecordingFormatInternal"; +``` + +### Rename RecordingState to RecordingStateInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.RecordingState["x-ms-enum"] + transform: > + $.name = "RecordingStateInternal"; +``` + +### Rename PlaySourceType to PlaySourceTypeInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.PlaySourceType["x-ms-enum"] + transform: > + $.name = "PlaySourceTypeInternal"; +``` + +### Rename CallLocatorKind to CallLocatorKindInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.CallLocatorKind["x-ms-enum"] + transform: > + $.name = "CallLocatorKindInternal"; +``` + +### Rename CallConnectionStateModel to CallConnectionStateModelInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.CallConnectionStateModel["x-ms-enum"] + transform: > + $.name = "CallConnectionStateModelInternal"; +``` + +### Rename AcsEventType to AcsEventTypeInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.AcsEventType["x-ms-enum"] + transform: > + $.name = "AcsEventTypeInternal"; +``` + +### Rename CallRejectReason to CallRejectReasonInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.CallRejectReason["x-ms-enum"] + transform: > + $.name = "CallRejectReasonInternal"; +``` + +### Rename StopTones to StopTonesInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.StopTones["x-ms-enum"] + transform: > + $.name = "StopTonesInternal"; +``` + + +### Rename RecognizeInputType to RecognizeInputTypeInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.RecognizeInputType["x-ms-enum"] + transform: > + $.name = "RecognizeInputTypeInternal"; +``` + +### Rename MediaStreamingAudioChannelType to MediaStreamingAudioChannelTypeInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.MediaStreamingAudioChannelType["x-ms-enum"] + transform: > + $.name = "MediaStreamingAudioChannelTypeInternal"; +``` + +### Rename MediaStreamingContentType to MediaStreamingContentTypeInternal +``` yaml +directive: +- from: swagger-document + where: $.definitions.MediaStreamingContentType["x-ms-enum"] + transform: > + $.name = "MediaStreamingContentTypeInternal"; +``` + +### Rename MediaStreamingTransportType to MediaStreamingTransportType +``` yaml +directive: +- from: swagger-document + where: $.definitions.MediaStreamingTransportType["x-ms-enum"] + transform: > + $.name = "MediaStreamingTransportTypeInternal"; +``` diff --git a/sdk/communication/azure-communication-callautomation/tests.yml b/sdk/communication/azure-communication-callautomation/tests.yml new file mode 100644 index 0000000000000..02949212d53a7 --- /dev/null +++ b/sdk/communication/azure-communication-callautomation/tests.yml @@ -0,0 +1,9 @@ +trigger: none + +stages: +- template: /sdk/communication/communication-tests-template.yml + parameters: + PackageName: azure-communication-callautomation + SafeName: azurecommunicationcallautomation + Clouds: 'Public' + TestMode: 'LIVE' diff --git a/sdk/communication/azure-communication-common/src/main/java/module-info.java b/sdk/communication/azure-communication-common/src/main/java/module-info.java index 954e7ed80d3f9..796923f4e6e89 100644 --- a/sdk/communication/azure-communication-common/src/main/java/module-info.java +++ b/sdk/communication/azure-communication-common/src/main/java/module-info.java @@ -19,6 +19,7 @@ com.azure.communication.chat, com.azure.communication.rooms, com.azure.communication.callingserver, + com.azure.communication.callautomation, com.azure.communication.networktraversal, com.azure.communication.jobrouter; } diff --git a/sdk/communication/pom.xml b/sdk/communication/pom.xml index 9bf14d8fc346f..61250bad30b3e 100644 --- a/sdk/communication/pom.xml +++ b/sdk/communication/pom.xml @@ -11,6 +11,7 @@ azure-communication-callingserver + azure-communication-callautomation azure-communication-chat azure-communication-common azure-communication-email