blob: eb227ce18ec552f1f5200ef43d7ce6204986a76c [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:ui';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'video_player_platform_interface.dart';
const MethodChannel _channel = MethodChannel('flutter.io/videoPlayer');
/// An implementation of [VideoPlayerPlatform] that uses method channels.
class MethodChannelVideoPlayer extends VideoPlayerPlatform {
@override
Future<void> init() {
return _channel.invokeMethod<void>('init');
}
@override
Future<void> dispose(int textureId) {
return _channel.invokeMethod<void>(
'dispose',
<String, dynamic>{'textureId': textureId},
);
}
@override
Future<int> create(DataSource dataSource) async {
Map<String, dynamic> dataSourceDescription;
switch (dataSource.sourceType) {
case DataSourceType.asset:
dataSourceDescription = <String, dynamic>{
'asset': dataSource.asset,
'package': dataSource.package,
};
break;
case DataSourceType.network:
dataSourceDescription = <String, dynamic>{
'uri': dataSource.uri,
'formatHint': _videoFormatStringMap[dataSource.formatHint]
};
break;
case DataSourceType.file:
dataSourceDescription = <String, dynamic>{'uri': dataSource.uri};
break;
}
final Map<String, dynamic> response =
await _channel.invokeMapMethod<String, dynamic>(
'create',
dataSourceDescription,
);
return response['textureId'];
}
@override
Future<void> setLooping(int textureId, bool looping) {
return _channel.invokeMethod<void>(
'setLooping',
<String, dynamic>{
'textureId': textureId,
'looping': looping,
},
);
}
@override
Future<void> play(int textureId) {
return _channel.invokeMethod<void>(
'play',
<String, dynamic>{'textureId': textureId},
);
}
@override
Future<void> pause(int textureId) {
return _channel.invokeMethod<void>(
'pause',
<String, dynamic>{'textureId': textureId},
);
}
@override
Future<void> setVolume(int textureId, double volume) {
return _channel.invokeMethod<void>(
'setVolume',
<String, dynamic>{
'textureId': textureId,
'volume': volume,
},
);
}
@override
Future<void> seekTo(int textureId, Duration position) {
return _channel.invokeMethod<void>(
'seekTo',
<String, dynamic>{
'textureId': textureId,
'location': position.inMilliseconds,
},
);
}
@override
Future<Duration> getPosition(int textureId) async {
return Duration(
milliseconds: await _channel.invokeMethod<int>(
'position',
<String, dynamic>{'textureId': textureId},
),
);
}
@override
Stream<VideoEvent> videoEventsFor(int textureId) {
return _eventChannelFor(textureId)
.receiveBroadcastStream()
.map((dynamic event) {
final Map<dynamic, dynamic> map = event;
switch (map['event']) {
case 'initialized':
return VideoEvent(
eventType: VideoEventType.initialized,
duration: Duration(milliseconds: map['duration']),
size: Size(map['width']?.toDouble() ?? 0.0,
map['height']?.toDouble() ?? 0.0),
);
case 'completed':
return VideoEvent(
eventType: VideoEventType.completed,
);
case 'bufferingUpdate':
final List<dynamic> values = map['values'];
return VideoEvent(
buffered: values.map<DurationRange>(_toDurationRange).toList(),
eventType: VideoEventType.bufferingUpdate,
);
case 'bufferingStart':
return VideoEvent(eventType: VideoEventType.bufferingStart);
case 'bufferingEnd':
return VideoEvent(eventType: VideoEventType.bufferingEnd);
default:
return VideoEvent(eventType: VideoEventType.unknown);
}
});
}
@override
Widget buildView(int textureId) {
return Texture(textureId: textureId);
}
EventChannel _eventChannelFor(int textureId) {
return EventChannel('flutter.io/videoPlayer/videoEvents$textureId');
}
static const Map<VideoFormat, String> _videoFormatStringMap =
<VideoFormat, String>{
VideoFormat.ss: 'ss',
VideoFormat.hls: 'hls',
VideoFormat.dash: 'dash',
VideoFormat.other: 'other',
};
DurationRange _toDurationRange(dynamic value) {
final List<dynamic> pair = value;
return DurationRange(
Duration(milliseconds: pair[0]),
Duration(milliseconds: pair[1]),
);
}
}