In this advanced Real-Time Engagement topic, we show you how the Agora Cloud Recording API can be called to handle the task for Unity applications. You should be familiar with the basic setup of a simple video chat app in Unity. If not, you can follow the tutorial in this blog, which will get you ready in 30 minutes. We further expand the logic to control the clouding recording with a custom server.
- Clone the quick start repo as the base project to work on.
- Fulfill the dependencies on the quick start project, such as getting an Agora App Id.
- Set up a working Amazon S3 Bucket. Be sure you verify that you can upload files to it by scripting.
- Have basic server-side coding knowledge and environment.
We will create a simple client-server system to simulate common usage of the feature. Here are the parts as depicted in figure1:
- Unity App client 1: the commanding client, which controls the start and stop of the video recording
- Unity App client 2: the normal client, which chats with client 1
- App Server: a trusted server that stores secret keys, takes command from client 1 and makes RESTFul API calls to the SD-RTN Backend
- SD-RTN Backend: the Agora network process video that makes magic happen (Software Defined Real Time Network)
- Amazon S3 Bucket: the cloud storage with APIs for the video upload
Note: Theoretically, we can omit the app server from this architecture and put the secret keys and RESTFul API calls directly in the client. But that wouldn’t be the best practice.
This project has three major steps:
- Environment: This involves enabling the feature on your Agora account and setting up client-server and an S3 account.
- Server: The code is written in PHP.
- Client: A Unity application built on the basic video chat project.
First, familiarize yourself with the background description from the documentation page. Follow the steps in the QuickStart section on how to enable the service from your Agora developer account console. You’ll need a customer Id and a customer secret from the console. Adding the setup from the basic video chat project, you should have the following tokens so far:
- App Id: Created with a new project. I chose not to use a certificate for this tutorial.
- App token: Only if you enabled certificate for your App Id.
- Customer Id: Press “Add a secret” to get one (figure 2).
- Customer secret: After getting the customer Id, the console generates a secret token for download.
Amazon S3 Credentials
You need the following information for the clouding recording configuration:
- Bucket name: In my example from figure 3, the name is “agoracdn”.
- Region: Since my bucket is in “us-west-1”, it is mapped to “2” according to this table.
- User access key: Get this from AWS IAM under Users (figure 4).
- User secret key: Get this from AWS IAM under Users.
$ php -S localhost:8000
For more information, such as how to do the same on Windows machines, check the PHP manual page.
The main goal of our server is to separate the necessary credential keys away from the client and relay the RESTful API calls to the Agora SD-RTN back end. The Cloud Recording Quick Start documentation shows the following essential steps for its life cycle:
These four steps are mapped to four PHP scripts running from our test server. They will share the configuration that we gather from the Environment Setup step above.
Here is the code of config.php. You need to fill into your credential tokens in the empty space and set the region number for your Amazon S3 bucket. The script combines the Customer Id and the Customer Secret token into an Authorization Secret (AuthSecret), which will be used throughout the API calls. You should create an integer string for the RecUID (Recorder User Id). This Id is different from the clients’ user Ids.
The Aquire step initializes a Cloud Recording request to the Agora SD-RTN. In return, the RTN provides a resourceId. The channel name is passed from the client in a POST body. As a result, the resourceId is sent to the client. The client should maintain that Id in its memory for the next steps.
After you obtain a resourceId, you can tell the SD-RTN when the recording starts. The SD-RTN sends chunks of video data in .ts format to your S3 bucket. The resourceId and the channel name are passed from the client in a POST body. If the call is successful, you should get back the same resourceId and a sid (Session Id).
It is important to know if a Recording is in session or the Start failed due to an AWS authentication issue. The Query command checks the current status with the stored resourceId and sid. The server responds with the current video name for the file list (m3u8) and other information.
When you decide the recording is done, call Stop to complete the cloud recording session.
Note: If you set up your Agora project with the certificate enabled, you need to add a token field into the CURLOPT_POSTFIELDS in the Acquire, Start, Stop, and Query API calls. Since my project was set up without one, I removed the field from the list.
So far, the server code and configuration are set up. You can test the recording manually before the client code is created. To do so, simply assign the necessary values by hand instead of getting the values from the POST body.
If you are interested in learning more about the RESTful calls, you can use the Agora-RESTful-Service project to test cloud recording on the Postman app. In fact, the scripts and JSON body that I used in the PHP code above are inspired by the Postman app. You can quickly create the corresponding code for your chosen framework and language. See figures 5 and 6.
As discussed in the Architecture section, there are two clients. Client 1 is the commanding client that controls the start and stop of the recording. Client 2 is a normal chat client. The original VideoChat project applies to client 2. We update the project with new features to support the commanding client.
The commanding feature is a good example application for the MVC design pattern. We will write the Unity C# code for the Model, the View and the Controller.
From observation of the returning JSON output from the SD-RTN, we find the following sample structure covers the response body for Acquire, Start, Stop, and Query:
Turning that into C# classes, we have the following implementation:
We will update the Video Chat demo scene to the following:
- Add a Start/Stop button to the lower-left side of the view area. Name it “RecordButton”. Set the text to display “Start”. We modify the text to display “Stop” in the controller logic.
- Add a Query button below the Start/Stop button. Make the RecordButton its parent in the hierarchy.
A CloudRecordController class responds to the button events and encapsulates the networking logic to drive the cloud recording sequence. Here is a top-down outline of the class structure:
- ChannelName: Set by main controller (VideoChat.cs),
- ResourceId: Get from server message,
- SID: Get from server message,
- IsRecording: Indicates if recording is in progress.
HandleStartStop(): Responds to the RecordButton click and toggles between the two states. The RecordButton is visible only after the user joins a channel and it appears as a Start button. When the user taps the Start button, the client sends an Acquire command to the server first. If the Acquire is successful, then Start begins automatically in the response handler to Acquire. The Start button becomes a Stop button. The Stop button stops the recording upon tapping by the user.
HandleQuery(): Responds to the QueryButton click. The output prints to the console.
RestoreRecordState(): Helps to maintain states between two Unity client sessions. If a recording is in progress but the user quits, the Start state is saved in the device’s persistent memory (PlayerPrefs). This function gets called at the Awake step of the hosting object.
The client interacts with the server with the four API calls defined earlier. It is easy to see that there are four API callers and four matching server response handlers for Acquire, Start, Stop, and Query.
The four functions use the same logic flow for the caller and the handler. We use the UnityWebRequest class to package and send the POST request and parse the result using the model we defined for CloudRecordResponseModel. At the end, invoke the callback to the handler to finish the processing. Figure 9 shows an example from the _Start function.
_Start() runs separately from the Main thread in Unity in a coroutine so that the network calls won’t block the execution of the UI display.
The complete code listing for CloudRecordController class:
Now we have the MVC components all defined. Let’s integrate everything. We need a game object to host the CloudRecordController. We simply add that as an extra component to the RecordButton.
First, go back to the Unity Editor and drag the CloudRecordController.cs script to RecordButton. Second, assign the RecordButton and QueryButton to their fields. Third, enter the following URL in the Server URL field:
Your Inspector should look like this:
We update the main controller logic to link to the CloudRecordController.
- Update the AgoraTest.cs script with a new serialized field for CloudRecordingObject (see figure 11).
- In the Start() method, hide the CloudRecordingObject (see figure 11).
3. In the OnJoinChannelSuccessHandler() method, update the code to pass the channel information to CloudRecordController (see figure 12).
4. In the Unity Editor, drag and drop the RecordButton into the CloudRecordingObject field of AgoraTest inside GameController (see figure 13).
Run the project from the Unity Editor, and execute in the following order:
When you are done, head over to your AWS S3 account to check the files. You should find a list of .ts files uploaded. Here is the quick test I just did:
This project is a bit complex, with various depending configurations to set up. Thank you for following my post up to the end. The completed project can be found in our community Github repo.
Want to build Real-Time Engagement apps?
If you have questions, please call us at 408-879-5885. We’d be happy to help you add voice or video chat, streaming, and messaging into your apps.
Stay inspired by accessing all RTE2020 session recordings. Gain access to innovative Real-Time-Engagement content and start innovating today.