flutter_sound_player_web.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Copyright 2018, 2019, 2020 Dooboolab.
  3. *
  4. * This file is part of Flutter-Sound.
  5. *
  6. * Flutter-Sound is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License version 3 (LGPL-V3), as published by
  8. * the Free Software Foundation.
  9. *
  10. * Flutter-Sound is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public License
  16. * along with Flutter-Sound. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. @JS()
  19. library flutter_sound;
  20. import 'dart:async';
  21. import 'dart:html' as html;
  22. import 'dart:typed_data' show Uint8List;
  23. import 'package:meta/meta.dart';
  24. import 'package:flutter_sound_platform_interface/flutter_sound_platform_interface.dart';
  25. import 'package:flutter_sound_platform_interface/flutter_sound_player_platform_interface.dart';
  26. import 'package:flutter_web_plugins/flutter_web_plugins.dart';
  27. import 'dart:io';
  28. import 'package:js/js.dart';
  29. import 'package:logger/logger.dart' show Level , Logger;
  30. // ==================================== JS =======================================================
  31. @JS('newPlayerInstance')
  32. external FlutterSoundPlayer newPlayerInstance(FlutterSoundPlayerCallback theCallBack, List<Function> callbackTable);
  33. @JS('FlutterSoundPlayer')
  34. class FlutterSoundPlayer
  35. {
  36. @JS('releaseMediaPlayer')
  37. external int releaseMediaPlayer();
  38. @JS('initializeMediaPlayer')
  39. external int initializeMediaPlayer( );
  40. @JS('setAudioFocus')
  41. external int setAudioFocus(int focus, int category, int mode, int? audioFlags, int device,);
  42. @JS('getPlayerState')
  43. external int getPlayerState();
  44. @JS('isDecoderSupported')
  45. external bool isDecoderSupported( int codec,);
  46. @JS('setSubscriptionDuration')
  47. external int setSubscriptionDuration( int duration);
  48. @JS('startPlayer')
  49. external int startPlayer(int? codec, Uint8List? fromDataBuffer, String? fromURI, int? numChannels, int? sampleRate);
  50. @JS('feed')
  51. external int feed(Uint8List? data,);
  52. @JS('startPlayerFromTrack')
  53. external int startPlayerFromTrack(int progress, int duration, Map<String, dynamic> track, bool canPause, bool canSkipForward, bool canSkipBackward, bool defaultPauseResume, bool removeUIWhenStopped, );
  54. @JS('nowPlaying')
  55. external int nowPlaying(int progress, int duration, Map<String, dynamic>? track, bool? canPause, bool? canSkipForward, bool? canSkipBackward, bool? defaultPauseResume, );
  56. @JS('stopPlayer')
  57. external int stopPlayer();
  58. @JS('resumePlayer')
  59. external int pausePlayer();
  60. @JS('')
  61. external int resumePlayer();
  62. @JS('seekToPlayer')
  63. external int seekToPlayer( int duration);
  64. @JS('setVolume')
  65. external int setVolume(double? volume);
  66. @JS('setSpeed')
  67. external int setSpeed(double speed);
  68. @JS('setUIProgressBar')
  69. external int setUIProgressBar(int duration, int progress);
  70. }
  71. List<Function> callbackTable =
  72. [
  73. allowInterop( (FlutterSoundPlayerCallback cb, int position, int duration) { cb.updateProgress(duration: duration, position: position,);} ),
  74. allowInterop( (FlutterSoundPlayerCallback cb, int state) { cb.updatePlaybackState(state,);} ),
  75. allowInterop( (FlutterSoundPlayerCallback cb, int ln) { cb.needSomeFood(ln,);} ),
  76. allowInterop( (FlutterSoundPlayerCallback cb, int state) { cb.audioPlayerFinished(state,);} ),
  77. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success, int duration) { cb.startPlayerCompleted(state, success, duration,);} ),
  78. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success) { cb.pausePlayerCompleted(state, success);} ),
  79. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success) { cb.resumePlayerCompleted(state, success);} ),
  80. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success) { cb.stopPlayerCompleted(state, success);} ),
  81. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success) { cb.openPlayerCompleted(state, success);} ),
  82. allowInterop( (FlutterSoundPlayerCallback cb, int state, bool success) { cb.closePlayerCompleted(state, success);} ),
  83. allowInterop( (FlutterSoundPlayerCallback cb, int level, String msg) { cb.log(Level.values[level], msg);} ),
  84. ];
  85. //=========================================================================================================
  86. /// The web implementation of [FlutterSoundPlatform].
  87. ///
  88. /// This class implements the `package:flutter_sound_player` functionality for the web.
  89. ///
  90. class FlutterSoundPlayerWeb extends FlutterSoundPlayerPlatform //implements FlutterSoundPlayerCallback
  91. {
  92. static List<String> defaultExtensions =
  93. [
  94. "flutter_sound.aac", // defaultCodec
  95. "flutter_sound.aac", // aacADTS
  96. "flutter_sound.opus", // opusOGG
  97. "flutter_sound_opus.caf", // opusCAF
  98. "flutter_sound.mp3", // mp3
  99. "flutter_sound.ogg", // vorbisOGG
  100. "flutter_sound.pcm", // pcm16
  101. "flutter_sound.wav", // pcm16WAV
  102. "flutter_sound.aiff", // pcm16AIFF
  103. "flutter_sound_pcm.caf", // pcm16CAF
  104. "flutter_sound.flac", // flac
  105. "flutter_sound.mp4", // aacMP4
  106. "flutter_sound.amr", // amrNB
  107. "flutter_sound.amr", // amrWB
  108. "flutter_sound.pcm", // pcm8
  109. "flutter_sound.pcm", // pcmFloat32
  110. ];
  111. /// Registers this class as the default instance of [FlutterSoundPlatform].
  112. static void registerWith(Registrar registrar)
  113. {
  114. FlutterSoundPlayerPlatform.instance = FlutterSoundPlayerWeb();
  115. }
  116. /* ctor */ MethodChannelFlutterSoundPlayer()
  117. {
  118. }
  119. //============================================ Session manager ===================================================================
  120. List<FlutterSoundPlayer?> _slots = [];
  121. FlutterSoundPlayer? getWebSession(FlutterSoundPlayerCallback callback)
  122. {
  123. return _slots[findSession(callback)];
  124. }
  125. //==============================================================================================================================
  126. @override
  127. Future<void>? resetPlugin(FlutterSoundPlayerCallback callback,)
  128. {
  129. callback.log(Level.debug, '---> resetPlugin');
  130. for (int i = 0; i < _slots.length; ++i)
  131. {
  132. callback.log(Level.debug, "Releasing slot #$i");
  133. _slots[i]!.releaseMediaPlayer();
  134. }
  135. _slots = [];
  136. callback.log(Level.debug, '<--- resetPlugin');
  137. return null;
  138. }
  139. @override
  140. Future<int> openPlayer(FlutterSoundPlayerCallback callback, {required Level logLevel, bool voiceProcessing = false}) async
  141. {
  142. // openAudioSessionCompleter = new Completer<bool>();
  143. // await invokeMethod( callback, 'initializeMediaPlayer', {'focus': focus.index, 'category': category.index, 'mode': mode.index, 'audioFlags': audioFlags, 'device': device.index, 'withUI': withUI ? 1 : 0 ,},) ;
  144. // return openAudioSessionCompleter.future ;
  145. int slotno = findSession(callback);
  146. if (slotno < _slots.length)
  147. {
  148. assert (_slots[slotno] == null);
  149. _slots[slotno] = newPlayerInstance(callback, callbackTable);
  150. } else
  151. {
  152. assert(slotno == _slots.length);
  153. _slots.add( newPlayerInstance(callback, callbackTable));
  154. }
  155. return _slots[slotno]!.initializeMediaPlayer( );
  156. }
  157. @override
  158. Future<int> closePlayer(FlutterSoundPlayerCallback callback, ) async
  159. {
  160. int slotno = findSession(callback);
  161. int r = _slots[slotno]!.releaseMediaPlayer();
  162. _slots[slotno] = null;
  163. return r;
  164. }
  165. @override
  166. Future<int> getPlayerState(FlutterSoundPlayerCallback callback, ) async
  167. {
  168. return getWebSession(callback)!.getPlayerState();
  169. }
  170. @override
  171. Future<Map<String, Duration>> getProgress(FlutterSoundPlayerCallback callback, ) async
  172. {
  173. // Map<String, int> m = await invokeMethod( callback, 'getPlayerState', null,) as Map;
  174. Map<String, Duration> r = {'duration': Duration.zero, 'progress': Duration.zero,};
  175. return r;
  176. }
  177. @override
  178. Future<bool> isDecoderSupported(FlutterSoundPlayerCallback callback, { required Codec codec ,}) async
  179. {
  180. return getWebSession(callback)!.isDecoderSupported(codec.index);
  181. }
  182. @override
  183. Future<int> setSubscriptionDuration(FlutterSoundPlayerCallback callback, { Duration? duration,}) async
  184. {
  185. return getWebSession(callback)!.setSubscriptionDuration(duration!.inMilliseconds);
  186. }
  187. @override
  188. Future<int> startPlayer(FlutterSoundPlayerCallback callback, {Codec? codec, Uint8List? fromDataBuffer, String? fromURI, int? numChannels, int? sampleRate}) async
  189. {
  190. // startPlayerCompleter = new Completer<Map>();
  191. // await invokeMethod( callback, 'startPlayer', {'codec': codec.index, 'fromDataBuffer': fromDataBuffer, 'fromURI': fromURI, 'numChannels': numChannels, 'sampleRate': sampleRate},) ;
  192. // return startPlayerCompleter.future ;
  193. // String s = "https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3";
  194. if (codec == null)
  195. codec = Codec.defaultCodec;
  196. if (fromDataBuffer != null)
  197. {
  198. if (fromURI != null)
  199. {
  200. throw Exception("You may not specify both 'fromURI' and 'fromDataBuffer' parameters");
  201. }
  202. //js.context.callMethod('playAudioFromBuffer', [fromDataBuffer]);
  203. //playAudioFromBuffer(fromDataBuffer);
  204. // .......................return getWebSession(callback).playAudioFromBuffer(fromDataBuffer);
  205. //playAudioFromBuffer3(fromDataBuffer);
  206. //Directory tempDir = await getTemporaryDirectory();
  207. /*
  208. String path = defaultExtensions[codec.index];
  209. File filOut = File(path);
  210. IOSink sink = filOut.openWrite();
  211. sink.add(fromDataBuffer.toList());
  212. fromURI = path;
  213. */
  214. }
  215. //js.context.callMethod('playAudioFromURL', [fromURI]);
  216. callback.log(Level.debug, 'startPlayer FromURI : $fromURI');
  217. return getWebSession(callback)!.startPlayer(codec.index, fromDataBuffer, fromURI, numChannels, sampleRate);
  218. }
  219. @override
  220. Future<int> startPlayerFromMic(FlutterSoundPlayerCallback callback, {int? numChannels, int? sampleRate}) {
  221. throw Exception('StartPlayerFromMic() is not implemented on Flutter Web');
  222. }
  223. @override
  224. Future<int> feed(FlutterSoundPlayerCallback callback, {Uint8List? data, }) async
  225. {
  226. return getWebSession(callback)!.feed(data);
  227. }
  228. @override
  229. Future<int> stopPlayer(FlutterSoundPlayerCallback callback, ) async
  230. {
  231. return getWebSession(callback)!.stopPlayer();
  232. }
  233. @override
  234. Future<int> pausePlayer(FlutterSoundPlayerCallback callback, ) async
  235. {
  236. return getWebSession(callback)!.pausePlayer();
  237. }
  238. @override
  239. Future<int> resumePlayer(FlutterSoundPlayerCallback callback, ) async
  240. {
  241. return getWebSession(callback)!.resumePlayer();
  242. }
  243. @override
  244. Future<int> seekToPlayer(FlutterSoundPlayerCallback callback, {Duration? duration}) async
  245. {
  246. return getWebSession(callback)!.seekToPlayer(duration!.inMilliseconds);
  247. }
  248. Future<int> setVolume(FlutterSoundPlayerCallback callback, {double? volume}) async
  249. {
  250. return getWebSession(callback)!.setVolume(volume);
  251. }
  252. Future<int> setSpeed(FlutterSoundPlayerCallback callback, {required double speed}) async
  253. {
  254. return getWebSession(callback)!.setSpeed(speed);
  255. }
  256. Future<String> getResourcePath(FlutterSoundPlayerCallback callback, ) async
  257. {
  258. return '';
  259. }
  260. @override
  261. Future<void>? setLogLeve(FlutterSoundPlayerCallback callback, Level loglevel)
  262. {
  263. }
  264. }