diff --git a/CHANGELOG.md b/CHANGELOG.md index 92ad20d..fca60a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.3.2 + +- Added callback for cloud recording destination URL +- Added loading state for cloud recording button +- Update to use new cloud recording schema + ## 1.3.1 - BUG FIX: No longer shows cloud recording by default. Need to enable it with `cloudRecordingEnabled: true` diff --git a/lib/controllers/rtc_buttons.dart b/lib/controllers/rtc_buttons.dart index 4ea557d..2eddecf 100644 --- a/lib/controllers/rtc_buttons.dart +++ b/lib/controllers/rtc_buttons.dart @@ -127,16 +127,29 @@ Future _showRPSystemBroadcastPickerViewIfNeed() async { /// Function to start and stop cloud recording Future toggleCloudRecording({required AgoraClient client}) async { - if (client.sessionController.value.isCloudRecording) { + if (client.sessionController.value.isCloudRecording == + RecordingState.recording) { //stop cloud recording + client.sessionController.value = client.sessionController.value.copyWith( + isCloudRecording: RecordingState.loading, + ); await client.sessionController .stopCloudRecording(connectionData: client.agoraConnectionData); - } else { + client.sessionController.value = client.sessionController.value.copyWith( + isCloudRecording: RecordingState.off, + ); + } else if (client.sessionController.value.isCloudRecording == + RecordingState.off) { //start cloud recording + client.sessionController.value = client.sessionController.value.copyWith( + isCloudRecording: RecordingState.loading, + ); await client.sessionController .startCloudRecording(connectionData: client.agoraConnectionData); + client.sessionController.value = client.sessionController.value.copyWith( + isCloudRecording: RecordingState.recording, + ); + } else { + //do nothing } - - client.sessionController.value = client.sessionController.value.copyWith( - isCloudRecording: !(client.sessionController.value.isCloudRecording)); } diff --git a/lib/controllers/session_controller.dart b/lib/controllers/session_controller.dart index 739a34b..b7096b9 100644 --- a/lib/controllers/session_controller.dart +++ b/lib/controllers/session_controller.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; +import 'dart:io'; import 'package:agora_rtc_engine/agora_rtc_engine.dart'; import 'package:agora_rtm/agora_rtm.dart'; @@ -288,13 +289,17 @@ class SessionController extends ValueNotifier { Future startCloudRecording( {required AgoraConnectionData connectionData}) async { final response = await http.post( - Uri.parse('${connectionData.cloudRecordingUrl}/api/start/call'), - body: {"channel": connectionData.channelName}, + Uri.parse( + '${connectionData.cloudRecordingUrl}/start-recording/${connectionData.channelName}'), ); - if (response.statusCode == 200) { - log('Recording Started', level: Level.warning.value); - value = value.copyWith(sid: jsonDecode(response.body)['data']['sid']); + if (response.statusCode == HttpStatus.ok) { + value = value.copyWith( + sid: jsonDecode(response.body)['sid'], + resourceId: jsonDecode(response.body)['resource_id'], + ); + log('Recording Started with SID ${value.sid} and RESOURCE ID: ${value.resourceId}', + level: Level.warning.value); } else { log('Couldn\'t start the recording : ${response.statusCode}', level: Level.error.value); @@ -304,15 +309,17 @@ class SessionController extends ValueNotifier { Future stopCloudRecording( {required AgoraConnectionData connectionData}) async { final response = await http.post( - Uri.parse('${connectionData.cloudRecordingUrl}/api/stop/call'), - body: { - "channel": connectionData.channelName, - "sid": value.sid, - }, + Uri.parse( + '${connectionData.cloudRecordingUrl}/stop-recording/${connectionData.channelName}/${value.sid}/${value.resourceId}'), ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { log('Recording Ended', level: Level.warning.value); + if (connectionData.cloudRecordingCallback != null) { + connectionData.cloudRecordingCallback!( + jsonDecode(response.body)['mp4_link'], + jsonDecode(response.body)['m3u8_link']); + } } else { log('Couldn\'t end the recording : ${response.statusCode}', level: Level.error.value); diff --git a/lib/models/agora_connection_data.dart b/lib/models/agora_connection_data.dart index 1429ffb..92e4c98 100644 --- a/lib/models/agora_connection_data.dart +++ b/lib/models/agora_connection_data.dart @@ -40,6 +40,8 @@ class AgoraConnectionData { final bool screenSharingEnabled; + final Function? cloudRecordingCallback; + AgoraConnectionData({ required this.appId, required this.channelName, @@ -55,6 +57,7 @@ class AgoraConnectionData { this.rtmEnabled = true, this.screenSharingUid = 1000, this.screenSharingEnabled = true, + this.cloudRecordingCallback, }); AgoraConnectionData copyWith({ @@ -72,6 +75,7 @@ class AgoraConnectionData { bool? rtmEnabled, int? screenSharingUid, bool? screenSharingEnabled, + Function? cloudRecordingCallback, }) { return AgoraConnectionData( appId: appId ?? this.appId, @@ -88,6 +92,8 @@ class AgoraConnectionData { rtmEnabled: rtmEnabled ?? this.rtmEnabled, screenSharingUid: screenSharingUid ?? this.screenSharingUid, screenSharingEnabled: screenSharingEnabled ?? this.screenSharingEnabled, + cloudRecordingCallback: + cloudRecordingCallback ?? this.cloudRecordingCallback, ); } } diff --git a/lib/models/agora_rtm_mute_request.dart b/lib/models/agora_rtm_mute_request.dart index 7cfd2fb..f46e4a0 100644 --- a/lib/models/agora_rtm_mute_request.dart +++ b/lib/models/agora_rtm_mute_request.dart @@ -99,7 +99,7 @@ class AgoraUIKit { String platform = platformStr(); String framework = "flutter"; - String version = "1.3.1"; + String version = "1.3.2"; AgoraUIKit.fromJson(Map json) : platform = json['platform'], diff --git a/lib/models/agora_settings.dart b/lib/models/agora_settings.dart index 94b76d6..f52a1af 100644 --- a/lib/models/agora_settings.dart +++ b/lib/models/agora_settings.dart @@ -34,8 +34,9 @@ class AgoraSettings { final Map? uidToUserIdMap; final bool isScreenShared; final bool turnOnScreenSharing; - final bool isCloudRecording; + final RecordingState isCloudRecording; final String? sid; + final String? resourceId; AgoraSettings({ this.engine, @@ -66,8 +67,9 @@ class AgoraSettings { this.uidToUserIdMap, this.isScreenShared = false, this.turnOnScreenSharing = false, - this.isCloudRecording = false, + this.isCloudRecording = RecordingState.off, this.sid, + this.resourceId, }); AgoraSettings copyWith({ @@ -99,8 +101,9 @@ class AgoraSettings { Map? uidToUserIdMap, bool? isScreenShared, bool? turnOnScreenSharing, - bool? isCloudRecording, + RecordingState? isCloudRecording, String? sid, + String? resourceId, }) { return AgoraSettings( engine: engine ?? this.engine, @@ -134,6 +137,7 @@ class AgoraSettings { turnOnScreenSharing: turnOnScreenSharing ?? this.turnOnScreenSharing, isCloudRecording: isCloudRecording ?? this.isCloudRecording, sid: sid ?? this.sid, + resourceId: resourceId ?? this.resourceId, ); } } diff --git a/lib/src/buttons/cloud_recording_button.dart b/lib/src/buttons/cloud_recording_button.dart index 7663d92..11db505 100644 --- a/lib/src/buttons/cloud_recording_button.dart +++ b/lib/src/buttons/cloud_recording_button.dart @@ -1,8 +1,7 @@ +import 'package:agora_uikit/agora_uikit.dart'; import 'package:agora_uikit/controllers/rtc_buttons.dart'; import 'package:flutter/material.dart'; -import '../agora_client.dart'; - class CloudRecordingButton extends StatelessWidget { final Widget? child; final AgoraClient client; @@ -19,23 +18,67 @@ class CloudRecordingButton extends StatelessWidget { onPressed: () => toggleCloudRecording(client: client), child: child, ) - : RawMaterialButton( - onPressed: () => toggleCloudRecording(client: client), - child: Icon( - client.sessionController.value.isCloudRecording - ? Icons.stop - : Icons.circle_outlined, - color: client.sessionController.value.isCloudRecording - ? Colors.white - : Colors.blueAccent, - size: 20.0, - ), - shape: CircleBorder(), - elevation: 2.0, - fillColor: client.sessionController.value.isCloudRecording - ? Colors.blueAccent - : Colors.white, - padding: const EdgeInsets.all(12.0), + : RecordingStateButton( + client: client, ); } } + +class RecordingStateButton extends StatelessWidget { + final AgoraClient client; + const RecordingStateButton({Key? key, required this.client}) + : super(key: key); + + @override + Widget build(BuildContext context) { + switch (client.sessionController.value.isCloudRecording) { + case RecordingState.off: + return RawMaterialButton( + onPressed: () => toggleCloudRecording(client: client), + child: Icon( + Icons.circle_outlined, + color: Colors.blueAccent, + size: 20.0, + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: Colors.white, + padding: const EdgeInsets.all(12.0), + ); + case RecordingState.loading: + return RawMaterialButton( + onPressed: () {}, + child: Container( + height: 20, + width: 20, + padding: const EdgeInsets.all(2), + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: Colors.white, + padding: const EdgeInsets.all(12.0), + ); + case RecordingState.recording: + return RawMaterialButton( + onPressed: () => toggleCloudRecording(client: client), + child: Icon( + Icons.stop, + color: Colors.white, + size: 20.0, + ), + shape: CircleBorder(), + elevation: 2.0, + fillColor: Colors.blueAccent, + padding: const EdgeInsets.all(12.0), + ); + default: + return RawMaterialButton( + onPressed: () {}, + child: CircularProgressIndicator(), + ); + } + } +} diff --git a/lib/src/enums.dart b/lib/src/enums.dart index a5377c1..dfa08dc 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -31,3 +31,5 @@ extension LevelExtension on Level { } enum Device { camera, mic } + +enum RecordingState { off, loading, recording } diff --git a/pubspec.yaml b/pubspec.yaml index b6145b0..9eec69d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: agora_uikit description: Flutter plugin to simply integrate Agora Video Calling or Live Video Streaming to your app with just a few lines of code. -version: 1.3.1 +version: 1.3.2 homepage: https://www.agora.io/en/ repository: https://github.com/AgoraIO-Community/VideoUIKit-Flutter