diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index bb53f1c98..94eb978a1 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -9,8 +9,8 @@ plugins:
lint:
enabled:
- actionlint@1.6.27
- - checkov@3.2.60
- - osv-scanner@1.7.0
+ - checkov@3.2.71
+ - osv-scanner@1.7.2
- trivy@0.50.1
- trufflehog@3.71.0
- oxipng@9.0.0
diff --git a/packages/hms_room_kit/CHANGELOG.md b/packages/hms_room_kit/CHANGELOG.md
index ef767db42..2dabfff25 100644
--- a/packages/hms_room_kit/CHANGELOG.md
+++ b/packages/hms_room_kit/CHANGELOG.md
@@ -5,7 +5,26 @@
| hms_room_kit | [![Pub Version](https://img.shields.io/pub/v/hms_room_kit)](https://pub.dev/packages/hms_room_kit) |
| hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) |
-## 1.1.0 - 2024-04-19
+## 1.1.1 - 2024-04-26
+
+| Package | Version |
+| -------------- | ------------------------------------------------------------------------------------------------------ |
+| hms_room_kit | 1.1.1 |
+| hmssdk_flutter | 1.10.1 |
+
+### 🚀 Added
+
+- Support for captions in HLS Player
+
+ HLS Player now supports captions for better accessibility. This can be enabled or disabled from the player settings.
+
+- Introducing Landscape Mode for HLS Player
+
+ HLS Player now supports landscape mode for better viewing experience.
+
+Uses `hmssdk_flutter` package version 1.10.1
+
+## 1.1.0 - 2024-04-22
| Package | Version |
| -------------- | ------------------------------------------------------------------------------------------------------ |
@@ -32,7 +51,7 @@
Prebuilt no longer uses `flutter_foreground_task` package. For apps that require foreground service, the package can be added on the application level.
-Uses `hmssdk_flutter` package version to 1.1.10
+Uses `hmssdk_flutter` package version 1.10.0
## 1.0.17 - 2024-04-01
@@ -41,7 +60,7 @@ Uses `hmssdk_flutter` package version to 1.1.10
| hms_room_kit | 1.0.17 |
| hmssdk_flutter | 1.9.14 |
-Uses `hmssdk_flutter` package version to 1.9.14
+Uses `hmssdk_flutter` package version 1.9.14
## 1.0.16 - 2024-03-15
diff --git a/packages/hms_room_kit/README.md b/packages/hms_room_kit/README.md
index 85fb04eed..28592a53d 100644
--- a/packages/hms_room_kit/README.md
+++ b/packages/hms_room_kit/README.md
@@ -1,6 +1,7 @@
# 100ms Room Kit 🎉
[![Pub Version](https://img.shields.io/pub/v/hms_room_kit)](https://pub.dev/packages/hms_room_kit)
+[![Build](https://github.com/100mslive/100ms-flutter/actions/workflows/build.yml/badge.svg?branch=develop)](https://github.com/100mslive/100ms-flutter/actions/workflows/build.yml)
[![License](https://img.shields.io/github/license/100mslive/100ms-flutter)](https://www.100ms.live/)
[![Documentation](https://img.shields.io/badge/Read-Documentation-blue)](https://docs.100ms.live/flutter/v2/foundation/basics)
[![Discord](https://img.shields.io/discord/843749923060711464?label=Join%20on%20Discord)](https://100ms.live/discord)
diff --git a/packages/hms_room_kit/example/pubspec.lock b/packages/hms_room_kit/example/pubspec.lock
index a43e05a3d..5013a3708 100644
--- a/packages/hms_room_kit/example/pubspec.lock
+++ b/packages/hms_room_kit/example/pubspec.lock
@@ -93,10 +93,10 @@ packages:
dependency: "direct main"
description:
name: cupertino_icons
- sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
+ sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
- version: "1.0.6"
+ version: "1.0.8"
dots_indicator:
dependency: transitive
description:
@@ -206,14 +206,15 @@ packages:
path: ".."
relative: true
source: path
- version: "1.1.0"
+ version: "1.1.1"
hmssdk_flutter:
dependency: transitive
description:
- path: "../../hmssdk_flutter"
- relative: true
- source: path
- version: "1.10.0"
+ name: hmssdk_flutter
+ sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.10.1"
http:
dependency: transitive
description:
diff --git a/packages/hms_room_kit/example/pubspec.yaml b/packages/hms_room_kit/example/pubspec.yaml
index 2b69549d4..9a41feb9d 100644
--- a/packages/hms_room_kit/example/pubspec.yaml
+++ b/packages/hms_room_kit/example/pubspec.yaml
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
-version: 1.1.0
+version: 1.1.1
environment:
sdk: ">=2.19.6 <3.0.0"
diff --git a/packages/hms_room_kit/lib/src/assets/icons/no_network.png b/packages/hms_room_kit/lib/src/assets/icons/no_network.png
deleted file mode 100644
index 3199decb9..000000000
Binary files a/packages/hms_room_kit/lib/src/assets/icons/no_network.png and /dev/null differ
diff --git a/packages/hms_room_kit/lib/src/assets/icons/pause.svg b/packages/hms_room_kit/lib/src/assets/icons/pause.svg
new file mode 100644
index 000000000..f7fc7e65f
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/assets/icons/pause.svg
@@ -0,0 +1,4 @@
+
diff --git a/packages/hms_room_kit/lib/src/assets/icons/play.svg b/packages/hms_room_kit/lib/src/assets/icons/play.svg
new file mode 100644
index 000000000..5183c98df
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/assets/icons/play.svg
@@ -0,0 +1,3 @@
+
diff --git a/packages/hms_room_kit/lib/src/assets/icons/seek_backward.svg b/packages/hms_room_kit/lib/src/assets/icons/seek_backward.svg
new file mode 100644
index 000000000..0879692ba
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/assets/icons/seek_backward.svg
@@ -0,0 +1,5 @@
+
diff --git a/packages/hms_room_kit/lib/src/assets/icons/seek_forward.svg b/packages/hms_room_kit/lib/src/assets/icons/seek_forward.svg
new file mode 100644
index 000000000..d17b2fff3
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/assets/icons/seek_forward.svg
@@ -0,0 +1,5 @@
+
diff --git a/packages/hms_room_kit/lib/src/common/utility_components.dart b/packages/hms_room_kit/lib/src/common/utility_components.dart
index 7bc5d99ad..bc56087d9 100644
--- a/packages/hms_room_kit/lib/src/common/utility_components.dart
+++ b/packages/hms_room_kit/lib/src/common/utility_components.dart
@@ -992,10 +992,10 @@ class UtilityComponents {
MeetingStore meetingStore = Provider.of(context);
return GestureDetector(
onTap: () {
- if (meetingStore.isLandscapeLocked) {
- meetingStore.setLandscapeLock(false);
+ if (meetingStore.isScreenRotationAllowed) {
+ meetingStore.allowScreenRotation(false);
} else {
- meetingStore.setLandscapeLock(true);
+ meetingStore.allowScreenRotation(true);
}
},
child: Padding(
@@ -1003,7 +1003,7 @@ class UtilityComponents {
child: SvgPicture.asset(
"packages/hms_room_kit/lib/src/assets/icons/rotate.svg",
colorFilter: ColorFilter.mode(
- meetingStore.isLandscapeLocked ? Colors.blue : iconColor,
+ meetingStore.isScreenRotationAllowed ? Colors.blue : iconColor,
BlendMode.srcIn)),
),
);
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_hand_raise_menu.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_hand_raise_menu.dart
index 20aafc5af..7d76ff6b3 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_hand_raise_menu.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_hand_raise_menu.dart
@@ -1,12 +1,18 @@
+library;
+
+///Package imports
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:provider/provider.dart';
+
+///Project imports
import 'package:hms_room_kit/hms_room_kit.dart';
import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart';
import 'package:hms_room_kit/src/meeting/meeting_store.dart';
import 'package:hms_room_kit/src/widgets/bottom_sheets/hls_app_utilities_bottom_sheet.dart';
import 'package:hms_room_kit/src/widgets/common_widgets/hms_embedded_button.dart';
-import 'package:provider/provider.dart';
+///[HLSHandRaiseMenu] is a widget that is used to render the hand raise menu in case of Viewer near realtime
class HLSHandRaiseMenu extends StatelessWidget {
const HLSHandRaiseMenu({Key? key}) : super(key: key);
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart
index e756e567e..0632aad64 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player.dart
@@ -28,56 +28,54 @@ class HLSPlayer extends StatelessWidget {
///Renders the HLS Player if the HLS has started
///Otherwise renders the waiting UI
hasHLSStarted
- ? Align(
- alignment: Alignment.center,
- child: Selector(
- selector: (_, hlsPlayerStore) =>
- hlsPlayerStore.hlsPlayerSize,
- builder: (_, hlsPlayerSize, __) {
- return AspectRatio(
- aspectRatio:
- hlsPlayerSize.width / hlsPlayerSize.height,
- child: InkWell(
- onTap: () => context
- .read()
- .toggleButtonsVisibility(),
- splashFactory: NoSplash.splashFactory,
- splashColor: HMSThemeColors.backgroundDim,
- child: IgnorePointer(
- child: const HMSHLSPlayer(
- showPlayerControls: false,
- ),
- ),
- ),
- );
- }),
- )
+ ? Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.isFullScreen,
+ builder: (_, isFullScreen, __) {
+ return InteractiveViewer(
+ minScale: 1,
+ maxScale: 8,
+ child: Align(
+ alignment: Alignment.center,
+ child: Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.hlsPlayerSize,
+ builder: (_, hlsPlayerSize, __) {
+ return InkWell(
+ onTap: () => context
+ .read()
+ .toggleButtonsVisibility(),
+ splashFactory: NoSplash.splashFactory,
+ splashColor: HMSThemeColors.backgroundDim,
+ child: AspectRatio(
+ aspectRatio: hlsPlayerSize.width /
+ hlsPlayerSize.height,
+ child: Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.isFullScreen,
+ builder: (_, isFullScreen, __) {
+ return IgnorePointer(
+ child: const HMSHLSPlayer(
+ showPlayerControls: false,
+ ),
+ );
+ }),
+ ),
+ );
+ }),
+ ),
+ );
+ })
: Center(child: const HLSWaitingUI()),
///This renders the overlay controls for HLS Player
Align(
- alignment: Alignment.center,
- child: Selector(
- selector: (_, hlsPlayerStore) =>
- hlsPlayerStore.isFullScreen,
- builder: (_, isFullScreen, __) {
- return isFullScreen
- ? Selector(
- selector: (_, hlsPlayerStore) =>
- hlsPlayerStore.hlsPlayerSize,
- builder: (_, hlsPlayerSize, __) {
- return AspectRatio(
- aspectRatio: hlsPlayerSize.width /
- hlsPlayerSize.height,
- child: HLSPlayerOverlayOptions(
- hasHLSStarted: hasHLSStarted,
- ),
- );
- })
- : HLSPlayerOverlayOptions(
- hasHLSStarted: hasHLSStarted);
- }),
- ),
+ alignment: Alignment.center,
+ child: HLSPlayerOverlayOptions(
+ hasHLSStarted: hasHLSStarted,
+ )),
+
+ ///This renders the circular progress indicator when the player is buffering or failed
Selector(
selector: (_, hlsPlayerStore) =>
hlsPlayerStore.playerPlaybackState,
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_desktop_controls.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_desktop_controls.dart
index 9ebba4811..e616c351c 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_desktop_controls.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_desktop_controls.dart
@@ -9,6 +9,10 @@ import 'package:hms_room_kit/src/widgets/bottom_sheets/chat_bottom_sheet.dart';
///[HLSPlayerDesktopControls] is the desktop controls for the HLS Player
class HLSPlayerDesktopControls extends StatefulWidget {
+ final Orientation orientation;
+ const HLSPlayerDesktopControls({Key? key, required this.orientation})
+ : super(key: key);
+
@override
State createState() =>
_HLSPlayerDesktopControlsState();
@@ -26,25 +30,25 @@ class _HLSPlayerDesktopControlsState extends State {
@override
Widget build(BuildContext context) {
- return Expanded(
- child: Column(
- children: [
- ///Renders HLS Stream Description and Chat Bottom Sheet
- HLSStreamDescription(
- showDescription: showDescription,
- toggleDescription: toggleDescription),
-
- ///Renders Chat Bottom Sheet only is the description is not visible
- if (!showDescription)
- Expanded(
- child: Padding(
- padding: const EdgeInsets.only(bottom: 8.0),
- child: ChatBottomSheet(
- isHLSChat: true,
- ),
- ))
- ],
- ),
+ return Column(
+ children: [
+ ///Renders HLS Stream Description and Chat Bottom Sheet
+ widget.orientation == Orientation.portrait
+ ? HLSStreamDescription(
+ showDescription: showDescription,
+ toggleDescription: toggleDescription)
+ : const SizedBox(),
+
+ ///Renders Chat Bottom Sheet only if the description is not visible
+ if (!showDescription)
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(bottom: 8.0),
+ child: const ChatBottomSheet(
+ isHLSChat: true,
+ ),
+ ))
+ ],
);
}
}
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_overlay_options.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_overlay_options.dart
index 58dec346e..339d85fce 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_overlay_options.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_overlay_options.dart
@@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
///Project imports
import 'package:hms_room_kit/src/hls_viewer/hls_viewer_bottom_navigation_bar.dart';
import 'package:hms_room_kit/src/hls_viewer/hls_viewer_header.dart';
+import 'package:hms_room_kit/src/hls_viewer/hls_viewer_mid_section.dart';
///[HLSPlayerOverlayOptions] renders the overlay options for the HLS Player
class HLSPlayerOverlayOptions extends StatelessWidget {
@@ -14,16 +15,30 @@ class HLSPlayerOverlayOptions extends StatelessWidget {
const HLSPlayerOverlayOptions({super.key, required this.hasHLSStarted});
@override
Widget build(BuildContext context) {
- return Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ ///Here top and bottom navigation bar are in Column
+ ///while mid section is above the Column
+ ///This is done to avoid overflowing in case of
+ ///large transcription
+ return Stack(
children: [
- HLSViewerHeader(
- hasHLSStarted: hasHLSStarted,
+ Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ HLSViewerHeader(
+ hasHLSStarted: hasHLSStarted,
+ ),
+
+ ///Renders the bottom navigation bar if the HLS has started
+ ///Otherwise does not render the bottom navigation bar
+ hasHLSStarted ? HLSViewerBottomNavigationBar() : const SizedBox()
+ ],
),
- ///Renders the bottom navigation bar if the HLS has started
- ///Otherwise does not render the bottom navigation bar
- hasHLSStarted ? HLSViewerBottomNavigationBar() : const SizedBox()
+ ///This renders the pause/play button
+ Align(
+ alignment: Alignment.center,
+ child: hasHLSStarted ? HLSViewerMidSection() : const SizedBox(),
+ )
],
);
}
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart
new file mode 100644
index 000000000..fe28dc1b4
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_seekbar.dart
@@ -0,0 +1,92 @@
+library;
+
+///Package imports
+import 'package:flutter/material.dart';
+import 'package:hmssdk_flutter/hmssdk_flutter.dart';
+import 'package:provider/provider.dart';
+import 'package:tuple/tuple.dart';
+
+///Project imports
+import 'package:hms_room_kit/src/meeting/meeting_store.dart';
+import 'package:hms_room_kit/hms_room_kit.dart';
+import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart';
+
+///[HLSPlayerSeekbar] is the seekbar for the HLS Player
+class HLSPlayerSeekbar extends StatefulWidget {
+ @override
+ State createState() => _HLSPlayerSeekbarState();
+}
+
+class _HLSPlayerSeekbarState extends State {
+ int seekBarValue = 0;
+ int minValue = 0, maxValue = 300;
+ bool isInteracting = false;
+
+ ///[_toggleIsInteracting] toggles the [isInteracting] variable
+ void _toggleIsInteracting(bool value) {
+ setState(() {
+ isInteracting = value;
+ });
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ maxValue = context.read().rollingWindow.inSeconds;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return (context
+ .read()
+ .hmsRoom
+ ?.hmshlsStreamingState
+ ?.variants[0]
+ ?.playlistType ==
+ HMSHLSPlaylistType.dvr)
+ ? Selector>(
+ selector: (_, hlsPlayerStore) => Tuple2(
+ hlsPlayerStore.timeFromLive, hlsPlayerStore.rollingWindow),
+ builder: (_, data, __) {
+ maxValue = data.item2.inSeconds;
+ seekBarValue = maxValue > 0 ? maxValue - data.item1.inSeconds : 0;
+ minValue = 0;
+ return (maxValue > 0 && seekBarValue > 0)
+ ? SliderTheme(
+ data: SliderThemeData(
+ trackHeight: isInteracting ? 6 : 4,
+ trackShape: RoundedRectSliderTrackShape(),
+ inactiveTrackColor: HMSThemeColors.baseWhite,
+ activeTrackColor: HMSThemeColors.primaryDefault,
+ thumbColor: HMSThemeColors.primaryDefault,
+ thumbShape: RoundSliderThumbShape(
+ enabledThumbRadius: isInteracting ? 10 : 6),
+ overlayShape:
+ RoundSliderOverlayShape(overlayRadius: 0)),
+ child: Slider(
+ value: seekBarValue.toDouble(),
+ onChanged: (value) {},
+ onChangeEnd: (value) {
+ if (value > seekBarValue) {
+ HMSHLSPlayerController.seekForward(
+ seconds: (value - seekBarValue).toInt());
+ } else {
+ HMSHLSPlayerController.seekBackward(
+ seconds: (seekBarValue - value).toInt());
+ }
+ HMSHLSPlayerController.resume();
+ _toggleIsInteracting(false);
+ },
+ onChangeStart: (_) {
+ HMSHLSPlayerController.pause();
+ _toggleIsInteracting(true);
+ },
+ min: minValue.toDouble(),
+ max: maxValue.toDouble(),
+ ),
+ )
+ : const SizedBox();
+ })
+ : const SizedBox();
+ }
+}
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart
index f48fab29b..c91f32a35 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_player_store.dart
@@ -3,6 +3,7 @@ library;
///Dart imports
import 'dart:async';
import 'dart:developer';
+import 'dart:io';
///Package imports
import 'package:flutter/material.dart';
@@ -14,6 +15,11 @@ import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart';
///[HLSPlayerStore] is a store that stores the state of the HLS Player
class HLSPlayerStore extends ChangeNotifier
implements HMSHLSPlaybackEventsListener {
+ ///[timeBeforeLive] is the time to show the go live button
+ ///It is set to 10 seconds for Android and 1 second for iOS
+ ///Basically `Go Live` will only be shown if the distance from live is greater than this value
+ final int timeBeforeLive = Platform.isAndroid ? 10000 : 5000;
+
///This variable stores whether the application is in full screen or not
bool isFullScreen = false;
@@ -29,6 +35,15 @@ class HLSPlayerStore extends ChangeNotifier
///This variable stores whether the captions are supported or not
bool areCaptionsSupported = false;
+ ///This variable stores whether the stream is at live edge or not
+ bool isLive = true;
+
+ ///This variable stores the time from live edge
+ Duration timeFromLive = Duration(milliseconds: 0);
+
+ ///This variable stores the stream rolling window time
+ Duration rollingWindow = Duration(milliseconds: 0);
+
///This variable stores whether the chat is opened or not
///The initial value is taken from the [HMSRoomLayout.chatData]
bool isChatOpened = (HMSRoomLayout.chatData?.isOpenInitially ?? false) &&
@@ -49,10 +64,17 @@ class HLSPlayerStore extends ChangeNotifier
///[hlsPlayerSize] stores the resolution of HLS Stream
Size hlsPlayerSize = Size(1, 1);
+ ///This variable stores whether the HLS Stats are enabled or not
bool isHLSStatsEnabled = false;
+ ///This variable stores the player playback state
HMSHLSPlaybackState playerPlaybackState = HMSHLSPlaybackState.PLAYING;
+ ///This variable handles the timer for fetching the stream properties
+ Timer? _timer;
+
+ String? caption;
+
///This method starts a timer for 5 seconds and then hides the buttons
///
///[isStreamPlaying] is used to check if the video is playing or not
@@ -90,6 +112,17 @@ class HLSPlayerStore extends ChangeNotifier
notifyListeners();
}
+ ///[toggleStreamPlaying] toggles the stream playing
+ void toggleStreamPlaying() {
+ if (isStreamPlaying) {
+ HMSHLSPlayerController.pause();
+ } else {
+ HMSHLSPlayerController.resume();
+ }
+ isStreamPlaying = !isStreamPlaying;
+ notifyListeners();
+ }
+
///This method toggles the visibility of the chat
void toggleIsChatOpened() {
isChatOpened = !isChatOpened;
@@ -98,6 +131,11 @@ class HLSPlayerStore extends ChangeNotifier
///This method toggles the visibility of the captions
void toggleCaptions() {
+ if (isCaptionEnabled) {
+ HMSHLSPlayerController.disableClosedCaptions();
+ } else {
+ HMSHLSPlayerController.enableClosedCaptions();
+ }
isCaptionEnabled = !isCaptionEnabled;
notifyListeners();
}
@@ -128,6 +166,11 @@ class HLSPlayerStore extends ChangeNotifier
void areClosedCaptionsSupported() async {
areCaptionsSupported =
await HMSHLSPlayerController.areClosedCaptionsSupported();
+
+ ///If isCaptionEnabled is true we enable the captions
+ if (isCaptionEnabled) {
+ HMSHLSPlayerController.enableClosedCaptions();
+ }
notifyListeners();
}
@@ -141,6 +184,37 @@ class HLSPlayerStore extends ChangeNotifier
notifyListeners();
}
+ ///[startTimer] starts a timer to get the stream properties every 3 seconds
+ void startTimer() {
+ if (_timer != null) {
+ _timer?.cancel();
+ }
+ _timer = Timer.periodic(Duration(seconds: 3), (timer) {
+ getStreamProperties();
+ });
+ }
+
+ ///[cancelTimer] cancels the timer
+ void cancelTimer() {
+ _timer?.cancel();
+ }
+
+ ///[getStreamProperties] gets the stream properties
+ void getStreamProperties() async {
+ HLSStreamProperties result =
+ await HMSHLSPlayerController.getStreamProperties();
+
+ ///If the [rollingWindowTime] is not null we set the [rollingWindow] to the value of [rollingWindowTime]
+ ///If the [streamDuration] is not null we set the [rollingWindow] to the value of [streamDuration]
+ ///If both are null we set the [rollingWindow] to 0
+ if (result.rollingWindowTime != null && result.streamDuration == null) {
+ rollingWindow = Duration(seconds: result.rollingWindowTime!.toInt());
+ } else if (result.streamDuration != null) {
+ rollingWindow = Duration(seconds: result.streamDuration!.toInt());
+ }
+ notifyListeners();
+ }
+
@override
void onCue({required HMSHLSCue hlsCue}) {}
@@ -149,7 +223,9 @@ class HLSPlayerStore extends ChangeNotifier
@override
void onHLSEventUpdate({required HMSHLSPlayerStats playerStats}) {
- log("onHLSEventUpdate-> bitrate:${playerStats.averageBitrate} buffered duration: ${playerStats.bufferedDuration}");
+ log("onHLSEventUpdate-> distanceFromLive: ${playerStats.distanceFromLive} buffered duration: ${playerStats.bufferedDuration}");
+ isLive = playerStats.distanceFromLive < timeBeforeLive;
+ timeFromLive = Duration(milliseconds: playerStats.distanceFromLive.toInt());
hlsPlayerStats = playerStats;
notifyListeners();
}
@@ -163,12 +239,26 @@ class HLSPlayerStore extends ChangeNotifier
void onPlaybackStateChanged({required HMSHLSPlaybackState playbackState}) {
log("Playback state changed to ${playbackState.name}");
playerPlaybackState = playbackState;
- if (playerPlaybackState == HMSHLSPlaybackState.PLAYING) {
- isPlayerFailed = false;
- areClosedCaptionsSupported();
- }
- if (playerPlaybackState == HMSHLSPlaybackState.FAILED) {
- isPlayerFailed = true;
+ switch (playbackState) {
+ case HMSHLSPlaybackState.PLAYING:
+ areClosedCaptionsSupported();
+ setHLSPlayerStats(true);
+ startTimer();
+ isStreamPlaying = true;
+ isPlayerFailed = false;
+ break;
+ case HMSHLSPlaybackState.STOPPED:
+ break;
+ case HMSHLSPlaybackState.PAUSED:
+ isStreamPlaying = false;
+ break;
+ case HMSHLSPlaybackState.BUFFERING:
+ break;
+ case HMSHLSPlaybackState.FAILED:
+ isPlayerFailed = true;
+ break;
+ case HMSHLSPlaybackState.UNKNOWN:
+ break;
}
notifyListeners();
}
@@ -179,4 +269,14 @@ class HLSPlayerStore extends ChangeNotifier
hlsPlayerSize = size;
notifyListeners();
}
+
+ @override
+ void onCues({required List subtitles}) {
+ log("onCues -> $subtitles");
+ String newSubtitles = subtitles.join(" ");
+ if (newSubtitles != caption) {
+ caption = newSubtitles;
+ }
+ notifyListeners();
+ }
}
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_bottom_navigation_bar.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_bottom_navigation_bar.dart
index 76584868a..ddb2c8192 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_bottom_navigation_bar.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_bottom_navigation_bar.dart
@@ -1,11 +1,17 @@
library;
+///Dart imports
+import 'dart:io';
+
///Package imports
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
+import 'package:hms_room_kit/src/widgets/common_widgets/hms_subheading_text.dart';
+import 'package:hmssdk_flutter/hmssdk_flutter.dart';
import 'package:provider/provider.dart';
///Project imports
+import 'package:hms_room_kit/src/hls_viewer/hls_player_seekbar.dart';
import 'package:hms_room_kit/hms_room_kit.dart';
import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart';
@@ -13,6 +19,13 @@ import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart';
class HLSViewerBottomNavigationBar extends StatelessWidget {
const HLSViewerBottomNavigationBar({super.key});
+ String _setTimeFromLive(Duration time) {
+ int minutes = time.inMinutes;
+ int seconds = time.inSeconds.remainder(60);
+
+ return "-${minutes > 0 ? "${minutes.toString().padLeft(2, '0')}:" : ""}${seconds.toString().padLeft(2, '0')}s";
+ }
+
@override
Widget build(BuildContext context) {
return Container(
@@ -23,27 +36,32 @@ class HLSViewerBottomNavigationBar extends StatelessWidget {
colors: [Colors.black.withAlpha(0), Colors.black.withAlpha(64)])),
child: Padding(
padding: EdgeInsets.only(left: 12, right: 12),
-
- ///Here we render the chat component if the chat is opened
- ///We also render the leave button, hand raise button, chat button and the menu button
child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- ///Chat Component only visible when the chat is opened
- // if (HMSRoomLayout.chatData != null)
- // Selector(
- // selector: (_, hlsPlayerStore) => hlsPlayerStore.isChatOpened,
- // builder: (_, isChatOpened, __) {
- // if (isChatOpened) {
- // Provider.of(context, listen: true)
- // .isNewMessageReceived = false;
- // }
- // return isChatOpened
- // ? const OverlayChatComponent()
- // : Container();
- // }),
+ ///This renders the captions only in case of android since iOS provides caption out of the box
+ if (Platform.isAndroid)
+ Selector(
+ selector: (_, hlsPlayerStore) => hlsPlayerStore.caption,
+ builder: (_, caption, __) {
+ return caption != null
+ ? Padding(
+ padding: const EdgeInsets.only(
+ bottom: 4.0, left: 4, right: 4),
+ child: Center(
+ child: HMSSubheadingText(
+ text: caption,
+ textColor: HMSThemeColors.baseWhite,
+ fontWeight: FontWeight.w600,
+ maxLines: 5,
+ ),
+ ),
+ )
+ : SizedBox();
+ }),
///Bottom Navigation Bar
- ///We render the leave button, hand raise button, chat button and the menu button
+ ///We render the stream controls here
///We only render the bottom navigation bar when the stream controls are visible
Selector(
selector: (_, hlsPlayerStore) =>
@@ -53,28 +71,90 @@ class HLSViewerBottomNavigationBar extends StatelessWidget {
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- ///This renders the go live button
- Row(
- children: [
- GestureDetector(
- onTap: () => {},
- child: Row(
+ ///This renders the go live/live button
+ Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.isLive,
+ builder: (_, isLive, __) {
+ return Row(
children: [
- Padding(
- padding:
- const EdgeInsets.only(right: 8.0),
- child: SvgPicture.asset(
- "packages/hms_room_kit/lib/src/assets/icons/red_dot.svg"),
- ),
- HMSTitleText(
- text: "LIVE",
- textColor: HMSThemeColors
- .onSurfaceHighEmphasis)
+ GestureDetector(
+ onTap: () => {
+ if (!isLive)
+ {
+ HMSHLSPlayerController
+ .seekToLivePosition()
+ }
+ },
+ child: isLive
+ ? Row(
+ children: [
+ Padding(
+ padding:
+ const EdgeInsets.only(
+ right: 8.0),
+ child: SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/red_dot.svg",
+ height: 8,
+ width: 8,
+ ),
+ ),
+ HMSTitleText(
+ text: "LIVE",
+ textColor: HMSThemeColors
+ .onSurfaceHighEmphasis)
+ ],
+ )
+ : Row(
+ children: [
+ Padding(
+ padding:
+ const EdgeInsets.only(
+ right: 8.0),
+ child: SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/red_dot.svg",
+ height: 8,
+ width: 8,
+ colorFilter: ColorFilter.mode(
+ HMSThemeColors
+ .onSurfaceLowEmphasis,
+ BlendMode.srcIn),
+ ),
+ ),
+ HMSTitleText(
+ text: "GO LIVE",
+ textColor: HMSThemeColors
+ .onSurfaceMediumEmphasis),
+ Selector(
+ selector:
+ (_, hlsPlayerStore) =>
+ hlsPlayerStore
+ .timeFromLive,
+ builder: (_, timeFromLive,
+ __) {
+ return Padding(
+ padding:
+ const EdgeInsets
+ .only(
+ left: 8.0),
+ child: HMSTitleText(
+ text: _setTimeFromLive(
+ timeFromLive),
+ textColor:
+ HMSThemeColors
+ .baseWhite,
+ fontWeight:
+ FontWeight.w400,
+ ),
+ );
+ })
+ ],
+ ),
+ )
],
- ),
- )
- ],
- ),
+ );
+ }),
///This renders the minimize/maximize button
///to toggle the full screen mode
@@ -98,6 +178,19 @@ class HLSViewerBottomNavigationBar extends StatelessWidget {
)
: const SizedBox();
}),
+
+ ///This renders the seekbar
+ Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.areStreamControlsVisible,
+ builder: (_, areStreamControlsVisible, __) {
+ return areStreamControlsVisible
+ ? Padding(
+ padding: const EdgeInsets.only(top: 8, bottom: 4),
+ child: HLSPlayerSeekbar(),
+ )
+ : const SizedBox();
+ })
],
),
),
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart
index 121f4dcd3..f72197030 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_header.dart
@@ -2,12 +2,14 @@ library;
///Package imports
import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
import 'package:provider/provider.dart';
///Project imports
import 'package:hms_room_kit/src/common/utility_components.dart';
import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart';
import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart';
+import 'package:tuple/tuple.dart';
///[HLSViewerHeader] is the header of the HLS Viewer screen
class HLSViewerHeader extends StatelessWidget {
@@ -53,50 +55,52 @@ class HLSViewerHeader extends StatelessWidget {
///This renders the [Caption Button] and [Settings Button] only if the controls are visible
///and the HLS has started
- // if (hasHLSStarted)
- // Row(
- // mainAxisAlignment: MainAxisAlignment.end,
- // children: [
- // ///The caption button is only rendered when closed captions are supported
- // ///and the HLS has started
- // Selector>(
- // selector: (_, hlsPlayerStore) => Tuple2(
- // hlsPlayerStore.isCaptionEnabled,
- // hlsPlayerStore.areCaptionsSupported),
- // builder: (_, captionsData, __) {
- // return captionsData.item2
- // ? InkWell(
- // onTap: () {
- // context
- // .read()
- // .toggleCaptions();
- // },
- // child: SvgPicture.asset(
- // "packages/hms_room_kit/lib/src/assets/icons/caption_${captionsData.item1 ? "on" : "off"}.svg",
- // colorFilter: ColorFilter.mode(
- // HMSThemeColors
- // .onSurfaceHighEmphasis,
- // BlendMode.srcIn),
- // semanticsLabel:
- // "caption_toggle_button",
- // ),
- // )
- // : const SizedBox();
- // }),
- // const SizedBox(
- // width: 16,
- // ),
+ if (hasHLSStarted)
+ Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ ///The caption button is only rendered when closed captions are supported
+ ///and the HLS has started
+ Selector>(
+ selector: (_, hlsPlayerStore) => Tuple2(
+ hlsPlayerStore.isCaptionEnabled,
+ hlsPlayerStore.areCaptionsSupported),
+ builder: (_, captionsData, __) {
+ return captionsData.item2
+ ? InkWell(
+ onTap: () {
+ context
+ .read()
+ .toggleCaptions();
+ },
+ child: SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/caption_${captionsData.item1 ? "on" : "off"}.svg",
+ colorFilter: ColorFilter.mode(
+ HMSThemeColors
+ .onSurfaceHighEmphasis,
+ BlendMode.srcIn),
+ semanticsLabel:
+ "caption_toggle_button",
+ ),
+ )
+ : const SizedBox();
+ }),
- // ///This renders the settings button
- // SvgPicture.asset(
- // "packages/hms_room_kit/lib/src/assets/icons/settings.svg",
- // colorFilter: ColorFilter.mode(
- // HMSThemeColors.onSurfaceHighEmphasis,
- // BlendMode.srcIn),
- // semanticsLabel: "caption_toggle_button",
- // )
- // ],
- // )
+ ///This will be added later
+ // const SizedBox(
+ // width: 16,
+ // ),
+
+ // ///This renders the settings button
+ // SvgPicture.asset(
+ // "packages/hms_room_kit/lib/src/assets/icons/settings.svg",
+ // colorFilter: ColorFilter.mode(
+ // HMSThemeColors.onSurfaceHighEmphasis,
+ // BlendMode.srcIn),
+ // semanticsLabel: "caption_toggle_button",
+ // )
+ ],
+ )
],
)
: const SizedBox();
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_mid_section.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_mid_section.dart
new file mode 100644
index 000000000..3b02dace6
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_mid_section.dart
@@ -0,0 +1,80 @@
+library;
+
+///Package imports
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:hmssdk_flutter/hmssdk_flutter.dart';
+import 'package:provider/provider.dart';
+
+///Project imports
+import 'package:hms_room_kit/src/hls_viewer/hls_player_store.dart';
+import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart';
+
+///[HLSViewerMidSection] renders the mid section of the HLS Viewer containing the pause/play button
+class HLSViewerMidSection extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.areStreamControlsVisible,
+ builder: (_, areStreamControlsVisible, __) {
+ return areStreamControlsVisible
+ ? Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(right: 16.0),
+ child: InkWell(
+ onTap: () =>
+ {HMSHLSPlayerController.seekBackward(seconds: 10)},
+ child: SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/seek_backward.svg",
+ colorFilter: ColorFilter.mode(
+ HMSThemeColors.baseWhite, BlendMode.srcIn),
+ ),
+ ),
+ ),
+ GestureDetector(
+ onTap: () => {
+ context.read().toggleStreamPlaying(),
+ },
+ child: CircleAvatar(
+ radius: 32,
+ backgroundColor:
+ HMSThemeColors.backgroundDim.withOpacity(0.64),
+ child: Center(
+ child: Container(
+ child: Selector(
+ selector: (_, hlsPlayerStore) =>
+ hlsPlayerStore.isStreamPlaying,
+ builder: (_, isStreamPlaying, __) {
+ return SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/${isStreamPlaying ? "pause" : "play"}.svg",
+ colorFilter: ColorFilter.mode(
+ HMSThemeColors.baseWhite,
+ BlendMode.srcIn),
+ );
+ }),
+ ),
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 16.0),
+ child: InkWell(
+ onTap: () =>
+ {HMSHLSPlayerController.seekForward(seconds: 10)},
+ child: SvgPicture.asset(
+ "packages/hms_room_kit/lib/src/assets/icons/seek_forward.svg",
+ colorFilter: ColorFilter.mode(
+ HMSThemeColors.baseWhite, BlendMode.srcIn),
+ ),
+ ),
+ ),
+ ],
+ )
+ : const SizedBox();
+ });
+ }
+}
diff --git a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_page.dart b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_page.dart
index 7b778d983..fd229d60f 100644
--- a/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_page.dart
+++ b/packages/hms_room_kit/lib/src/hls_viewer/hls_viewer_page.dart
@@ -70,6 +70,8 @@ class _HLSViewerPageState extends State {
void deactivate() {
HMSHLSPlayerController.removeHMSHLSPlaybackEventsListener(
context.read());
+ context.read().setHLSPlayerStats(false);
+ context.read().cancelTimer();
super.deactivate();
}
@@ -104,6 +106,7 @@ class _HLSViewerPageState extends State {
: SafeArea(
child: Scaffold(
backgroundColor: HMSThemeColors.backgroundDim,
+ resizeToAvoidBottomInset: false,
body: Theme(
data: ThemeData(
brightness: Brightness.dark,
@@ -125,33 +128,54 @@ class _HLSViewerPageState extends State {
selector: (_, hlsPlayerStore) =>
hlsPlayerStore.isFullScreen,
builder: (_, isFullScreen, __) {
- double widgetHeight = height -
- MediaQuery.of(context)
- .viewPadding
- .top -
- MediaQuery.of(context)
- .viewPadding
- .bottom;
- return Column(
- mainAxisAlignment:
- isFullScreen
- ? MainAxisAlignment
- .center
- : MainAxisAlignment
- .start,
- children: [
- ///Renders HLS Player
- SizedBox(
- width: width,
- height: isFullScreen
- ? widgetHeight
- : widgetHeight * 0.27,
- child: const HLSPlayer(),
- ),
- if (!isFullScreen)
- HLSPlayerDesktopControls()
- ],
- );
+ return OrientationBuilder(
+ builder:
+ (context, orientation) {
+ return orientation ==
+ Orientation.portrait
+ ? Column(
+ mainAxisAlignment:
+ isFullScreen
+ ? MainAxisAlignment
+ .center
+ : MainAxisAlignment
+ .start,
+ children: [
+ ///Renders HLS Player
+ Expanded(
+ flex: 1,
+ child:
+ const HLSPlayer(),
+ ),
+ if (!isFullScreen)
+ Expanded(
+ flex: 3,
+ child:
+ HLSPlayerDesktopControls(
+ orientation:
+ orientation,
+ ),
+ )
+ ],
+ )
+ : Row(
+ children: [
+ ///Renders HLS Player
+ Expanded(
+ flex: 2,
+ child:
+ const HLSPlayer(),
+ ),
+ if (!isFullScreen)
+ Expanded(
+ flex: 1,
+ child: HLSPlayerDesktopControls(
+ orientation:
+ orientation),
+ )
+ ],
+ );
+ });
});
}),
diff --git a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart
index c205caf92..95a80691a 100644
--- a/packages/hms_room_kit/lib/src/meeting/meeting_store.dart
+++ b/packages/hms_room_kit/lib/src/meeting/meeting_store.dart
@@ -150,7 +150,7 @@ class MeetingStore extends ChangeNotifier
MeetingMode meetingMode = MeetingMode.activeSpeakerWithInset;
- bool isLandscapeLocked = false;
+ bool isScreenRotationAllowed = false;
bool isMessageInfoShown = true;
@@ -857,7 +857,9 @@ class MeetingStore extends ChangeNotifier
addPeer(localPeer!);
if (HMSRoomLayout
.roleLayoutData?.screens?.conferencing?.hlsLiveStreaming !=
- null) isHLSLink = true;
+ null) {
+ isHLSLink = true;
+ }
index = peerTracks
.indexWhere((element) => element.uid == "${each.peerId}mainVideo");
if (each.videoTrack != null) {
@@ -1343,7 +1345,7 @@ class MeetingStore extends ChangeNotifier
_hmsSessionStore = null;
peerTracks.clear();
isRoomEnded = true;
- resetForegroundTaskAndOrientation();
+ resetOrientation();
for (var element in viewControllers) {
element.disposeTextureView();
@@ -1359,8 +1361,8 @@ class MeetingStore extends ChangeNotifier
notifyListeners();
}
- void resetForegroundTaskAndOrientation() {
- setLandscapeLock(false);
+ void resetOrientation() {
+ allowScreenRotation(false);
}
// void clearPIPState() {
@@ -1519,14 +1521,18 @@ class MeetingStore extends ChangeNotifier
}
}
- void setLandscapeLock(bool value) {
- if (value) {
- SystemChrome.setPreferredOrientations(
- [DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft]);
+ void allowScreenRotation(bool allowRotation) {
+ if (allowRotation) {
+ SystemChrome.setPreferredOrientations([
+ DeviceOrientation.landscapeRight,
+ DeviceOrientation.landscapeLeft,
+ DeviceOrientation.portraitUp,
+ DeviceOrientation.portraitDown
+ ]);
} else {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
}
- isLandscapeLocked = value;
+ isScreenRotationAllowed = allowRotation;
notifyListeners();
}
@@ -2894,4 +2900,9 @@ class MeetingStore extends ChangeNotifier
break;
}
}
+
+ @override
+ void onCues({required List subtitles}) {
+ // TODO: implement onCues
+ }
}
diff --git a/packages/hms_room_kit/lib/src/meeting_screen_controller.dart b/packages/hms_room_kit/lib/src/meeting_screen_controller.dart
index 7a98943a5..5dc70ce02 100644
--- a/packages/hms_room_kit/lib/src/meeting_screen_controller.dart
+++ b/packages/hms_room_kit/lib/src/meeting_screen_controller.dart
@@ -126,6 +126,18 @@ class _MeetingScreenControllerState extends State {
_meetingStore.setSettings();
}
+ void setScreenRotation() {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ if (HMSRoomLayout
+ .roleLayoutData?.screens?.conferencing?.hlsLiveStreaming !=
+ null) {
+ _meetingStore.allowScreenRotation(true);
+ } else {
+ _meetingStore.allowScreenRotation(false);
+ }
+ });
+ }
+
@override
Widget build(BuildContext context) {
return showLoader
@@ -136,6 +148,7 @@ class _MeetingScreenControllerState extends State {
selector: (_, meetingStore) =>
meetingStore.localPeer?.role.name,
builder: (_, data, __) {
+ setScreenRotation();
return (HMSRoomLayout.roleLayoutData?.screens?.conferencing
?.hlsLiveStreaming !=
null)
diff --git a/packages/hms_room_kit/lib/src/preview/preview_page.dart b/packages/hms_room_kit/lib/src/preview/preview_page.dart
index 1bd588901..08531289b 100644
--- a/packages/hms_room_kit/lib/src/preview/preview_page.dart
+++ b/packages/hms_room_kit/lib/src/preview/preview_page.dart
@@ -62,6 +62,9 @@ class _PreviewPageState extends State {
bool isRoomMute = previewStore.isRoomMute;
HMSAudioDevice currentAudioDeviceMode = previewStore.currentAudioDeviceMode;
+ if (nameController.text.trim().isEmpty) {
+ return;
+ }
previewStore.removePreviewListener();
Navigator.of(context).pushReplacement(MaterialPageRoute(
@@ -271,9 +274,14 @@ class _PreviewPageState extends State {
textController:
nameController,
width: width * 0.38,
- onPressed: () =>
- _navigateToMeeting(
- previewStore),
+ onPressed: () {
+ nameController.text
+ .trim()
+ .isEmpty
+ ? null
+ : _navigateToMeeting(
+ previewStore);
+ },
childWidget:
PreviewJoinButton(
isEmpty: nameController.text
diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart
index d7d66bf06..457bfab82 100644
--- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart
+++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/chat_bottom_sheet.dart
@@ -1,7 +1,7 @@
+library;
+
//Package imports
import 'package:flutter/material.dart';
-import 'package:hms_room_kit/src/hls_viewer/hls_hand_raise_menu.dart';
-import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
@@ -11,13 +11,14 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart';
import 'package:hms_room_kit/src/widgets/chat_widgets/hms_empty_chat_widget.dart';
import 'package:hms_room_kit/src/widgets/common_widgets/message_container.dart';
import 'package:hms_room_kit/src/meeting/meeting_store.dart';
-import 'package:hms_room_kit/src/widgets/chat_widgets/chat_text_field.dart';
import 'package:hms_room_kit/src/widgets/chat_widgets/pin_chat_widget.dart';
import 'package:hms_room_kit/hms_room_kit.dart';
import 'package:hms_room_kit/src/widgets/chat_widgets/recipient_selector_chip.dart';
import 'package:hms_room_kit/src/widgets/toasts/hms_error_toast.dart';
import 'package:hms_room_kit/src/widgets/toasts/hms_toast_model.dart';
import 'package:hms_room_kit/src/widgets/toasts/hms_toasts_type.dart';
+import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart';
+import 'package:hms_room_kit/src/widgets/chat_widgets/chat_text_utility.dart';
///[ChatBottomSheet] is a bottom sheet that is used to render the bottom sheet for chat
class ChatBottomSheet extends StatefulWidget {
@@ -29,7 +30,6 @@ class ChatBottomSheet extends StatefulWidget {
}
class _ChatBottomSheetState extends State {
- late double widthOfScreen;
String currentlySelectedValue = "Choose a Recipient";
String? currentlySelectedpeerId;
@@ -50,10 +50,15 @@ class _ChatBottomSheetState extends State {
void _scrollToEnd() {
if (_scrollController.hasClients) {
- WidgetsBinding.instance.addPostFrameCallback((_) => _scrollController
- .animateTo(_scrollController.position.maxScrollExtent,
- duration: const Duration(milliseconds: 200),
- curve: Curves.easeInOut));
+ WidgetsBinding.instance.addPostFrameCallback((_) => {
+ if (_scrollController.positions.isNotEmpty)
+ {
+ _scrollController.animateTo(
+ _scrollController.position.maxScrollExtent,
+ duration: const Duration(milliseconds: 200),
+ curve: Curves.easeInOut)
+ }
+ });
}
}
@@ -104,8 +109,6 @@ class _ChatBottomSheetState extends State {
@override
Widget build(BuildContext context) {
- widthOfScreen = MediaQuery.of(context).size.width;
-
return WillPopScope(
onWillPop: () async {
context.read().setNewMessageFalse();
@@ -152,10 +155,13 @@ class _ChatBottomSheetState extends State {
child: const HMSEmptyChatWidget())))
: Expanded(
child: Column(children: [
- const PinChatWidget(),
+ Expanded(
+ flex: 1,
+ child: const PinChatWidget()),
/// List containing chats
Expanded(
+ flex: 3,
child: SingleChildScrollView(
reverse: true,
child: Column(
@@ -194,31 +200,8 @@ class _ChatBottomSheetState extends State {
currentlySelectedValue: currentlySelectedValue,
updateSelectedValue: _updateValueChoose),
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- ///Text Field
- if ((HMSRoomLayout.chatData?.isPrivateChatEnabled ??
- false) ||
- (HMSRoomLayout.chatData?.isPublicChatEnabled ??
- false) ||
- (HMSRoomLayout
- .chatData?.rolesWhitelist.isNotEmpty ??
- false))
- Expanded(
- child: Row(
- children: [
- ChatTextField(
- sendMessage: sendMessage,
- isHLSChat: widget.isHLSChat,
- ),
- ],
- ),
- ),
- if (widget.isHLSChat) HLSHandRaiseMenu()
- ],
- )
+ ChatTextUtility(
+ sendMessage: sendMessage, isHLSChat: widget.isHLSChat)
],
),
),
diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/end_service_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/end_service_bottom_sheet.dart
index 54e89f46a..6e7819beb 100644
--- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/end_service_bottom_sheet.dart
+++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/end_service_bottom_sheet.dart
@@ -55,7 +55,9 @@ class _EndServiceBottomSheetState extends State {
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
- heightFactor: 0.25,
+ heightFactor: MediaQuery.of(context).orientation == Orientation.portrait
+ ? 0.25
+ : 0.45,
child: Padding(
padding: const EdgeInsets.only(top: 16.0, left: 20, right: 20),
child: SingleChildScrollView(
diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart
index fbafaa443..df5b53833 100644
--- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart
+++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/participants_bottom_sheet.dart
@@ -1,6 +1,6 @@
-///Dart imports
library;
+///Dart imports
import 'dart:async';
import 'dart:convert';
import 'dart:developer';
@@ -272,8 +272,7 @@ class _ParticipantsBottomSheetState extends State {
),
if (mutePermission &&
peerTrackNode != null &&
- !peerTrackNode.peer.isLocal &&
- peerTrackNode.peer.type == HMSPeerType.regular)
+ !peerTrackNode.peer.isLocal)
PopupMenuItem(
value: 4,
child: Row(children: [
diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart
index 2e1b6f244..30e5525cb 100644
--- a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart
+++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/remote_peer_bottom_sheet.dart
@@ -1,6 +1,6 @@
-///Package imports
library;
+///Package imports
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
@@ -159,8 +159,7 @@ class _RemotePeerBottomSheetState extends State {
// textColor: HMSThemeColors.onSurfaceHighEmphasis)),
if ((widget.meetingStore.localPeer?.role.permissions.mute ??
- false) &&
- widget.peerTrackNode.peer.type == HMSPeerType.regular)
+ false))
ListTile(
horizontalTitleGap: 2,
onTap: () async {
diff --git a/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_field.dart b/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_field.dart
index 30fbdc3c8..ea56e4814 100644
--- a/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_field.dart
+++ b/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_field.dart
@@ -1,6 +1,6 @@
-///Dart imports
library;
+///Dart imports
import 'dart:math' as math;
///Package imports
@@ -27,8 +27,8 @@ class ChatTextField extends StatefulWidget {
const ChatTextField(
{Key? key,
required this.sendMessage,
- this.toastBackgroundColor,
- this.isHLSChat = false})
+ this.isHLSChat = false,
+ this.toastBackgroundColor})
: super(key: key);
@override
@@ -52,10 +52,8 @@ class _ChatTextFieldState extends State {
@override
Widget build(BuildContext context) {
- double width = MediaQuery.of(context).size.width - 32;
return SizedBox(
height: 40,
- width: widget.isHLSChat ? width * 0.7 : width,
child: Selector>>(
///item1: whether chat is resumed or not
diff --git a/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_utility.dart b/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_utility.dart
new file mode 100644
index 000000000..e1212e41f
--- /dev/null
+++ b/packages/hms_room_kit/lib/src/widgets/chat_widgets/chat_text_utility.dart
@@ -0,0 +1,102 @@
+library;
+
+///Dart imports
+import 'dart:io';
+
+///Package imports
+import 'package:flutter/material.dart';
+
+///Project imports
+import 'package:hms_room_kit/src/hls_viewer/hls_hand_raise_menu.dart';
+import 'package:hms_room_kit/src/layout_api/hms_room_layout.dart';
+import 'package:hms_room_kit/src/layout_api/hms_theme_colors.dart';
+import 'package:hms_room_kit/src/widgets/chat_widgets/chat_text_field.dart';
+import 'package:hms_room_kit/src/widgets/common_widgets/hms_subheading_text.dart';
+
+///[ChatTextUtility] is a utility widget that renders the chat text field and hand raise menu
+class ChatTextUtility extends StatefulWidget {
+ final Function sendMessage;
+ final bool isHLSChat;
+
+ const ChatTextUtility(
+ {super.key, required this.sendMessage, required this.isHLSChat});
+
+ @override
+ State createState() => _ChatTextUtilityState();
+}
+
+class _ChatTextUtilityState extends State
+ with WidgetsBindingObserver {
+ bool showMenu = true;
+
+ @override
+ void initState() {
+ super.initState();
+ WidgetsBinding.instance.addObserver(this);
+ }
+
+ @override
+ void dispose() {
+ WidgetsBinding.instance.removeObserver(this);
+ super.dispose();
+ }
+
+ @override
+ void didChangeMetrics() {
+ final bool isKeyboardOpen =
+ (MediaQuery.of(context).viewInsets.bottom).toInt() > 0;
+ if (Platform.isAndroid) {
+ showMenu = isKeyboardOpen;
+ } else {
+ showMenu = !isKeyboardOpen;
+ }
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ if (HMSRoomLayout.chatData == null)
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(right: 8.0),
+ child: Container(
+ decoration: BoxDecoration(
+ color: HMSThemeColors.surfaceDefault,
+ borderRadius: BorderRadius.circular(8),
+ ),
+ height: 40,
+ child: Padding(
+ padding: const EdgeInsets.only(top: 8.0, bottom: 8, left: 8),
+ child: HMSSubheadingText(
+ text: "Chat disabled.",
+ textColor: HMSThemeColors.onSurfaceLowEmphasis),
+ ),
+ ),
+ ),
+ ),
+
+ ///Text Field
+ if ((HMSRoomLayout.chatData?.isPrivateChatEnabled ?? false) ||
+ (HMSRoomLayout.chatData?.isPublicChatEnabled ?? false) ||
+ (HMSRoomLayout.chatData?.rolesWhitelist.isNotEmpty ?? false))
+ Expanded(
+ child: Row(
+ children: [
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.only(right: 8.0),
+ child: ChatTextField(sendMessage: widget.sendMessage),
+ ),
+ ),
+ ],
+ ),
+ ),
+ if (widget.isHLSChat && showMenu) HLSHandRaiseMenu()
+ ],
+ );
+ }
+}
diff --git a/packages/hms_room_kit/lib/src/widgets/chat_widgets/pin_chat_widget.dart b/packages/hms_room_kit/lib/src/widgets/chat_widgets/pin_chat_widget.dart
index efff9f9a1..3f209a2b7 100644
--- a/packages/hms_room_kit/lib/src/widgets/chat_widgets/pin_chat_widget.dart
+++ b/packages/hms_room_kit/lib/src/widgets/chat_widgets/pin_chat_widget.dart
@@ -1,6 +1,6 @@
-///Package imports
library;
+///Package imports
import 'package:dots_indicator/dots_indicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
@@ -28,6 +28,7 @@ class _PinChatWidgetState extends State {
int currentPage = 0;
PageController? _pageController;
bool isExpanded = false;
+ double height = 0, containerHeight = 0, dotsHeight = 0;
@override
void initState() {
@@ -51,7 +52,22 @@ class _PinChatWidgetState extends State {
});
}
+ @override
+ void didChangeDependencies() {
+ super.didChangeDependencies();
+ height = MediaQuery.of(context).size.height;
+ containerHeight = height * 0.09;
+ dotsHeight = containerHeight * 0.5;
+ }
+
void toggleExpand() {
+ if (isExpanded) {
+ containerHeight = height * 0.09;
+ dotsHeight = containerHeight * 0.5;
+ } else {
+ containerHeight = height * 0.12;
+ dotsHeight = containerHeight * 0.5;
+ }
setState(() {
isExpanded = !isExpanded;
});
@@ -73,94 +89,99 @@ class _PinChatWidgetState extends State {
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
- AnimatedContainer(
- height: MediaQuery.of(context).size.height *
- (isExpanded ? 0.13 : 0.09),
- width:
- (HMSRoomLayout.chatData?.allowPinningMessages ??
- false)
- ? MediaQuery.of(context).size.width * 0.83
- : MediaQuery.of(context).size.width * 0.9,
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(8),
- color: widget.backgroundColor ??
- HMSThemeColors.surfaceDefault),
- duration: const Duration(milliseconds: 0),
- child: Padding(
- padding: const EdgeInsets.all(8.0),
+ Expanded(
+ child: AnimatedContainer(
+ height: containerHeight,
+ decoration: BoxDecoration(
+ borderRadius: BorderRadius.circular(8),
+ color: widget.backgroundColor ??
+ HMSThemeColors.surfaceDefault),
+ duration: const Duration(milliseconds: 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
- crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (data.item2 > 1)
- DotsIndicator(
- axis: Axis.vertical,
- mainAxisSize: MainAxisSize.min,
- dotsCount: data.item2,
- position: currentPage >= data.item2
- ? 0
- : currentPage,
- decorator: DotsDecorator(
- spacing: const EdgeInsets.only(
- bottom: 3.0, right: 8),
- size: Size(2.0, isExpanded ? 24 : 9.0),
- activeSize:
- Size(2.0, isExpanded ? 24 : 9.0),
- color:
- HMSThemeColors.onSurfaceLowEmphasis,
- activeColor:
- HMSThemeColors.onSurfaceHighEmphasis,
- activeShape: RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(16.0)),
- shape: RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(16.0)),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 8.0, top: 2, bottom: 2),
+ child: SingleChildScrollView(
+ physics: NeverScrollableScrollPhysics(),
+ child: DotsIndicator(
+ axis: Axis.vertical,
+ mainAxisSize: MainAxisSize.max,
+ dotsCount: data.item2,
+ position: currentPage >= data.item2
+ ? 0
+ : currentPage,
+ decorator: DotsDecorator(
+ spacing: const EdgeInsets.only(
+ bottom: 3.0, right: 8),
+ size: Size(
+ 2.0, dotsHeight / data.item2),
+ activeSize: Size(
+ 2.0, dotsHeight / data.item2),
+ color: HMSThemeColors
+ .onSurfaceLowEmphasis,
+ activeColor: HMSThemeColors
+ .onSurfaceHighEmphasis,
+ activeShape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.circular(16.0)),
+ shape: RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.circular(16.0)),
+ ),
+ onTap: (position) =>
+ setCurrentPage(position),
+ ),
),
- onTap: (position) =>
- setCurrentPage(position),
),
Expanded(
- child: PageView.builder(
- scrollDirection: Axis.vertical,
- controller: _pageController,
- itemCount: data.item2,
- physics: const PageScrollPhysics(),
- onPageChanged: (value) =>
- setCurrentPage(value),
- itemBuilder: (context, index) =>
- SelectableLinkify(
- maxLines: 3,
- scrollPhysics: isExpanded
- ? const BouncingScrollPhysics()
- : const NeverScrollableScrollPhysics(),
- text: data.item1[index]["text"],
- onOpen: (link) async {
- Uri url = Uri.parse(link.url);
- if (await canLaunchUrl(url)) {
- await launchUrl(url,
- mode: LaunchMode
- .externalApplication);
- }
- },
- onTap: () => toggleExpand(),
- options:
- const LinkifyOptions(humanize: false),
- style: HMSTextStyle.setTextStyle(
- fontSize: 14.0,
- color: HMSThemeColors
- .onSurfaceHighEmphasis,
- letterSpacing: 0.25,
- height: 20 / 14,
- fontWeight: FontWeight.w400,
- ),
- linkStyle: HMSTextStyle.setTextStyle(
+ child: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: PageView.builder(
+ scrollDirection: Axis.vertical,
+ controller: _pageController,
+ itemCount: data.item2,
+ physics: const PageScrollPhysics(),
+ onPageChanged: (value) =>
+ setCurrentPage(value),
+ itemBuilder: (context, index) =>
+ SelectableLinkify(
+ maxLines: 3,
+ scrollPhysics: isExpanded
+ ? const BouncingScrollPhysics()
+ : const NeverScrollableScrollPhysics(),
+ text: data.item1[index]["text"],
+ onOpen: (link) async {
+ Uri url = Uri.parse(link.url);
+ if (await canLaunchUrl(url)) {
+ await launchUrl(url,
+ mode: LaunchMode
+ .externalApplication);
+ }
+ },
+ onTap: () => toggleExpand(),
+ options: const LinkifyOptions(
+ humanize: false),
+ style: HMSTextStyle.setTextStyle(
fontSize: 14.0,
- color: HMSThemeColors.primaryDefault,
+ color: HMSThemeColors
+ .onSurfaceHighEmphasis,
letterSpacing: 0.25,
height: 20 / 14,
- fontWeight: FontWeight.w400),
+ fontWeight: FontWeight.w400,
+ ),
+ linkStyle: HMSTextStyle.setTextStyle(
+ fontSize: 14.0,
+ color:
+ HMSThemeColors.primaryDefault,
+ letterSpacing: 0.25,
+ height: 20 / 14,
+ fontWeight: FontWeight.w400),
+ ),
),
),
),
@@ -168,7 +189,6 @@ class _PinChatWidgetState extends State {
),
),
),
- const SizedBox(width: 8),
if (HMSRoomLayout.chatData?.allowPinningMessages ??
false)
GestureDetector(
diff --git a/packages/hms_room_kit/pubspec.lock b/packages/hms_room_kit/pubspec.lock
index 00f594ef4..287ab5d9f 100644
--- a/packages/hms_room_kit/pubspec.lock
+++ b/packages/hms_room_kit/pubspec.lock
@@ -188,10 +188,10 @@ packages:
dependency: "direct main"
description:
name: hmssdk_flutter
- sha256: "88673b9ddd7eaa2e997976a4386374b0881b4485f4ba750689d3c9ca25032f65"
+ sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376
url: "https://pub.dev"
source: hosted
- version: "1.10.0"
+ version: "1.10.1"
http:
dependency: transitive
description:
diff --git a/packages/hms_room_kit/pubspec.yaml b/packages/hms_room_kit/pubspec.yaml
index e54935c4f..c9ffea667 100644
--- a/packages/hms_room_kit/pubspec.yaml
+++ b/packages/hms_room_kit/pubspec.yaml
@@ -1,6 +1,6 @@
name: hms_room_kit
description: 100ms Room Kit provides simple & easy to use UI components to build Live Streaming & Video Conferencing experiences in your apps.
-version: 1.1.0
+version: 1.1.1
homepage: https://www.100ms.live/
repository: https://github.com/100mslive/100ms-flutter
issue_tracker: https://github.com/100mslive/100ms-flutter/issues
@@ -14,7 +14,7 @@ dependencies:
flutter:
sdk: flutter
- hmssdk_flutter: 1.10.0
+ hmssdk_flutter: 1.10.1
intl: ^0.18.0
permission_handler: ^11.0.0
provider: ^6.0.5
diff --git a/packages/hmssdk_flutter/CHANGELOG.md b/packages/hmssdk_flutter/CHANGELOG.md
index af4cb0bed..eefddafd3 100644
--- a/packages/hmssdk_flutter/CHANGELOG.md
+++ b/packages/hmssdk_flutter/CHANGELOG.md
@@ -5,7 +5,25 @@
| hms_room_kit | [![Pub Version](https://img.shields.io/pub/v/hms_room_kit)](https://pub.dev/packages/hms_room_kit) |
| hmssdk_flutter | [![Pub Version](https://img.shields.io/pub/v/hmssdk_flutter)](https://pub.dev/packages/hmssdk_flutter) |
-# 1.10.0 - 2024-04-19
+# 1.10.1 - 2024-04-26
+
+| Package | Version |
+| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
+| hms_room_kit | 1.1.1 |
+| hmssdk_flutter | 1.10.1 |
+
+### ✨ Added
+
+- Support for captions in HLS Player
+
+ HMSSDK now provides support for captions in HLS Player. You can now `enable` or `disable` captions in the HLS Player using the
+ `HMSHLSPlayerController` methods. Moreover HMSSDK provides a new `onCues` callback to get captions. Learn more about it [here](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player#how-to-enabledisable-captions)
+
+Uses Android SDK 2.9.54 & iOS SDK 1.9.0
+
+**Full Changelog**: [1.10.0...1.10.1](https://github.com/100mslive/100ms-flutter/compare/1.10.0...1.10.1)
+
+# 1.10.0 - 2024-04-22
| Package | Version |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSVariantExtension.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSVariantExtension.kt
index 7b8ff793d..62e1ce40e 100644
--- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSVariantExtension.kt
+++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HMSHLSVariantExtension.kt
@@ -1,5 +1,6 @@
package live.hms.hmssdk_flutter
+import live.hms.video.sdk.models.HMSHLSPlaylistType
import live.hms.video.sdk.models.HMSHLSVariant
class HMSHLSVariantExtension {
@@ -13,7 +14,23 @@ class HMSHLSVariantExtension {
hmshlsVariant.startedAt?.let {
args["started_at"] = it
}
+ args["playlist_type"] = getHMSHLSVariantToString(hmshlsVariant.playlistType)
return args
}
+
+ private fun getHMSHLSVariantToString(hmsHlsVariantType: HMSHLSPlaylistType?): String{
+
+ return when(hmsHlsVariantType){
+ HMSHLSPlaylistType.dvr -> {
+ "dvr"
+ }
+ HMSHLSPlaylistType.noDVR -> {
+ "noDvr"
+ }
+ else -> {
+ "noDvr"
+ }
+ }
+ }
}
}
diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt
index 6c7ff934b..d1dc5b060 100644
--- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt
+++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/HmssdkFlutterPlugin.kt
@@ -252,7 +252,7 @@ class HmssdkFlutterPlugin :
"remove_key_change_listener" -> {
removeKeyChangeListener(call, result)
}
- "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions" -> {
+ "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties" -> {
HMSHLSPlayerAction.hlsPlayerAction(call, result)
}
"toggle_always_screen_on" -> {
diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt
index 5cac07bb0..55fb06fce 100644
--- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt
+++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/HMSHLSPlayerAction.kt
@@ -31,6 +31,7 @@ class HMSHLSPlayerAction {
"are_closed_captions_supported" -> areClosedCaptionsSupported(result)
"enable_closed_captions" -> enableClosedCaptions(result)
"disable_closed_captions" -> disableClosedCaptions(result)
+ "get_stream_properties" -> getStreamProperties(result)
else -> {
result.notImplemented()
}
@@ -54,7 +55,7 @@ class HMSHLSPlayerAction {
val hlsUrl = call.argument("hls_url")
hlsActions?.let {
it.get()?.start(hlsUrl, result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("start", "hlsActions is NULL", "NULL Error")
}
}
@@ -67,7 +68,7 @@ class HMSHLSPlayerAction {
private fun stop(result: Result) {
hlsActions?.let {
it.get()?.stop(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("stop", "hlsActions is NULL", "NULL Error")
}
}
@@ -80,7 +81,7 @@ class HMSHLSPlayerAction {
private fun pause(result: Result) {
hlsActions?.let {
it.get()?.pause(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("pause", "hlsActions is NULL", "NULL Error")
}
}
@@ -93,7 +94,7 @@ class HMSHLSPlayerAction {
private fun resume(result: Result) {
hlsActions?.let {
it.get()?.resume(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("resume", "hlsActions is NULL", "NULL Error")
}
}
@@ -106,7 +107,7 @@ class HMSHLSPlayerAction {
private fun seekToLivePosition(result: Result) {
hlsActions?.let {
it.get()?.seekToLivePosition(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("seekToLivePosition", "hlsActions is NULL", "NULL Error")
}
}
@@ -128,9 +129,9 @@ class HMSHLSPlayerAction {
}
seconds?.let {
- hlsActions?.let {_hlsActions ->
+ hlsActions?.let { _hlsActions ->
_hlsActions.get()?.seekForward(it, result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("seekForward", "hlsActions is NULL", "NULL Error")
}
}
@@ -155,7 +156,7 @@ class HMSHLSPlayerAction {
seconds?.let {
hlsActions?.let { _hlsActions ->
_hlsActions.get()?.seekBackward(it, result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("seekBackward", "hlsActions is NULL", "NULL Error")
}
}
@@ -178,9 +179,9 @@ class HMSHLSPlayerAction {
}
volume?.let {
- hlsActions?.let {_hlsActions ->
- _hlsActions.get()?.setVolume(it,result)
- }?:run{
+ hlsActions?.let { _hlsActions ->
+ _hlsActions.get()?.setVolume(it, result)
+ } ?: run {
HMSErrorLogger.logError("setVolume", "hlsActions is NULL", "NULL Error")
}
}
@@ -192,10 +193,9 @@ class HMSHLSPlayerAction {
* @param result The result object to be returned after adding the HLS stats listener.
*/
private fun addHLSStatsListener(result: Result) {
-
hlsActions?.let {
it.get()?.addHLSStatsListener(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("addHLSStatsListener", "hlsActions is NULL", "NULL Error")
}
}
@@ -208,7 +208,7 @@ class HMSHLSPlayerAction {
private fun removeHLSStatsListener(result: Result) {
hlsActions?.let {
it.get()?.removeHLSStatsListener(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("removeHLSStatsListener", "hlsActions is NULL", "NULL Error")
}
}
@@ -222,7 +222,7 @@ class HMSHLSPlayerAction {
private fun areClosedCaptionsSupported(result: Result) {
hlsActions?.let {
it.get()?.areClosedCaptionsSupported(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("areClosedCaptionsSupported", "hlsActions is NULL", "NULL Error")
}
}
@@ -235,7 +235,7 @@ class HMSHLSPlayerAction {
private fun enableClosedCaptions(result: Result) {
hlsActions?.let {
it.get()?.enableClosedCaptions(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("enableClosedCaptions", "hlsActions is NULL", "NULL Error")
}
}
@@ -248,9 +248,17 @@ class HMSHLSPlayerAction {
private fun disableClosedCaptions(result: Result) {
hlsActions?.let {
it.get()?.disableClosedCaptions(result)
- }?:run{
+ } ?: run {
HMSErrorLogger.logError("disableClosedCaptions", "hlsActions is NULL", "NULL Error")
}
}
+
+ private fun getStreamProperties(result:Result){
+ hlsActions?.let {
+ it.get()?.getStreamProperties(result)
+ } ?: run {
+ HMSErrorLogger.logError("getStreamProperties", "hlsActions is NULL", "NULL Error")
+ }
+ }
}
}
diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt
index 4a3b20ef1..86bf25099 100644
--- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt
+++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/hls_player/IHLSPlayerActionInterface.kt
@@ -45,4 +45,6 @@ interface IHLSPlayerActionInterface {
fun enableClosedCaptions(result: Result)
fun disableClosedCaptions(result: Result)
+
+ fun getStreamProperties(result: Result)
}
diff --git a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt
index 727956d47..9cdb44355 100644
--- a/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt
+++ b/packages/hmssdk_flutter/android/src/main/kotlin/live/hms/hmssdk_flutter/views/HMSHLSPlayer.kt
@@ -2,6 +2,7 @@ package live.hms.hmssdk_flutter.views
import android.content.Context
import android.view.LayoutInflater
+import android.view.View
import android.widget.FrameLayout
import androidx.media3.common.Player
import androidx.media3.common.VideoSize
@@ -40,7 +41,7 @@ class HMSHLSPlayer(
var hlsPlayer: HmsHlsPlayer? = null
private var hlsPlayerView: PlayerView? = null
private var actions: IHLSPlayerActionInterface? = null
-
+ private var areCaptionsEnabled = false
/**
* Inflate the HLS player view and initialize the HLS player.
* Set the HLS player view and player if the inflation is successful.
@@ -75,6 +76,10 @@ class HMSHLSPlayer(
// Set the native player of the HLS player view.
it.player = hlsPlayer?.getNativePlayer()
+ ///Hiding Subtitles
+ if(!showHLSControls){
+ it.subtitleView?.visibility = View.GONE
+ }
it.player?.addListener(
object : Player.Listener {
override fun onSurfaceSizeChanged(
@@ -115,6 +120,23 @@ class HMSHLSPlayer(
}
override fun onCues(cueGroup: CueGroup) {
+ if(areCaptionsEnabled){
+ val hashMap = HashMap()
+ val args = HashMap()
+
+ hashMap["event_name"] = "on_cues"
+ val cues = ArrayList()
+ cueGroup.cues.forEach {_cues ->
+ _cues.text?.let { cue ->
+ cues.add(cue.toString())
+ }
+ }
+ args["subtitles"] = cues
+ hashMap["data"] = args
+ CoroutineScope(Dispatchers.Main).launch {
+ hmssdkFlutterPlugin?.hlsPlayerSink?.success(hashMap)
+ }
+ }
super.onCues(cueGroup)
}
},
@@ -242,6 +264,10 @@ class HMSHLSPlayer(
}
}
+ private fun areClosedCaptionSupported(): Boolean{
+ return hlsPlayer?.areClosedCaptionsSupported()?:false
+ }
+
/**
* This handles the method call from flutter channel
* and return the values
@@ -325,16 +351,33 @@ class HMSHLSPlayer(
}
override fun areClosedCaptionsSupported(result: Result) {
- val areCaptionsSupported = hlsPlayer?.areClosedCaptionsSupported()
+ val areCaptionsSupported = areClosedCaptionSupported()
result.success(areCaptionsSupported)
}
override fun enableClosedCaptions(result: Result) {
- TODO("Not yet implemented")
+ if(areClosedCaptionSupported()){
+ areCaptionsEnabled = true
+ result.success(null)
+ }else{
+ HMSErrorLogger.logError("enableClosedCaptions", "Closed Captions are not supported", "SUPPORT ERROR")
+ result.success(null)
+ }
}
override fun disableClosedCaptions(result: Result) {
- TODO("Not yet implemented")
+ areCaptionsEnabled = false
+ result.success(null)
+ }
+
+ override fun getStreamProperties(result: Result) {
+ val map = HashMap()
+
+ map["rolling_window_time"] =
+ hlsPlayer?.getNativePlayer()?.seekParameters?.toleranceAfterUs?.div(1000000);
+ map["stream_duration"] = hlsPlayer?.getNativePlayer()?.duration?.div(1000)
+
+ result.success(map)
}
}
}
diff --git a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt
index 593ea824a..db9ffb8f0 100644
--- a/packages/hmssdk_flutter/example/ExampleAppChangelog.txt
+++ b/packages/hmssdk_flutter/example/ExampleAppChangelog.txt
@@ -1,34 +1,18 @@
Board: https://100ms.atlassian.net/jira/software/projects/FLUT/boards/34/
-- Added active noise cancellation feature
-https://100ms.atlassian.net/browse/FLUT-259
+- Added Captions in HLS Player
+https://100ms.atlassian.net/browse/FLUT-265
-- Added SIP Peer support
-https://100ms.atlassian.net/browse/FLUT-260
+- Pinch & Zoom on HLS Player
+https://100ms.atlassian.net/browse/FLUT-268
-- Fixed: UI inconsistent when using a Screenshare only Role
-https://100ms.atlassian.net/browse/FLUT-279
+- Full Screen Landscape UI
+https://100ms.atlassian.net/browse/FLUT-269
-- Removed `flutter_foreground_task` from `hms_room_kit`
-https://100ms.atlassian.net/browse/FLUT-280
+- Seek Bar + Go Live Button behaviour (Polling)
+https://100ms.atlassian.net/browse/FLUT-272
-- Main Player UI with Chat below
-https://100ms.atlassian.net/browse/FLUT-262
-
-- Description Pane
-https://100ms.atlassian.net/browse/FLUT-263
-
-- Remove webrtc header and footer + Bottom toolbar from HLS screen
-https://100ms.atlassian.net/browse/FLUT-264
-
-- New Player Controls (Auto hide/overlay)
-https://100ms.atlassian.net/browse/FLUT-266
-
-- Header + Description from Layout API in Description Pane
-https://100ms.atlassian.net/browse/FLUT-271
-
-
-Room Kit: 1.1.0
-Core SDK: 1.10.0
-Android SDK: 2.9.53
-iOS SDK: 1.8.0
\ No newline at end of file
+Room Kit: 1.1.1
+Core SDK: 1.10.1
+Android SDK: 2.9.54
+iOS SDK: 1.9.0
\ No newline at end of file
diff --git a/packages/hmssdk_flutter/example/android/Gemfile.lock b/packages/hmssdk_flutter/example/android/Gemfile.lock
index b491244fd..4e4043c3b 100644
--- a/packages/hmssdk_flutter/example/android/Gemfile.lock
+++ b/packages/hmssdk_flutter/example/android/Gemfile.lock
@@ -15,17 +15,17 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
- aws-partitions (1.913.0)
- aws-sdk-core (3.191.6)
+ aws-partitions (1.916.0)
+ aws-sdk-core (3.192.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.78.0)
+ aws-sdk-kms (1.79.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.146.1)
- aws-sdk-core (~> 3, >= 3.191.0)
+ aws-sdk-s3 (1.147.0)
+ aws-sdk-core (~> 3, >= 3.192.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
@@ -177,7 +177,7 @@ GEM
nanaimo (0.3.0)
naturally (2.2.1)
nkf (0.2.0)
- optparse (0.4.0)
+ optparse (0.5.0)
os (1.1.4)
plist (3.7.1)
public_suffix (5.0.5)
diff --git a/packages/hmssdk_flutter/example/android/app/build.gradle b/packages/hmssdk_flutter/example/android/app/build.gradle
index 9e4879be3..863fc41b4 100644
--- a/packages/hmssdk_flutter/example/android/app/build.gradle
+++ b/packages/hmssdk_flutter/example/android/app/build.gradle
@@ -36,8 +36,8 @@ android {
applicationId "live.hms.flutter"
minSdkVersion 21
targetSdkVersion 34
- versionCode 474
- versionName "1.5.174"
+ versionCode 483
+ versionName "1.5.183"
}
signingConfigs {
diff --git a/packages/hmssdk_flutter/example/ios/Gemfile.lock b/packages/hmssdk_flutter/example/ios/Gemfile.lock
index 59ff0e0e1..85288e6db 100644
--- a/packages/hmssdk_flutter/example/ios/Gemfile.lock
+++ b/packages/hmssdk_flutter/example/ios/Gemfile.lock
@@ -15,17 +15,17 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
- aws-partitions (1.913.0)
- aws-sdk-core (3.191.6)
+ aws-partitions (1.916.0)
+ aws-sdk-core (3.192.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.78.0)
+ aws-sdk-kms (1.79.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.146.1)
- aws-sdk-core (~> 3, >= 3.191.0)
+ aws-sdk-s3 (1.147.0)
+ aws-sdk-core (~> 3, >= 3.192.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
@@ -178,7 +178,7 @@ GEM
nanaimo (0.3.0)
naturally (2.2.1)
nkf (0.2.0)
- optparse (0.4.0)
+ optparse (0.5.0)
os (1.1.4)
plist (3.7.1)
public_suffix (5.0.5)
diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock
index 13f5497b9..64e0f64ba 100644
--- a/packages/hmssdk_flutter/example/ios/Podfile.lock
+++ b/packages/hmssdk_flutter/example/ios/Podfile.lock
@@ -129,16 +129,16 @@ PODS:
- HMSHLSPlayerSDK (0.0.2):
- HMSAnalyticsSDK (= 0.0.2)
- HMSNoiseCancellationModels (1.0.0)
- - HMSSDK (1.8.0):
+ - HMSSDK (1.9.0):
- HMSAnalyticsSDK (= 0.0.2)
- - HMSWebRTC (= 1.0.5118)
+ - HMSWebRTC (= 1.0.6168)
- hmssdk_flutter (1.10.0):
- Flutter
- HMSBroadcastExtensionSDK (= 0.0.9)
- HMSHLSPlayerSDK (= 0.0.2)
- HMSNoiseCancellationModels (= 1.0.0)
- - HMSSDK (= 1.8.0)
- - HMSWebRTC (1.0.5118)
+ - HMSSDK (= 1.9.0)
+ - HMSWebRTC (1.0.6168)
- MLImage (1.0.0-beta4)
- MLKitBarcodeScanning (3.0.0):
- MLKitCommon (~> 9.0)
@@ -299,9 +299,9 @@ SPEC CHECKSUMS:
HMSBroadcastExtensionSDK: d80fe325f6c928bd8e5176290b5a4b7ae15d6fbb
HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3
HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02
- HMSSDK: c893d1381a47ed02760ef6d06625b9aa5251f998
- hmssdk_flutter: 997715f0bedfcb22750fb95549672bf3fea380ff
- HMSWebRTC: 4487c7200f1e9358412c1d8cd974edd2766467dc
+ HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb
+ hmssdk_flutter: 3febf31ba806e9a5ee540fe299c7331fc43135cf
+ HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5
MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b
MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505
MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390
@@ -319,4 +319,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 9fb9f6e431a2c6c79942252e94b241ac7972ac90
-COCOAPODS: 1.15.2
+COCOAPODS: 1.14.3
diff --git a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj
index c6527dce3..457887001 100644
--- a/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/hmssdk_flutter/example/ios/Runner.xcodeproj/project.pbxproj
@@ -793,9 +793,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FlutterBroadcastUploadExtension/FlutterBroadcastUploadExtension.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 185;
- DEVELOPMENT_TEAM = 5N85PP82A9;
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5N85PP82A9;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = x86_64;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -813,7 +815,8 @@
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = live.100ms.flutter.FlutterBroadcastUploadExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = FlutterAppStoreBroadcastUploadExtension;
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = FlutterAppStoreBroadcastUploadExtension;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -834,9 +837,11 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = FlutterBroadcastUploadExtension/FlutterBroadcastUploadExtension.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 185;
- DEVELOPMENT_TEAM = 5N85PP82A9;
+ DEVELOPMENT_TEAM = "";
+ "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 5N85PP82A9;
ENABLE_BITCODE = NO;
EXCLUDED_ARCHS = x86_64;
GCC_C_LANGUAGE_STANDARD = gnu11;
@@ -854,7 +859,8 @@
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = live.100ms.flutter.FlutterBroadcastUploadExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = FlutterAppStoreBroadcastUploadExtension;
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = FlutterAppStoreBroadcastUploadExtension;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
diff --git a/packages/hmssdk_flutter/example/ios/Runner/Info.plist b/packages/hmssdk_flutter/example/ios/Runner/Info.plist
index 4f8b85db3..e5a655037 100644
--- a/packages/hmssdk_flutter/example/ios/Runner/Info.plist
+++ b/packages/hmssdk_flutter/example/ios/Runner/Info.plist
@@ -21,7 +21,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.5.174
+ 1.5.183
CFBundleSignature
????
CFBundleURLTypes
@@ -48,7 +48,7 @@
CFBundleVersion
- 474
+ 483
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock
index c0c11e670..71150e5cd 100644
--- a/packages/hmssdk_flutter/example/pubspec.lock
+++ b/packages/hmssdk_flutter/example/pubspec.lock
@@ -302,15 +302,15 @@ packages:
path: "../../hms_room_kit"
relative: true
source: path
- version: "1.1.0"
+ version: "1.1.1"
hmssdk_flutter:
dependency: transitive
description:
name: hmssdk_flutter
- sha256: "88673b9ddd7eaa2e997976a4386374b0881b4485f4ba750689d3c9ca25032f65"
+ sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376
url: "https://pub.dev"
source: hosted
- version: "1.10.0"
+ version: "1.10.1"
http:
dependency: transitive
description:
diff --git a/packages/hmssdk_flutter/example/pubspec.yaml b/packages/hmssdk_flutter/example/pubspec.yaml
index 836a27fde..7be7095df 100644
--- a/packages/hmssdk_flutter/example/pubspec.yaml
+++ b/packages/hmssdk_flutter/example/pubspec.yaml
@@ -4,7 +4,7 @@ description: Demonstrates how to use the hmssdk_flutter plugin.
# The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages.
publish_to: "none" # Remove this line if you wish to publish to pub.dev
-version: 1.10.0
+version: 1.10.1
environment:
sdk: ">=2.16.0 <4.0.0"
diff --git a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift
index a8726877a..6bb5fac4e 100644
--- a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift
+++ b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift
@@ -57,7 +57,10 @@ class HMSHLSPlayerAction {
case "disable_closed_captions":
disableClosedCaptions(result)
-
+
+ case "get_stream_properties":
+ getStreamProperties(result)
+
default:
result(FlutterMethodNotImplemented)
}
@@ -217,4 +220,8 @@ class HMSHLSPlayerAction {
NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "disable_closed_captions"])
result(nil)
}
+
+ static private func getStreamProperties(_ result: @escaping FlutterResult){
+ NotificationCenter.default.post(name: NSNotification.Name(HLS_PLAYER_METHOD), object: nil, userInfo: [METHOD_CALL: "get_stream_properties", "result": result])
+ }
}
diff --git a/packages/hmssdk_flutter/ios/Classes/Models/HMSHLSVariantExtension.swift b/packages/hmssdk_flutter/ios/Classes/Models/HMSHLSVariantExtension.swift
index 965b9bd34..e9699652d 100644
--- a/packages/hmssdk_flutter/ios/Classes/Models/HMSHLSVariantExtension.swift
+++ b/packages/hmssdk_flutter/ios/Classes/Models/HMSHLSVariantExtension.swift
@@ -27,8 +27,23 @@ class HMSHLSVariantExtension {
if let startedAt = hmshlsVariant.startedAt {
dict["started_at"] = Int(startedAt.timeIntervalSince1970 * 1000)
}
+
+ if let playlistType = hmshlsVariant.playlistType {
+ dict["playlist_type"] = getStringFromHMSHLSPlaylistType(playlistType: playlistType)
+ }
return dict
}
+
+ private static func getStringFromHMSHLSPlaylistType(playlistType: HMSHLSPlaylistType) -> String{
+ switch playlistType{
+ case .dvr:
+ return "dvr"
+ case .noDVR:
+ return "noDvr"
+ default:
+ return "noDvr"
+ }
+ }
}
diff --git a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift
index 5912dde91..67b265427 100644
--- a/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift
+++ b/packages/hmssdk_flutter/ios/Classes/SwiftHmssdkFlutterPlugin.swift
@@ -300,7 +300,7 @@ public class SwiftHmssdkFlutterPlugin: NSObject, FlutterPlugin, HMSUpdateListene
// MARK: - HLS Player
- case "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions":
+ case "start_hls_player", "stop_hls_player", "pause_hls_player", "resume_hls_player", "seek_to_live_position", "seek_forward", "seek_backward", "set_hls_player_volume", "add_hls_stats_listener", "remove_hls_stats_listener", "are_closed_captions_supported", "enable_closed_captions", "disable_closed_captions", "get_stream_properties":
HMSHLSPlayerAction.hlsPlayerAction(call, result)
case "toggle_always_screen_on":
diff --git a/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift b/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift
index a54b0600d..fc86ffa8d 100644
--- a/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift
+++ b/packages/hmssdk_flutter/ios/Classes/Views/HMSHLSPlayerView.swift
@@ -126,6 +126,27 @@ class HMSHLSPlayerView: NSObject, FlutterPlatformView {
// Set the hlsPlayer to nil to release its resources
hlsPlayer = nil
}
+
+ private func areClosedCaptionsSupported() -> Bool{
+ guard let playerItem = hlsPlayer?._nativePlayer.currentItem else {
+ return false
+ }
+
+ guard let availableSubtitleTracks = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else {
+ return false
+ }
+
+ guard let firstOption = availableSubtitleTracks.options.first else {
+ return false
+ }
+
+ if firstOption.mediaType == .subtitle {
+ return true
+ }
+ else {
+ return false
+ }
+ }
/**
* Below methods handles the HLS Player controller calls
@@ -163,37 +184,53 @@ class HMSHLSPlayerView: NSObject, FlutterPlatformView {
case "are_closed_captions_supported":
let result = notification.userInfo?["result"] as? FlutterResult
-
- var isSubtitleToggleShown = false
- guard let playerItem = hlsPlayer?._nativePlayer.currentItem else {
- isSubtitleToggleShown = false
- return
+ result?(areClosedCaptionsSupported())
+
+ case "enable_closed_captions":
+ let result = notification.userInfo?["result"] as? FlutterResult
+ if(areClosedCaptionsSupported()){
+ let player = hlsPlayer?._nativePlayer
+ guard let playerItem = player?.currentItem else {return }
+
+ guard let availableSubtitleTracks = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { return }
+
+ if let firstSubtitle = availableSubtitleTracks.options.first(where: {$0.mediaType == .subtitle}) {
+
+ playerItem.select(firstSubtitle, in: availableSubtitleTracks)
+
+ }
+ }else{
+ HMSErrorLogger.logError("\(#function)", "Closed Captions are not supported", "SUPPORT ERROR")
}
+ result?(nil)
+ case "disable_closed_captions":
+ let result = notification.userInfo?["result"] as? FlutterResult
+ let player = hlsPlayer?._nativePlayer
+ guard let playerItem = player?.currentItem else {return }
- guard let availableSubtitleTracks = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else {
- isSubtitleToggleShown = false
- return
- }
+ guard let availableSubtitleTracks = playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) else { return }
- guard let firstOption = availableSubtitleTracks.options.first else {
- isSubtitleToggleShown = false
- return
+ if let _ = playerItem.currentMediaSelection.selectedMediaOption(in: availableSubtitleTracks) {
+ playerItem.select(nil, in: availableSubtitleTracks)
}
+ result?(nil)
+ case "get_stream_properties":
+ let result = notification.userInfo?["result"] as? FlutterResult
+ let player = hlsPlayer?._nativePlayer
+ guard let playerItem = player?.currentItem else {return }
- if firstOption.mediaType == .subtitle {
- isSubtitleToggleShown = true
- }
- else {
- isSubtitleToggleShown = false
- }
+ var map = [String:Any?]()
- result?(isSubtitleToggleShown)
-
- case "enable_closed_captions":
- break
+ let duration = playerItem.duration
- case "disable_closed_captions":
- break
+ if duration.isIndefinite {
+ guard let timeRange = playerItem.seekableTimeRanges.last as? CMTimeRange else { return }
+
+ map["rolling_window_time"] = timeRange.duration.seconds
+ }else{
+ map["stream_duration"] = duration.seconds
+ }
+ result?(map)
default:
return
diff --git a/packages/hmssdk_flutter/lib/assets/sdk-versions.json b/packages/hmssdk_flutter/lib/assets/sdk-versions.json
index 6737887cb..17f99841f 100644
--- a/packages/hmssdk_flutter/lib/assets/sdk-versions.json
+++ b/packages/hmssdk_flutter/lib/assets/sdk-versions.json
@@ -1,6 +1,6 @@
{
- "flutter": "1.10.0",
- "ios": "1.8.0",
+ "flutter": "1.10.1",
+ "ios": "1.9.0",
"iOSBroadcastExtension": "0.0.9",
"iOSHLSPlayerSDK": "0.0.2",
"iOSNoiseCancellationModels": "1.0.0",
diff --git a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart
index 58bf560c6..0107e3c6a 100644
--- a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart
+++ b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart
@@ -24,6 +24,7 @@ export 'src/enum/hms_audio_mode.dart';
export 'src/enum/hms_hls_playback_state.dart';
export 'src/enum/hms_poll_enum.dart';
export 'src/enum/hms_peer_type.dart';
+export 'src/enum/hms_hls_playlist_type.dart';
//EXCEPTIONS
export 'src/exceptions/hms_exception.dart';
@@ -114,6 +115,7 @@ export 'src/model/polls/hms_poll_leaderboard_response.dart';
export 'src/model/polls/hms_poll_leaderboard_summary.dart';
export 'src/model/polls/hms_poll_peer_info_response.dart';
export 'src/model/hms_noise_cancellation_controller.dart';
+export 'src/model/hls_stream_properties.dart';
//Views
export 'src/ui/meeting/hms_texture_view.dart';
diff --git a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart
index b1280cb63..3b32138d3 100644
--- a/packages/hmssdk_flutter/lib/src/common/platform_methods.dart
+++ b/packages/hmssdk_flutter/lib/src/common/platform_methods.dart
@@ -187,6 +187,7 @@ enum PlatformMethod {
areClosedCaptionsSupported,
enableClosedCaptions,
disableClosedCaptions,
+ getStreamProperties,
switchAudioOutputUsingiOSUI,
sendHLSTimedMetadata,
@@ -506,6 +507,8 @@ extension PlatformMethodValues on PlatformMethod {
return "enable_closed_captions";
case PlatformMethod.disableClosedCaptions:
return "disable_closed_captions";
+ case PlatformMethod.getStreamProperties:
+ return "get_stream_properties";
case PlatformMethod.switchAudioOutputUsingiOSUI:
return "switch_audio_output_using_ios_ui";
@@ -851,6 +854,8 @@ extension PlatformMethodValues on PlatformMethod {
return PlatformMethod.enableClosedCaptions;
case "disable_closed_captions":
return PlatformMethod.disableClosedCaptions;
+ case "get_stream_properties":
+ return PlatformMethod.getStreamProperties;
case "switch_audio_output_using_ios_ui":
return PlatformMethod.switchAudioOutputUsingiOSUI;
diff --git a/packages/hmssdk_flutter/lib/src/enum/hms_hls_playback_event_method.dart b/packages/hmssdk_flutter/lib/src/enum/hms_hls_playback_event_method.dart
index 72428d86d..68f2c4994 100644
--- a/packages/hmssdk_flutter/lib/src/enum/hms_hls_playback_event_method.dart
+++ b/packages/hmssdk_flutter/lib/src/enum/hms_hls_playback_event_method.dart
@@ -6,6 +6,7 @@ enum HMSHLSPlaybackEventMethod {
onHLSError,
onHLSEventUpdate,
onVideoSizeChanged,
+ onCues,
unknown
}
@@ -24,6 +25,8 @@ extension HMSHLSPlaybackEventMethodValues on HMSHLSPlaybackEventMethod {
return HMSHLSPlaybackEventMethod.onHLSEventUpdate;
case "on_video_size_changed":
return HMSHLSPlaybackEventMethod.onVideoSizeChanged;
+ case "on_cues":
+ return HMSHLSPlaybackEventMethod.onCues;
default:
return HMSHLSPlaybackEventMethod.unknown;
}
diff --git a/packages/hmssdk_flutter/lib/src/enum/hms_hls_playlist_type.dart b/packages/hmssdk_flutter/lib/src/enum/hms_hls_playlist_type.dart
new file mode 100644
index 000000000..d4fa404da
--- /dev/null
+++ b/packages/hmssdk_flutter/lib/src/enum/hms_hls_playlist_type.dart
@@ -0,0 +1,15 @@
+///[HMSHLSPlaylistType] is an enum which defines the type of playlist to be used in the HLS stream.
+enum HMSHLSPlaylistType { dvr, noDvr }
+
+extension HMSHLSPlaylistTypeValues on HMSHLSPlaylistType {
+ static HMSHLSPlaylistType getHMSHLSPlaylistTypeFromString(String? name) {
+ switch (name) {
+ case "dvr":
+ return HMSHLSPlaylistType.dvr;
+ case "noDvr":
+ return HMSHLSPlaylistType.noDvr;
+ default:
+ return HMSHLSPlaylistType.noDvr;
+ }
+ }
+}
diff --git a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_playback_event_listener.dart b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_playback_event_listener.dart
index 856a2b696..4033635b3 100644
--- a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_playback_event_listener.dart
+++ b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_playback_event_listener.dart
@@ -38,4 +38,9 @@ abstract class HMSHLSPlaybackEventsListener {
///
/// - Parameter: size: A [Size] object containing the new height and width of the stream
void onVideoSizeChanged({required Size size}) {}
+
+ /// Callback to get the subtitles
+ ///
+ /// - Parameter: subtitles: A list of [String] containing the subtitles
+ void onCues({required List subtitles}) {}
}
diff --git a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart
index 46a92cc09..e57192357 100644
--- a/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart
+++ b/packages/hmssdk_flutter/lib/src/model/hls_player/hms_hls_player_controller.dart
@@ -105,6 +105,7 @@ class HMSHLSPlayerController {
///
/// If closed captions are supported, you can enable/disable them using [enableClosedCaptions] and [disableClosedCaptions] respectively.
/// If this returns null then we set it to false.
+ /// Refer [areClosedCaptionsSupported](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player#how-to-enabledisable-captions)
static Future areClosedCaptionsSupported() async {
bool? result = await PlatformService.invokeMethod(
PlatformMethod.areClosedCaptionsSupported);
@@ -112,11 +113,13 @@ class HMSHLSPlayerController {
}
///[enableClosedCaptions] enables closed captions in the current HLS playback.
+ /// Refer [enableClosedCaptions](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player#how-to-enabledisable-captions)
static Future enableClosedCaptions() async {
await PlatformService.invokeMethod(PlatformMethod.enableClosedCaptions);
}
///[disableClosedCaptions] disables closed captions in the current HLS playback.
+ /// Refer [disableClosedCaptions](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player#how-to-enabledisable-captions)
static Future disableClosedCaptions() async {
await PlatformService.invokeMethod(PlatformMethod.disableClosedCaptions);
}
@@ -132,4 +135,12 @@ class HMSHLSPlayerController {
static Future removeHLSStatsListener() async {
await PlatformService.invokeMethod(PlatformMethod.removeHLSStatsListener);
}
+
+ ///[getStreamProperties] gets the properties of the current HLS stream.
+ /// Refer [getStreamProperties](https://www.100ms.live/docs/flutter/v2/how-to-guides/record-and-live-stream/hls-player#how-to-get-stream-properties)
+ static Future getStreamProperties() async {
+ var result =
+ await PlatformService.invokeMethod(PlatformMethod.getStreamProperties);
+ return HLSStreamProperties.fromMap(result);
+ }
}
diff --git a/packages/hmssdk_flutter/lib/src/model/hls_stream_properties.dart b/packages/hmssdk_flutter/lib/src/model/hls_stream_properties.dart
new file mode 100644
index 000000000..935de689e
--- /dev/null
+++ b/packages/hmssdk_flutter/lib/src/model/hls_stream_properties.dart
@@ -0,0 +1,20 @@
+///[HLSStreamProperties] class defines the properties of the HLS stream.
+class HLSStreamProperties {
+ ///[rollingWindowTime] is the time interval for which user can seek the stream
+ double? rollingWindowTime;
+
+ ///[streamDuration] is the total duration of the stream generally null in case of live stream
+ double? streamDuration;
+
+ HLSStreamProperties({this.rollingWindowTime, this.streamDuration});
+
+ factory HLSStreamProperties.fromMap(Map map) {
+ return HLSStreamProperties(
+ rollingWindowTime: map['rolling_window_time'] != null
+ ? map["rolling_window_time"].toDouble()
+ : null,
+ streamDuration: map['stream_duration'] != null
+ ? map["stream_duration"].toDouble()
+ : null);
+ }
+}
diff --git a/packages/hmssdk_flutter/lib/src/model/hms_hls_variant.dart b/packages/hmssdk_flutter/lib/src/model/hms_hls_variant.dart
index 70cd49f67..d2c1805f1 100644
--- a/packages/hmssdk_flutter/lib/src/model/hms_hls_variant.dart
+++ b/packages/hmssdk_flutter/lib/src/model/hms_hls_variant.dart
@@ -1,6 +1,8 @@
//Dart imports
import 'dart:core';
+///Project imports
+import 'package:hmssdk_flutter/src/enum/hms_hls_playlist_type.dart';
import 'package:hmssdk_flutter/src/model/hms_date_extension.dart';
///100ms HMSHLSVarient
@@ -11,12 +13,14 @@ class HMSHLSVariant {
final String? meetingUrl;
final String? metadata;
final DateTime? startedAt;
+ final HMSHLSPlaylistType playlistType;
HMSHLSVariant(
{required this.hlsStreamUrl,
required this.meetingUrl,
required this.metadata,
- required this.startedAt});
+ required this.startedAt,
+ required this.playlistType});
Map toMap() {
return {
@@ -24,6 +28,7 @@ class HMSHLSVariant {
'meetingUrl': this.meetingUrl,
'metadata': this.metadata,
'startedAt': this.startedAt,
+ 'playlist_type': this.playlistType,
};
}
@@ -34,12 +39,13 @@ class HMSHLSVariant {
factory HMSHLSVariant.fromMap(Map map) {
return HMSHLSVariant(
- hlsStreamUrl: map['hls_stream_url'] as String?,
- meetingUrl: map['meeting_url'] as String?,
- metadata: map['metadata'] as String?,
- startedAt: map['started_at'] != null
- ? HMSDateExtension.convertDateFromEpoch(map['started_at'])
- : null,
- );
+ hlsStreamUrl: map['hls_stream_url'] as String?,
+ meetingUrl: map['meeting_url'] as String?,
+ metadata: map['metadata'] as String?,
+ startedAt: map['started_at'] != null
+ ? HMSDateExtension.convertDateFromEpoch(map['started_at'])
+ : null,
+ playlistType: HMSHLSPlaylistTypeValues.getHMSHLSPlaylistTypeFromString(
+ map["playlist_type"]));
}
}
diff --git a/packages/hmssdk_flutter/lib/src/service/platform_service.dart b/packages/hmssdk_flutter/lib/src/service/platform_service.dart
index 3e02fd860..959ba0557 100644
--- a/packages/hmssdk_flutter/lib/src/service/platform_service.dart
+++ b/packages/hmssdk_flutter/lib/src/service/platform_service.dart
@@ -11,6 +11,7 @@ import 'dart:async';
// Flutter imports:
import 'package:flutter/services.dart';
+
// Project imports:
import 'package:hmssdk_flutter/hmssdk_flutter.dart';
import 'package:hmssdk_flutter/src/enum/hms_hls_playback_event_method.dart';
@@ -779,6 +780,12 @@ abstract class PlatformService {
arguments["height"].toDouble())));
}
break;
+ case HMSHLSPlaybackEventMethod.onCues:
+ hlsPlaybackEventListener.forEach((e) => e.onCues(
+ subtitles: arguments["subtitles"] != null
+ ? List.from(arguments["subtitles"])
+ : []));
+ break;
case HMSHLSPlaybackEventMethod.unknown:
break;
}
diff --git a/packages/hmssdk_flutter/pubspec.yaml b/packages/hmssdk_flutter/pubspec.yaml
index 23ea9d5ee..c6ebe82a8 100644
--- a/packages/hmssdk_flutter/pubspec.yaml
+++ b/packages/hmssdk_flutter/pubspec.yaml
@@ -1,6 +1,6 @@
name: hmssdk_flutter
description: Add Real Time Audio & Video calls, Interactive Live Streaming & Recording, Chat, HLS, RTMP, PiP, CallKit, VoIP, Video conferencing, Stream Player & WebRTC-based communications API
-version: 1.10.0
+version: 1.10.1
homepage: https://www.100ms.live/
repository: https://github.com/100mslive/100ms-flutter
issue_tracker: https://github.com/100mslive/100ms-flutter/issues