diff --git a/ServerRecording/README.MD b/ServerRecording/README.MD index 4c2322d..dcad3e6 100644 --- a/ServerRecording/README.MD +++ b/ServerRecording/README.MD @@ -6,83 +6,96 @@ products: - azure - azure-communication-services --- - -[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure-Samples%2Fcommunication-services-web-calling-hero%2Fmain%2Fdeploy%2Fazuredeploy.json) - # Recording APIs Sample This is a sample application to show how the Azure Communication Services server calling SDK can be used to build a call recording feature. -Its a Java web application powered by Spring boot to connect this application with Azure Communication Services. +It's a Java web application powered by Spring Boot to connect this application with Azure Communication Services. ## Prerequisites -- Create an Azure account with an active subscription. For details, see [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F) +- [Visual Studio Code](https://code.visualstudio.com/download) - [Java Development Kit (JDK) version 11 or above](https://docs.microsoft.com/azure/developer/java/fundamentals/java-jdk-install) - [Apache Maven](https://maven.apache.org/download.cgi) -- [Visual Studio code (2019 and above)](https://code.visualstudio.com/download) -- [Spring boot framework v- 2.5.0](https://spring.io/projects/spring-boot) -- Create an Azure Communication Services resource. For details, see [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource **connection string** for this quickstart. -- Create a webhook and subscribe to the recording events [Create webhook](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/download-recording-file-sample) +- [Spring Boot framework v- 2.5.0](https://spring.io/projects/spring-boot) +- An Azure account with an active subscription. For details, see here to [create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). +- [Create container registry](https://docs.microsoft.com/en-us/azure/developer/java/spring-framework/deploy-spring-boot-java-app-on-linux#create-an-azure-container-registry-to-use-as-a-private-docker-registry) +- [Create an Azure Communication Resource](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource). You'll need to record your resource\'s **connection string** for this quickstart. +- [Create a webhook](https://docs.microsoft.com/azure/communication-services/quickstarts/voice-video-calling/download-recording-file-sample) and subscribe to the recording events. ## Code structure - -- ./ServerRecording/src/main/java/com/acsrecording/api/controllers : Server app core logics to make Api calls that connects with the Azure Communication Services Web Calling SDK -- ./ServerRecording/pom.xml : XML file which contains project and package configurations -- ./ServerRecording/src/main/resources/config.properties : config file which contains user level configurations +- ./src/main/java/com/acsrecording/api/Controller : Server app core logic to make Api calls that connect with the Azure Communication Services Web Calling SDK +- ./pom.xml : XML file which contains project and package configurations +- ./src/main/resources/config.properties : config file which contains user level configurations ## Before running the sample for the first time 1. Get the `Connection String` from the Azure portal. For more information on connection strings, see [Create an Azure Communication Resources](https://docs.microsoft.com/azure/communication-services/quickstarts/create-communication-resource) -2. Once you get the config keys add the keys to the **resources/config.properties** file found under the ./ServerRecording/src/main/resources folder. - - Input your connection string in the variable: `Connectionstring` - - Input your blob storage connectionString string in the variable: `BlobStorageConnectionString` +2. Once you get the config keys, add the keys to the **resources/config.properties** file found under the ./src/main/resources folder. + - Input your ACS connection string in the variable: `ACSConnectionString` + - Input your blob storage connection string in the variable: `BlobStorageConnectionString` - Input blob container name for recorded media in the variable `ContainerName` - Input recording callback url for start recording api in the variable `CallbackUri` ## Locally deploying the sample app -1. Build java code : mvn clean install +1. Build java code : `mvn clean install` -2. Run app locally : mvn spring-boot:run +2. Run app locally : `mvn spring-boot:run` -3. Use postman or any debugging tool and open url - http://localhost:8080 +3. Use [Postman](https://www.postman.com/) or any debugging tool and open url - http://localhost:8080 -### Troubleshooting +## Troubleshooting -1. Solution doesn\'t build, it throws errors during NPM installation/build +1. Solution doesn\'t build / It throws errors during MVN installation/build - - Check if all the config keys are present + - Check if all the config keys are present, and rebuild with `mvn package`, then `mvn clean install` - - Run mvn package, then mvn clean install + - After installing the JDK and building, if you see "invalid target release: 11", verify that your JAVA_HOME variable does in fact point to your Java 11 installation (as opposed to a previous installation). ## Publish to Azure -1. Build java code using : mvn clean install +1. Build java code : -2. Run app locally using : mvn spring-boot:run + ``` + mvn clean install + ``` + +1. Run app locally using : -3. Create container registry - follow steps in link - https://docs.microsoft.com/azure/developer/java/spring-framework/deploy-spring-boot-java-app-on-linux + ``` + mvn spring-boot:run + ``` -4. Login to Azure : +1. Login to Azure : ```azurecli - using az login + az login ``` -5. Login to Azure Container Registry : +1. Login to your Azure Container Registry : ```azurecli az acr login --name ``` -6. Build docker image using : mvn compile jib:dockerBuild +1. Build docker image using : + + ``` + mvn compile jib:dockerBuild + ``` -7. Run image locally to validate using : docker run -it --rm -p 8080:8080 .azurecr.io/ +1. Run image locally to validate using : + ``` + docker run -it --rm -p 8080:8080 {registryName}.azurecr.io/{projectNameAndVersion} + ``` -8. Push docker image to ACR using : docker push .azurecr.io/ +1. Push docker image to ACR using : + ``` + docker push {registryName}.azurecr.io/{projectNameAndVersion} + ``` -9.Create web app by following steps in link : https://docs.microsoft.com/azure/developer/java/spring-framework/deploy-spring-boot-java-app-on-linux +1. Create web app by following steps in link : https://docs.microsoft.com/en-us/azure/developer/java/spring-framework/deploy-spring-boot-java-app-on-linux#create-a-web-app-on-linux-on-azure-app-service-using-your-container-image ## Additional Reading -- [Azure Communication Calling SDK](https://docs.microsoft.com/azure/communication-services/concepts/voice-video-calling/calling-sdk-features) - To learn more about the calling web sdk \ No newline at end of file +- [Azure Communication Calling SDK](https://docs.microsoft.com/azure/communication-services/concepts/voice-video-calling/calling-sdk-features) - To learn more about the calling web sdk. \ No newline at end of file diff --git a/ServerRecording/src/main/java/com/acsrecording/api/ApiApplication.java b/ServerRecording/src/main/java/com/acsrecording/api/ApiApplication.java index 09776c8..2a488ed 100644 --- a/ServerRecording/src/main/java/com/acsrecording/api/ApiApplication.java +++ b/ServerRecording/src/main/java/com/acsrecording/api/ApiApplication.java @@ -11,5 +11,4 @@ public class ApiApplication { public static void main(String[] args) { SpringApplication.run(ApiApplication.class, args); } - } diff --git a/ServerRecording/src/main/java/com/acsrecording/api/Controller/CallRecordingController.java b/ServerRecording/src/main/java/com/acsrecording/api/Controller/CallRecordingController.java index 6fbc237..f2aab78 100644 --- a/ServerRecording/src/main/java/com/acsrecording/api/Controller/CallRecordingController.java +++ b/ServerRecording/src/main/java/com/acsrecording/api/Controller/CallRecordingController.java @@ -51,7 +51,7 @@ public class CallRecordingController { CallRecordingController() { ConfigurationManager configurationManager = ConfigurationManager.getInstance(); - String connectionString = configurationManager.getAppSettings("Connectionstring"); + String connectionString = configurationManager.getAppSettings("ACSConnectionString"); container = configurationManager.getAppSettings("ContainerName"); recordingStateCallbackUrl = configurationManager.getAppSettings("CallbackUri"); blobStorageConnectionString = configurationManager.getAppSettings("BlobStorageConnectionString"); @@ -73,7 +73,7 @@ public StartCallRecordingResult startRecording(String serverCallId) { var output = response.getValue(); logger.log(Level.INFO, "Start Recording response --> " + getResponse(response) + "\n recording ID: " + response.getValue().getRecordingId()); - if(!recordingDataMap.containsKey(serverCallId)){ + if (!recordingDataMap.containsKey(serverCallId)) { recordingDataMap.put(serverCallId, ""); } recordingDataMap.replace(serverCallId, output.getRecordingId()); @@ -86,8 +86,8 @@ public StartCallRecordingResult startRecording(String serverCallId) { } @GetMapping("/pauseRecording") - public void pauseRecording(String serverCallId, String recordingId){ - if(!Strings.isNullOrEmpty(serverCallId)){ + public void pauseRecording(String serverCallId, String recordingId) { + if (!Strings.isNullOrEmpty(serverCallId)) { if (Strings.isNullOrEmpty(recordingId)) { recordingId = recordingDataMap.get(serverCallId); @@ -106,8 +106,8 @@ public void pauseRecording(String serverCallId, String recordingId){ } @GetMapping("/resumeRecording") - public void resumeRecording(String serverCallId, String recordingId){ - if(!Strings.isNullOrEmpty(serverCallId)){ + public void resumeRecording(String serverCallId, String recordingId) { + if (!Strings.isNullOrEmpty(serverCallId)) { if (Strings.isNullOrEmpty(recordingId)) { recordingId = recordingDataMap.get(serverCallId); @@ -126,8 +126,8 @@ public void resumeRecording(String serverCallId, String recordingId){ } @GetMapping("/stopRecording") - public void stopRecording(String serverCallId, String recordingId){ - if(!Strings.isNullOrEmpty(serverCallId)){ + public void stopRecording(String serverCallId, String recordingId) { + if (!Strings.isNullOrEmpty(serverCallId)) { if (Strings.isNullOrEmpty(recordingId)) { recordingId = recordingDataMap.get(serverCallId); @@ -174,13 +174,13 @@ public CallRecordingState getRecordingState(String serverCallId, String recordin } @PostMapping(value = "/getRecordingFile", consumes = "application/json", produces = "application/json") - public ResponseEntity getRecordingFile (@RequestBody String eventGridEventJsonData){ + public ResponseEntity getRecordingFile (@RequestBody String eventGridEventJsonData) { logger.log(Level.INFO, "Entered getRecordingFile API"); List eventGridEvents = EventGridEvent.fromString(eventGridEventJsonData); - if(eventGridEvents.stream().count() > 0) + if (eventGridEvents.stream().count() > 0) { EventGridEvent eventGridEvent = eventGridEvents.get(0); logger.log(Level.INFO, "Event type is --> " + eventGridEvent.getEventType()); @@ -196,13 +196,13 @@ public ResponseEntity getRecordingFile (@RequestBody String eventGridEventJso responseData.setValidationResponse(subscriptionValidationEvent.getValidationCode()); return new ResponseEntity<>(responseData, HttpStatus.OK); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } - if(eventGridEvent.getEventType().equals(SystemEventNames.COMMUNICATION_RECORDING_FILE_STATUS_UPDATED)){ + if (eventGridEvent.getEventType().equals(SystemEventNames.COMMUNICATION_RECORDING_FILE_STATUS_UPDATED)) { try { AcsRecordingFileStatusUpdatedEventData acsRecordingFileStatusUpdatedEventData = eventData.toObject(AcsRecordingFileStatusUpdatedEventData.class); AcsRecordingChunkInfoProperties recordingChunk = acsRecordingFileStatusUpdatedEventData @@ -228,13 +228,14 @@ public ResponseEntity getRecordingFile (@RequestBody String eventGridEventJso ); return new ResponseEntity<>(true, HttpStatus.OK); - } catch (Exception e){ + } catch (Exception e) { e.printStackTrace(); logger.log(Level.SEVERE, e.getMessage()); return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); } } - else{ + else + { return new ResponseEntity<>(eventGridEvent.getEventType() + " is not handled.", HttpStatus.BAD_REQUEST); } } diff --git a/ServerRecording/src/main/resources/config.properties b/ServerRecording/src/main/resources/config.properties index 523b246..0bc1e36 100644 --- a/ServerRecording/src/main/resources/config.properties +++ b/ServerRecording/src/main/resources/config.properties @@ -1,4 +1,4 @@ -Connectionstring=endpoint=https://REDACTED.communication.azure.com/;accesskey=QWNjZXNzS2V5 +ACSConnectionString=endpoint=https://REDACTED.communication.azure.com/;accesskey=QWNjZXNzS2V5 BlobStorageConnectionString=DefaultEndpointsProtocol=https;AccountName=REDACTED;AccountKey=QWNjZXNzS2V5;EndpointSuffix=core.windows.net ContainerName=acs-recording-container-name CallbackUri=http://localhost:3000/ \ No newline at end of file