part of './ijkplayer.dart'; /// Media Controller class IjkMediaController { /// MediaController IjkMediaController({ this.autoRotate = true, }) { index = IjkMediaPlayerManager().add(this); } int index; String get debugLabel => index.toString(); /// texture id from native int _textureId; /// It will automatically correct the direction of the video. bool autoRotate; /// texture id from native int get textureId => _textureId; /// set texture id, Normally the user does not call set textureId(int id) { _textureId = id; _textureIdController.add(id); } /// on texture id change StreamController _textureIdController = StreamController.broadcast(); /// on texture id change Stream get textureIdStream => _textureIdController?.stream; /// Channel of flutter and native. _IjkPlugin _plugin; /// Whether texture id is null bool get isInit => textureId == null; /// channel of native to flutter _IJKEventChannel eventChannel; /// playing state bool _isPlaying = false; /// playing state bool get isPlaying => _isPlaying == true; /// playing state set isPlaying(bool value) { this._isPlaying = value; _playingController?.add(value); } /// playing state stream controller StreamController _playingController = StreamController.broadcast(); /// playing state stream Stream get playingStream => _playingController?.stream; /// video info stream controller StreamController _videoInfoController = StreamController.broadcast(); /// video info stream Stream get videoInfoStream => _videoInfoController?.stream; /// video volume stream controller StreamController _volumeController = StreamController.broadcast(); /// video volume stream Stream get volumeStream => _volumeController?.stream; /// video volume, not system volume int _volume = 100; /// video volume, not system volume set volume(int value) { if (value > 100) { value = 100; } else if (value < 0) { value = 0; } this._volume = value; _volumeController?.add(value); _setVolume(value); } /// video volume, not system volume int get volume => _volume; /// create ijk texture id from native Future _initIjk() async { try { var id = await _createIjk(); this.textureId = id; _plugin = _IjkPlugin(id); eventChannel = _IJKEventChannel(this); await eventChannel.init(); volume = 100; } catch (e) { LogUtils.warning(e); LogUtils.warning("初始化失败"); } } /// [reset] and close all controller void dispose() async { await reset(); _playingController?.close(); _videoInfoController?.close(); _textureIdController?.close(); _volumeController?.close(); _playingController = null; _videoInfoController = null; _textureIdController = null; _volumeController = null; IjkMediaPlayerManager().remove(this); } /// dispose all resource Future reset() async { volume = 100; this.textureId = null; _plugin?.dispose(); _plugin = null; eventChannel?.dispose(); eventChannel = null; } /// set net DataSource Future setNetworkDataSource( String url, { Map headers = const {}, bool autoPlay = false, }) async { await _initDataSource(() async { await _plugin?.setNetworkDataSource( uri: url, headers: headers, ); }, autoPlay); } /// set asset DataSource Future setAssetDataSource( String name, { String package, bool autoPlay = false, }) async { await _initDataSource(() async { await _plugin?.setAssetDataSource(name, package); }, autoPlay); } /// Set datasource with [DataSource] Future setDataSource( DataSource source, { bool autoPlay = false, }) async { switch (source._type) { case DataSourceType.asset: await setAssetDataSource( source._assetName, package: source._assetPackage, autoPlay: autoPlay, ); break; case DataSourceType.file: await setFileDataSource( source._file, autoPlay: autoPlay, ); break; case DataSourceType.network: await setNetworkDataSource( source._netWorkUrl, headers: source._headers, autoPlay: autoPlay, ); break; default: } } /// set file DataSource Future setFileDataSource( File file, { bool autoPlay = false, }) async { await _initDataSource(() async { await _plugin?.setFileDataSource(file.absolute.path); }, autoPlay); } /// dispose last textureId resource Future _initDataSource( Future setDataSource(), bool autoPlay, ) async { autoPlay ??= false; if (this.textureId != null) { await _plugin?.dispose(); } await _initIjk(); Future playFuture = _autoPlay(autoPlay); await setDataSource(); return playFuture; } /// Play or pause according to your current status Future playOrPause({ pauseOther = false, }) async { var videoInfo = await getVideoInfo(); var playing = videoInfo.isPlaying; if (playing) { await pause(); } else { await play(pauseOther: pauseOther); } } /// play media Future play({ pauseOther = false, }) async { if (pauseOther) { await pauseOtherController(); } LogUtils.info("$this play"); await _plugin?.play(); refreshVideoInfo(); } /// pause media Future pause() async { LogUtils.info("$this pause"); await _plugin?.pause(); refreshVideoInfo(); } /// seek to second /// /// [target] unit is second Future seekTo(double target) async { await _plugin?.seekTo(target); refreshVideoInfo(); } Future seekToProgress(double progress) async { var videoInfo = await getVideoInfo(); var target = videoInfo.duration * progress; await this.seekTo(target); refreshVideoInfo(); } /// get video info from native Future getVideoInfo() async { Map result = await _plugin?.getInfo(); var info = VideoInfo.fromMap(result); return info; } /// request info and notify Future refreshVideoInfo() async { var info = await getVideoInfo(); isPlaying = info.isPlaying; if (info.hasData) { _videoInfoController?.add(info); LogUtils.verbose("onrefreshInfo = $info"); } } /// AutoPlay use Future _autoPlay(bool autoPlay) async { if (autoPlay) { await eventChannel?.autoPlay(this); } else { await eventChannel?.disableAutoPlay(this); } } /// set video volume Future _setVolume(int volume) async { await _plugin?.setVolume(volume); } /// [pause] and [seekTo] 0 Future stop() async { // await _plugin?.stop(); // refreshVideoInfo(); await _plugin?.pause(); await _plugin?.seekTo(0); refreshVideoInfo(); } /// get system volume Future getSystemVolume() async { return IjkManager.getSystemVolume(); } /// set system volume Future setSystemVolume(int volume) async { await IjkManager.setSystemVolume(volume); } Future pauseOtherController() async { await IjkMediaPlayerManager().pauseOther(this); } @override String toString() { return "IJKController[$index]"; } } /// about channel MethodChannel _globalChannel = MethodChannel("top.kikt/ijkplayer"); Future _createIjk() async { int id = await _globalChannel.invokeMethod("create"); return id; } class _IjkPlugin { MethodChannel get channel => MethodChannel("top.kikt/ijkplayer/$textureId"); /// texture id int textureId; _IjkPlugin(this.textureId); Future dispose() async { await _globalChannel.invokeMethod("dispose", {"id": textureId}); } Future play() async { await channel.invokeMethod("play"); } Future pause() async { await channel.invokeMethod("pause"); } Future stop() async { await channel.invokeMethod("stop"); } Future setNetworkDataSource( {String uri, Map headers = const {}}) async { LogUtils.debug("id = $textureId net uri = $uri ,headers = $headers"); await channel.invokeMethod("setNetworkDataSource", { "uri": uri, "headers": headers, }); } Future setAssetDataSource(String name, String package) async { LogUtils.debug("id = $textureId asset name = $name package = $package"); var params = { "name": name, }; if (package != null) { params["package"] = package; } await channel.invokeMethod("setAssetDataSource", params); } Future setFileDataSource(String path) async { if (!File(path).existsSync()) { return Error.fileNotExists; } await channel.invokeMethod("setFileDataSource", { "path": path, }); LogUtils.debug("id = $textureId file path = $path"); } Future> getInfo() async { var map = await channel.invokeMethod("getInfo"); if (map == null) { return null; } else { return map.cast(); } } Future seekTo(double target) async { await channel.invokeMethod("seekTo", { "target": target, }); } Future setVolume(int volume) async { await channel.invokeMethod("setVolume", { "volume": volume, }); } } /// Entity classe for data sources. class DataSource { /// See [DataSourceType] DataSourceType _type; File _file; String _assetName; String _assetPackage; String _netWorkUrl; Map _headers; DataSource._(); /// Create file data source factory DataSource.file(File file) { var ds = DataSource._(); ds._file = file; ds._type = DataSourceType.file; return ds; } /// Create network data source factory DataSource.network(String url, {Map headers = const {}}) { var ds = DataSource._(); ds._netWorkUrl = url; ds._headers = headers; ds._type = DataSourceType.network; return ds; } /// Create asset data source factory DataSource.asset(String assetName, {String package}) { var ds = DataSource._(); ds._assetName = assetName; ds._assetPackage = package; ds._type = DataSourceType.asset; return ds; } } enum DataSourceType { network, file, asset, }