From 50c9a4ca312d34f856da11d6ee1671b3a9dd49ec Mon Sep 17 00:00:00 2001 From: Decoder07 Date: Mon, 29 Apr 2024 18:18:43 +0530 Subject: [PATCH] Added bottom sheet for hls quality --- .../lib/src/hls_viewer/hls_player_store.dart | 28 +++- .../lib/src/hls_viewer/hls_viewer_header.dart | 44 ++++-- ..._viewer_quality_selector_bottom_sheet.dart | 129 ++++++++++++++++++ .../hmssdk_flutter/example/ios/Podfile.lock | 4 +- packages/hmssdk_flutter/example/pubspec.lock | 73 ++++------ .../HLSPlayer/HMSHLSPlayerAction.swift | 47 ++++--- .../hmssdk_flutter/lib/hmssdk_flutter.dart | 1 + .../hls_player/hms_hls_player_controller.dart | 1 - 8 files changed, 247 insertions(+), 80 deletions(-) create mode 100644 packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart 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 7c5064ad4..35e2cc00e 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 @@ -75,6 +75,10 @@ class HLSPlayerStore extends ChangeNotifier String? caption; + Map layerMap = {}; + + HMSHLSLayer? selectedLayer; + ///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 @@ -217,7 +221,28 @@ class HLSPlayerStore extends ChangeNotifier void getHLSLayers() async { var layers = await HMSHLSPlayerController.getHLSLayers(); - log("Layers are $layers"); + layers.sort((a, b) => (b.bitrate ?? 0).compareTo(a.bitrate ?? 0)); + int layersSize = layers.length; + if (layers[layersSize - 1].bitrate == 0 || + layers[layersSize - 1].bitrate == null) { + layerMap["AUTO"] = layers[layersSize - 1]; + } + layerMap["HIGH"] = layers[0]; + if (layersSize > 1) { + layerMap["LOW"] = layers[layersSize - 2]; + } + layerMap["MEDIUM"] = layers[layersSize ~/ 2]; + } + + void getCurrentHLSLayer() async { + var layer = await HMSHLSPlayerController.getCurrentHLSLayer(); + selectedLayer = layer; + } + + void setHLSLayer(HMSHLSLayer hmsHLSLayer) async { + selectedLayer = hmsHLSLayer; + await HMSHLSPlayerController.setHLSLayer(hmsHLSLayer: hmsHLSLayer); + notifyListeners(); } @override @@ -250,6 +275,7 @@ class HLSPlayerStore extends ChangeNotifier setHLSPlayerStats(true); startTimer(); getHLSLayers(); + getCurrentHLSLayer(); isStreamPlaying = true; isPlayerFailed = false; break; 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 f72197030..a608a266d 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 @@ -3,6 +3,8 @@ library; ///Package imports import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:hms_room_kit/src/meeting/meeting_store.dart'; +import 'package:hms_room_kit/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart'; import 'package:provider/provider.dart'; ///Project imports @@ -87,18 +89,38 @@ class HLSViewerHeader extends StatelessWidget { }), ///This will be added later - // const SizedBox( - // width: 16, - // ), + 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", - // ) + ///This renders the settings button + GestureDetector( + onTap: () { + var _meetingStore = + context.read(); + var _hlsPlayerStore = + context.read(); + showModalBottomSheet( + isScrollControlled: true, + backgroundColor: Colors.transparent, + context: context, + builder: (ctx) => + ChangeNotifierProvider.value( + value: _meetingStore, + child: ChangeNotifierProvider.value( + value: _hlsPlayerStore, + child: + HLSViewerQualitySelectorBottomSheet()), + )); + }, + child: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/settings.svg", + colorFilter: ColorFilter.mode( + HMSThemeColors.onSurfaceHighEmphasis, + BlendMode.srcIn), + semanticsLabel: "caption_toggle_button", + ), + ) ], ) ], diff --git a/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart new file mode 100644 index 000000000..a9ae599ad --- /dev/null +++ b/packages/hms_room_kit/lib/src/widgets/bottom_sheets/hls_viewer_quality_selector_bottom_sheet.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.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:hms_room_kit/src/meeting/meeting_store.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_cross_button.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_subtitle_text.dart'; +import 'package:hms_room_kit/src/widgets/common_widgets/hms_title_text.dart'; +import 'package:hmssdk_flutter/hmssdk_flutter.dart'; +import 'package:provider/provider.dart'; +import 'package:tuple/tuple.dart'; + +class HLSViewerQualitySelectorBottomSheet extends StatefulWidget { + @override + State createState() => + _HLSViewerQualitySelectorBottomSheetState(); +} + +class _HLSViewerQualitySelectorBottomSheetState + extends State { + @override + void initState() { + super.initState(); + context.read().addBottomSheet(context); + } + + @override + void deactivate() { + context.read().removeBottomSheet(context); + super.deactivate(); + } + + @override + Widget build(BuildContext context) { + double height = MediaQuery.of(context).size.height; + return SizedBox( + height: MediaQuery.of(context).orientation == Orientation.landscape? height * 0.8: height * 0.4, + width: , + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), topRight: Radius.circular(16)), + color: HMSThemeColors.backgroundDefault, + ), + child: Selector, int>>( + selector: (_, hlsPlayerStore) => Tuple2( + hlsPlayerStore.layerMap, hlsPlayerStore.layerMap.length), + builder: (context, data, _) { + return Padding( + padding: + const EdgeInsets.only(top: 24.0, left: 16, right: 16), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + HMSTitleText( + text: "Quality", + textColor: + HMSThemeColors.onSurfaceHighEmphasis, + letterSpacing: 0.15, + ), + ], + ), + const Row( + children: [HMSCrossButton()], + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Divider( + color: HMSThemeColors.borderDefault, + height: 5, + ), + ), + Expanded( + child: ListView.builder( + itemCount: data.item2, + itemBuilder: (context, index) { + return ListTile( + horizontalTitleGap: 2, + enabled: false, + contentPadding: EdgeInsets.zero, + title: HMSSubtitleText( + text: + data.item1.entries.elementAt(index).key, + fontSize: 14, + lineHeight: 20, + letterSpacing: 0.10, + fontWeight: FontWeight.w600, + textColor: + HMSThemeColors.onSurfaceHighEmphasis, + ), + trailing: context + .read() + .selectedLayer == + data.item1.entries + .elementAt(index) + .value + ? SizedBox( + height: 24, + width: 24, + child: SvgPicture.asset( + "packages/hms_room_kit/lib/src/assets/icons/tick.svg", + fit: BoxFit.scaleDown, + colorFilter: ColorFilter.mode( + HMSThemeColors + .onSurfaceHighEmphasis, + BlendMode.srcIn), + ), + ) + : const SizedBox( + height: 24, + width: 24, + ), + ); + }), + ) + ], + ), + ); + }), + )); + } +} diff --git a/packages/hmssdk_flutter/example/ios/Podfile.lock b/packages/hmssdk_flutter/example/ios/Podfile.lock index 64e0f64ba..cad71311c 100644 --- a/packages/hmssdk_flutter/example/ios/Podfile.lock +++ b/packages/hmssdk_flutter/example/ios/Podfile.lock @@ -132,7 +132,7 @@ PODS: - HMSSDK (1.9.0): - HMSAnalyticsSDK (= 0.0.2) - HMSWebRTC (= 1.0.6168) - - hmssdk_flutter (1.10.0): + - hmssdk_flutter (1.10.1): - Flutter - HMSBroadcastExtensionSDK (= 0.0.9) - HMSHLSPlayerSDK (= 0.0.2) @@ -300,7 +300,7 @@ SPEC CHECKSUMS: HMSHLSPlayerSDK: 6a54ad4d12f3dc2270d1ecd24019d71282a4f6a3 HMSNoiseCancellationModels: a3bda1405a16015632f4bcabd46ce48f35103b02 HMSSDK: 96bdafc1c610aabfecd1155ad7e3c1bc45b3a6cb - hmssdk_flutter: 3febf31ba806e9a5ee540fe299c7331fc43135cf + hmssdk_flutter: c2ad70779ed9355577afbbe1047fb20f862820ac HMSWebRTC: a302f0d6c94f7bee94f3265adb7bb1c6569e7ee5 MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 diff --git a/packages/hmssdk_flutter/example/pubspec.lock b/packages/hmssdk_flutter/example/pubspec.lock index 71150e5cd..a0a1f069a 100644 --- a/packages/hmssdk_flutter/example/pubspec.lock +++ b/packages/hmssdk_flutter/example/pubspec.lock @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.17.2" convert: dependency: transitive description: @@ -306,10 +306,9 @@ packages: hmssdk_flutter: dependency: transitive description: - name: hmssdk_flutter - sha256: bfa6e6ec411d6f86f6cc054936fb2163c4cd3f8703f8848099689652b3794376 - url: "https://pub.dev" - source: hosted + path: ".." + relative: true + source: path version: "1.10.1" http: dependency: transitive @@ -343,30 +342,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" linkify: dependency: transitive description: @@ -387,26 +362,26 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" mime: dependency: transitive description: @@ -451,10 +426,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_parsing: dependency: transitive description: @@ -688,18 +663,18 @@ packages: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.1" string_scanner: dependency: transitive description: @@ -720,10 +695,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.6.0" tuple: dependency: transitive description: @@ -852,14 +827,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0+2" - vm_service: + web: dependency: transitive description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "0.1.4-beta" win32: dependency: transitive description: @@ -885,5 +860,5 @@ packages: source: hosted version: "6.3.0" sdks: - dart: ">=3.2.0-0 <4.0.0" + dart: ">=3.1.0 <4.0.0" flutter: ">=3.13.0" diff --git a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift index 41899a013..e36fd72a8 100644 --- a/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift +++ b/packages/hmssdk_flutter/ios/Classes/HLSPlayer/HMSHLSPlayerAction.swift @@ -457,62 +457,77 @@ class HMSHLSPlayerAction { [ "resolution": [ - "height": 1080, - "width": 1920 + "height": 1080.0, + "width": 1920.0 ], "bitrate": 4000 * 1000 ], [ "resolution": [ - "height": 720, - "width": 1280 + "height": 720.0, + "width": 1280.0 ], "bitrate": 1500 * 1000 ], [ "resolution": [ - "height": 540, - "width": 960 + "height": 540.0, + "width": 960.0 ], "bitrate": 1000 * 1000 ], [ "resolution": [ - "height": 480, - "width": 852 + "height": 480.0, + "width": 852.0 ], "bitrate": 850 * 1000 ], [ "resolution": [ - "height": 360, - "width": 640 + "height": 360.0, + "width": 640.0 ], "bitrate": 450 * 1000 ], [ "resolution": [ - "height": 240, - "width": 426 + "height": 240.0, + "width": 426.0 ], "bitrate": 300 * 1000 ], [ "resolution": [ - "height": 144, - "width": 256 + "height": 144.0, + "width": 256.0 ], "bitrate": 200 * 1000 ], + [ + "resolution": [ + "height": 1080.0, + "width": 1920.0 + ], + "bitrate": 0 + ] ] - static private var currentBitrate : Any? = nil + static private var currentBitrate : Any? = [ + "resolution": [ + "height": 0.0, + "width": 0.0 + ], + "bitrate": 0 + ] static private func getHLSLayers( _ result: @escaping FlutterResult ){ - result(layersMap) + var layers = [String:Any]() + layers["layers"] = layersMap + result(layers) } static private func setHLSLayer( diff --git a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart index 0107e3c6a..4fd3f1956 100644 --- a/packages/hmssdk_flutter/lib/hmssdk_flutter.dart +++ b/packages/hmssdk_flutter/lib/hmssdk_flutter.dart @@ -116,6 +116,7 @@ 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'; +export 'src/model/hls_player/hms_hls_layer.dart'; //Views export 'src/ui/meeting/hms_texture_view.dart'; 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 153ca5db8..a1897caeb 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 @@ -1,5 +1,4 @@ import 'package:hmssdk_flutter/hmssdk_flutter.dart'; -import 'package:hmssdk_flutter/src/model/hls_player/hms_hls_layer.dart'; import 'package:hmssdk_flutter/src/service/platform_service.dart'; ///100ms HMSHLSPlayerController