diff --git a/android/build.gradle b/android/build.gradle index f36aaaf1..e2977fc7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.kotlin_version = '1.7.10' - ext.voxeet_sdk_version = "[3.10.1,3.11)" + ext.voxeet_sdk_version = "[3.11.0,3.12)" ext.dagger_version = "2.40.5" repositories { google() diff --git a/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ConferenceListenOptionsMapper.kt b/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ConferenceListenOptionsMapper.kt index 5960aa9c..657042bf 100644 --- a/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ConferenceListenOptionsMapper.kt +++ b/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ConferenceListenOptionsMapper.kt @@ -1,6 +1,7 @@ package io.dolby.comms.sdk.flutter.mapper import com.voxeet.VoxeetSDK +import com.voxeet.sdk.models.ListenType import com.voxeet.sdk.models.VideoForwardingStrategy import com.voxeet.sdk.services.builders.ConferenceListenOptions @@ -25,6 +26,9 @@ class ConferenceListenOptionsMapper { (options?.get("videoForwardingStrategy") as? String)?.let { builder.setVideoForwardingStrategy(VideoForwardingStrategy.valueOf(it)) } + (options?.get("listenType") as? String)?.let { listenType -> + builder.setListenType(ListenTypeMapper.fromValue(listenType)) + } builder .setSpatialAudio(options?.get("spatialAudio") as? Boolean ?: false) .build() diff --git a/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ListenTypeMapper.kt b/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ListenTypeMapper.kt new file mode 100644 index 00000000..1582039d --- /dev/null +++ b/android/src/main/kotlin/io/dolby/comms/sdk/flutter/mapper/ListenTypeMapper.kt @@ -0,0 +1,18 @@ +package io.dolby.comms.sdk.flutter.mapper + +import com.voxeet.sdk.models.ListenType +import java.security.InvalidParameterException + +object ListenTypeMapper { + fun fromValue(listenType: String): ListenType { + return when (listenType) { + REGULAR -> ListenType.REGULAR + MIXED -> ListenType.MIXED + else -> throw InvalidParameterException("Invalid value for listen type") + } + } + + + private const val REGULAR = "REGULAR" + private const val MIXED = "MIXED" +} \ No newline at end of file diff --git a/lib/dolbyio_comms_sdk_flutter.dart b/lib/dolbyio_comms_sdk_flutter.dart index 37e7b6e4..3aece792 100644 --- a/lib/dolbyio_comms_sdk_flutter.dart +++ b/lib/dolbyio_comms_sdk_flutter.dart @@ -41,7 +41,8 @@ export 'src/sdk_api/models/enums.dart' VideoPresentationState, VideoPresentationEventNames, RecordingServiceEventNames, - AudioPreviewEventNames; + AudioPreviewEventNames, + ListenType; export 'src/sdk_api/models/subscription.dart' show Subscription, SubscriptionType; export 'src/sdk_api/models/events.dart' diff --git a/lib/src/sdk_api/models/conference.dart b/lib/src/sdk_api/models/conference.dart index 21ed1062..bcc22a64 100644 --- a/lib/src/sdk_api/models/conference.dart +++ b/lib/src/sdk_api/models/conference.dart @@ -584,11 +584,14 @@ class ConferenceListenOptions { /// Enables spatial audio for the local participant who joins a Dolby Voice conference. By default, this parameter is set to false. When set to true in a conference that uses the individual [SpatialAudioStyle], the application must place remote participants in a 3D space using the [ConferenceService.setSpatialPosition] method. bool? spatialAudio; + ListenType listenType = ListenType.regular; + /// Returns a representation of this object as a JSON object. Map toJson() => { "conferenceAccessToken": conferenceAccessToken, "maxVideoForwarding": maxVideoForwarding, "videoForwardingStrategy": videoForwardingStrategy?.encode(), "spatialAudio": spatialAudio, + "listenType": listenType }; } diff --git a/lib/src/sdk_api/models/enums.dart b/lib/src/sdk_api/models/enums.dart index acc4f551..d51da603 100644 --- a/lib/src/sdk_api/models/enums.dart +++ b/lib/src/sdk_api/models/enums.dart @@ -242,3 +242,24 @@ enum AudioPreviewEventNames implements EnumWithStringValue { ); } } + +enum ListenType implements EnumWithStringValue { + regular("REGULAR"), + mixerMix("MIXER_MIX"); + + @override + final String value; + + const ListenType(this.value); + + static ListenType valueOf(String? value) { + final lowerCaseValue = value?.toLowerCase(); + return ListenType.values.firstWhere( + (element) { + return element.value == value || + element.name.toLowerCase() == lowerCaseValue; + }, + orElse: () => throw Exception("Invalid enum name"), + ); + } +} diff --git a/test_app/android/build.gradle b/test_app/android/build.gradle index d08d4ec5..a42df3f2 100644 --- a/test_app/android/build.gradle +++ b/test_app/android/build.gradle @@ -29,6 +29,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/test_app/lib/main.dart b/test_app/lib/main.dart index a5da841b..7b0765da 100644 --- a/test_app/lib/main.dart +++ b/test_app/lib/main.dart @@ -1,4 +1,5 @@ import 'package:dolbyio_comms_sdk_flutter_example/logger/logger_view.dart'; +import 'package:dolbyio_comms_sdk_flutter_example/screens/init_sdk_screen.dart'; import 'package:dolbyio_comms_sdk_flutter_example/state_management/models/conference_model.dart'; import 'package:flutter/material.dart'; import 'package:dolbyio_comms_sdk_flutter/dolbyio_comms_sdk_flutter.dart'; @@ -61,8 +62,8 @@ class _MyAppState extends State { widgetText: const Text('Open example app'), onPressed: () { Navigator.of(context).push(MaterialPageRoute( - settings: const RouteSettings(name: "LoginScreen"), - builder: (context) => const LoginScreen())); + settings: const RouteSettings(name: "InitSdkScreen"), + builder: (context) => const InitSdkScreen())); }), PrimaryButton( widgetText: const Text('Run playground'), diff --git a/test_app/lib/screens/init_sdk_screen.dart b/test_app/lib/screens/init_sdk_screen.dart new file mode 100644 index 00000000..608e7463 --- /dev/null +++ b/test_app/lib/screens/init_sdk_screen.dart @@ -0,0 +1,158 @@ +import 'dart:developer' as developer; +import 'package:dolbyio_comms_sdk_flutter_example/screens/login_screen.dart'; + +import 'join_screen.dart'; +import 'package:flutter/material.dart'; +import 'package:dolbyio_comms_sdk_flutter/dolbyio_comms_sdk_flutter.dart'; +import '/widgets/circular_progress_indicator.dart'; +import '/widgets/dolby_title.dart'; +import '/widgets/input_text_field.dart'; +import '/widgets/primary_button.dart'; +import '/widgets/text_form_field.dart'; +import '../shared_preferences_helper.dart'; + +class InitSdkScreen extends StatelessWidget { + const InitSdkScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SafeArea( + left: false, + right: false, + child: Scaffold( + body: Container( + constraints: const BoxConstraints.expand(), + decoration: const BoxDecoration(color: Colors.deepPurple), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: const [ + DolbyTitle(title: 'Dolby.io', subtitle: 'Flutter SDK'), + InitSdkScreenContent() + ], + ), + ), + ), + ); + } +} + +class InitSdkScreenContent extends StatefulWidget { + const InitSdkScreenContent({Key? key}) : super(key: key); + + @override + State createState() => _InitSdkScreenContentState(); +} + +class _InitSdkScreenContentState extends State { + final formKey = GlobalKey(); + final _dolbyioCommsSdkFlutterPlugin = DolbyioCommsSdk.instance; + TextEditingController accessTokenTextController = TextEditingController(); + late String _accessToken; + bool isSessionOpen = false, loginInProgress = false; + + @override + void initState() { + super.initState(); + initSharedPreferences(); + } + + Future initSessionStatus() async { + await _dolbyioCommsSdkFlutterPlugin.session.isOpen().then((isOpen) { + if (isOpen) { + isSessionOpen = true; + } else { + isSessionOpen = false; + } + }); + } + + @override + Widget build(BuildContext context) { + return Expanded( + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.vertical(top: Radius.circular(16))), + child: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Form( + key: formKey, + autovalidateMode: AutovalidateMode.disabled, + child: Column( + children: [ + InputTextFormField( + labelText: 'Access token', + controller: accessTokenTextController, + focusColor: Colors.deepPurple), + const SizedBox(height: 16), + ], + )), + const SizedBox(height: 16), + PrimaryButton( + color: Colors.deepPurple, + widgetText: loginInProgress + ? const WhiteCircularProgressIndicator() + : const Text('Initialize'), + onPressed: () { + onLoginButtonPressed(); + }, + ) + ], + ), + ), + ), + ), + ); + } + + void onLoginButtonPressed() async { + setState(() => loginInProgress = true); + try { + final isValidForm = formKey.currentState!.validate(); + if (isValidForm) { + await initializeSdk(); + saveToSharedPreferences(); + navigateToLoginScreen(); + } + } catch (e) { + onError('Error: ', e); + } finally { + setState(() => loginInProgress = false); + } + } + + Future initializeSdk() async { + _accessToken = accessTokenTextController.text; + await _dolbyioCommsSdkFlutterPlugin.initializeToken( + _accessToken, () => getRefreshToken()); + } + + void navigateToLoginScreen() { + Navigator.of(context).push( + MaterialPageRoute( + settings: const RouteSettings(name: "LoginScreen"), + builder: (context) => const LoginScreen(), + ), + ); + } + + Future getRefreshToken() async { + return _accessToken; + } + + void initSharedPreferences() { + accessTokenTextController.text = SharedPreferencesHelper().accessToken; + } + + void saveToSharedPreferences() { + SharedPreferencesHelper().accessToken = _accessToken; + } + + void onError(String message, Object? error) { + developer.log(message, error: error); + } +} diff --git a/test_app/lib/screens/join_screen.dart b/test_app/lib/screens/join_screen.dart index e1ec128e..eab6cff0 100644 --- a/test_app/lib/screens/join_screen.dart +++ b/test_app/lib/screens/join_screen.dart @@ -74,6 +74,7 @@ class _JoinConferenceContentState extends State { "Spatial Audio with Shared Scene"; static const String spatialAudioDisabled = "Spatial Audio Disabled"; bool joinAsListener = false; + bool isRtsViewer = false; String _conferenceAlias = ''; final LoggerView _loggerView = LoggerView.getLoggerView(); @@ -287,15 +288,12 @@ class _JoinConferenceContentState extends State { } }), SwitchOption( - title: 'Join as listener', - value: joinAsListener, + title: 'Is rts viewer', + value: isRtsViewer, onChanged: (value) { - if (value == false) { - setState(() => joinAsListener = value); - } else { - setState(() => joinAsListener = value); - } + setState(() => isRtsViewer = value); }), + ]), DropdownButton( focusColor: Colors.white, value: switchDolbyVoice @@ -560,8 +558,14 @@ class _JoinConferenceContentState extends State { ConferenceListenOptions conferenceListenOptions() { var listenOptions = ConferenceListenOptions(); + listenOptions.maxVideoForwarding = 4; listenOptions.spatialAudio = spatialAudio; + if (isRtsViewer) { + listenOptions.listenType = ListenType.mixerMix; + } else { + listenOptions.listenType = ListenType.regular; + } return listenOptions; } diff --git a/test_app/lib/screens/login_screen.dart b/test_app/lib/screens/login_screen.dart index b805ef1f..d67cadeb 100644 --- a/test_app/lib/screens/login_screen.dart +++ b/test_app/lib/screens/login_screen.dart @@ -46,10 +46,8 @@ class LoginScreenContent extends StatefulWidget { class _LoginScreenContentState extends State { final formKey = GlobalKey(); final _dolbyioCommsSdkFlutterPlugin = DolbyioCommsSdk.instance; - TextEditingController accessTokenTextController = TextEditingController(); TextEditingController usernameTextController = TextEditingController(); TextEditingController externalIdTextController = TextEditingController(); - late String _accessToken; late String _username; late String? _externalId; bool isSessionOpen = false, loginInProgress = false; @@ -89,10 +87,6 @@ class _LoginScreenContentState extends State { autovalidateMode: AutovalidateMode.disabled, child: Column( children: [ - InputTextFormField( - labelText: 'Access token', - controller: accessTokenTextController, - focusColor: Colors.deepPurple), const SizedBox(height: 16), InputTextFormField( labelText: 'Username', @@ -128,7 +122,6 @@ class _LoginScreenContentState extends State { try { final isValidForm = formKey.currentState!.validate(); if (isValidForm) { - await initializeSdk(); await openSession(); await initSessionStatus(); saveToSharedPreferences(); @@ -143,12 +136,6 @@ class _LoginScreenContentState extends State { } } - Future initializeSdk() async { - _accessToken = accessTokenTextController.text; - await _dolbyioCommsSdkFlutterPlugin.initializeToken( - _accessToken, () => getRefreshToken()); - } - Future openSession() async { _username = usernameTextController.text; _externalId = externalIdTextController.text; @@ -173,17 +160,11 @@ class _LoginScreenContentState extends State { ); } - Future getRefreshToken() async { - return _accessToken; - } - void initSharedPreferences() { - accessTokenTextController.text = SharedPreferencesHelper().accessToken; usernameTextController.text = SharedPreferencesHelper().username; } void saveToSharedPreferences() { - SharedPreferencesHelper().accessToken = _accessToken; SharedPreferencesHelper().username = _username; } diff --git a/test_app/pubspec.lock b/test_app/pubspec.lock index cadfd18e..de1e4767 100644 --- a/test_app/pubspec.lock +++ b/test_app/pubspec.lock @@ -1,22 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - archive: - dependency: transitive - description: - name: archive - sha256: "80e5141fafcb3361653ce308776cfd7d45e6e9fbb429e14eec571382c0c5fecb" - url: "https://pub.dev" - source: hosted - version: "3.3.2" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -29,10 +21,10 @@ packages: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" clock: dependency: transitive description: @@ -45,18 +37,10 @@ packages: dependency: "direct main" description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 - url: "https://pub.dev" - source: hosted - version: "1.17.0" - crypto: - dependency: transitive - description: - name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "1.17.1" cupertino_icons: dependency: "direct main" description: @@ -178,10 +162,10 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" lints: dependency: transitive description: @@ -194,10 +178,10 @@ packages: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.15" material_color_utilities: dependency: transitive description: @@ -210,10 +194,10 @@ packages: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.9.1" nested: dependency: transitive description: @@ -226,10 +210,10 @@ packages: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.8.3" path_provider_linux: dependency: transitive description: @@ -447,10 +431,10 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.5.1" typed_data: dependency: transitive description: @@ -471,18 +455,18 @@ packages: dependency: transitive description: name: vm_service - sha256: e7fb6c2282f7631712b69c19d1bff82f3767eea33a2321c14fa59ad67ea391c7 + sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe url: "https://pub.dev" source: hosted - version: "9.4.0" + version: "11.3.0" webdriver: dependency: transitive description: name: webdriver - sha256: ef67178f0cc7e32c1494645b11639dd1335f1d18814aa8435113a92e9ef9d841 + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" win32: dependency: transitive description: @@ -500,5 +484,5 @@ packages: source: hosted version: "0.2.0+1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=3.0.0-0 <4.0.0" flutter: ">=3.0.0"