diff --git a/packages/video_player_avplay/CHANGELOG.md b/packages/video_player_avplay/CHANGELOG.md index 38bea5078..3e5e27154 100644 --- a/packages/video_player_avplay/CHANGELOG.md +++ b/packages/video_player_avplay/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.14 + +* Synchronize isPlaying state + ## 0.5.13 * Update plusplayer diff --git a/packages/video_player_avplay/README.md b/packages/video_player_avplay/README.md index c05f7b174..d0d3dcd58 100644 --- a/packages/video_player_avplay/README.md +++ b/packages/video_player_avplay/README.md @@ -12,7 +12,7 @@ To use this package, add `video_player_avplay` as a dependency in your `pubspec. ```yaml dependencies: - video_player_avplay: ^0.5.13 + video_player_avplay: ^0.5.14 ``` Then you can import `video_player_avplay` in your Dart code: diff --git a/packages/video_player_avplay/lib/src/closed_caption_file.dart b/packages/video_player_avplay/lib/src/closed_caption_file.dart index 324ffc471..91b44687d 100644 --- a/packages/video_player_avplay/lib/src/closed_caption_file.dart +++ b/packages/video_player_avplay/lib/src/closed_caption_file.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/foundation.dart' show objectRuntimeType; +import 'package:flutter/foundation.dart' show immutable, objectRuntimeType; import 'sub_rip.dart'; import 'web_vtt.dart'; @@ -32,6 +32,7 @@ abstract class ClosedCaptionFile { /// /// A typical closed captioning file will include several [Caption]s, each /// linked to a start and end time. +@immutable class Caption { /// Creates a new [Caption] object. /// @@ -74,4 +75,22 @@ class Caption { 'end: $end, ' 'text: $text)'; } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Caption && + runtimeType == other.runtimeType && + number == other.number && + start == other.start && + end == other.end && + text == other.text; + + @override + int get hashCode => Object.hash( + number, + start, + end, + text, + ); } diff --git a/packages/video_player_avplay/lib/src/video_player_tizen.dart b/packages/video_player_avplay/lib/src/video_player_tizen.dart index a4ec563ff..f942f2729 100644 --- a/packages/video_player_avplay/lib/src/video_player_tizen.dart +++ b/packages/video_player_avplay/lib/src/video_player_tizen.dart @@ -271,6 +271,11 @@ class VideoPlayerTizen extends VideoPlayerPlatform { eventType: VideoEventType.subtitleUpdate, text: map['text']! as String, ); + case 'isPlayingStateUpdate': + return VideoEvent( + eventType: VideoEventType.isPlayingStateUpdate, + isPlayingState: map['isPlayingState']! as bool, + ); default: return VideoEvent(eventType: VideoEventType.unknown); } diff --git a/packages/video_player_avplay/lib/video_player.dart b/packages/video_player_avplay/lib/video_player.dart index ea006f62a..6e9315632 100644 --- a/packages/video_player_avplay/lib/video_player.dart +++ b/packages/video_player_avplay/lib/video_player.dart @@ -37,10 +37,11 @@ VideoPlayerPlatform get _videoPlayerPlatform { /// The duration, current position, buffering state, error state and settings /// of a [VideoPlayerController]. +@immutable class VideoPlayerValue { /// Constructs a video with the given values. Only [duration] is required. The /// rest will initialize with default values when unset. - VideoPlayerValue({ + const VideoPlayerValue({ required this.duration, this.size = Size.zero, this.position = Duration.zero, @@ -212,6 +213,46 @@ class VideoPlayerValue { 'errorDescription: $errorDescription, ' 'isCompleted: $isCompleted),'; } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is VideoPlayerValue && + runtimeType == other.runtimeType && + duration == other.duration && + size == other.size && + position == other.position && + caption == other.caption && + captionOffset == other.captionOffset && + listEquals(tracks, other.tracks) && + buffered == other.buffered && + isInitialized == other.isInitialized && + isPlaying == other.isPlaying && + isLooping == other.isLooping && + isBuffering == other.isBuffering && + volume == other.volume && + playbackSpeed == other.playbackSpeed && + errorDescription == other.errorDescription && + isCompleted == other.isCompleted; + + @override + int get hashCode => Object.hash( + duration, + size, + position, + caption, + captionOffset, + tracks, + buffered, + isInitialized, + isPlaying, + isLooping, + isBuffering, + volume, + playbackSpeed, + errorDescription, + isCompleted, + ); } /// Controls a platform video player, and provides updates when the state is @@ -495,6 +536,15 @@ class VideoPlayerController extends ValueNotifier { text: event.text ?? '', ); value = value.copyWith(caption: caption); + + case VideoEventType.isPlayingStateUpdate: + if (event.isPlayingState ?? false) { + value = value.copyWith( + isPlaying: event.isPlayingState, isCompleted: false); + } else { + value = value.copyWith(isPlaying: event.isPlayingState); + } + case VideoEventType.unknown: break; } diff --git a/packages/video_player_avplay/lib/video_player_platform_interface.dart b/packages/video_player_avplay/lib/video_player_platform_interface.dart index 2f64ac1c6..6b62946c4 100644 --- a/packages/video_player_avplay/lib/video_player_platform_interface.dart +++ b/packages/video_player_avplay/lib/video_player_platform_interface.dart @@ -424,6 +424,7 @@ class VideoEvent { this.size, this.buffered, this.text, + this.isPlayingState, }); /// The type of the event. @@ -449,6 +450,11 @@ class VideoEvent { /// Only used if [eventType] is [VideoEventType.subtitleUpdate]. final String? text; + /// Whether the video is currently playing. + /// + /// Only used if [eventType] is [VideoEventType.isPlayingStateUpdate]. + final bool? isPlayingState; + @override bool operator ==(Object other) { return identical(this, other) || @@ -493,6 +499,12 @@ enum VideoEventType { /// Updated the video subtitle text. subtitleUpdate, + /// The playback state of the video has changed. + /// + /// This event is fired when the video starts or pauses due to user actions or + /// phone calls, or other app media such as music players. + isPlayingStateUpdate, + /// An unknown event has been received. unknown, } diff --git a/packages/video_player_avplay/pubspec.yaml b/packages/video_player_avplay/pubspec.yaml index 2ff960532..6dcf87b04 100644 --- a/packages/video_player_avplay/pubspec.yaml +++ b/packages/video_player_avplay/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avplay description: Flutter plugin for displaying inline video on Tizen TV devices. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/video_player_avplay -version: 0.5.13 +version: 0.5.14 environment: sdk: ">=3.1.0 <4.0.0" diff --git a/packages/video_player_avplay/tizen/src/media_player.cc b/packages/video_player_avplay/tizen/src/media_player.cc index 6f90ad91f..f56568fa3 100644 --- a/packages/video_player_avplay/tizen/src/media_player.cc +++ b/packages/video_player_avplay/tizen/src/media_player.cc @@ -229,6 +229,7 @@ bool MediaPlayer::Play() { LOG_ERROR("[MediaPlayer] player_start failed: %s.", get_error_message(ret)); return false; } + SendIsPlayingState(true); return true; } @@ -253,6 +254,7 @@ bool MediaPlayer::Pause() { LOG_ERROR("[MediaPlayer] player_pause failed: %s.", get_error_message(ret)); return false; } + SendIsPlayingState(false); return true; } @@ -684,6 +686,8 @@ void MediaPlayer::OnPlayCompleted(void *user_data) { void MediaPlayer::OnInterrupted(player_interrupted_code_e code, void *user_data) { + MediaPlayer *self = static_cast(user_data); + self->SendIsPlayingState(false); LOG_ERROR("[MediaPlayer] Interrupt code: %d.", code); } diff --git a/packages/video_player_avplay/tizen/src/plus_player.cc b/packages/video_player_avplay/tizen/src/plus_player.cc index 9ad13407d..0e4bb10e8 100644 --- a/packages/video_player_avplay/tizen/src/plus_player.cc +++ b/packages/video_player_avplay/tizen/src/plus_player.cc @@ -63,6 +63,8 @@ void PlusPlayer::RegisterListener() { listener_.prepared_callback = OnPrepareDone; listener_.seek_completed_callback = OnSeekDone; listener_.subtitle_data_callback = OnSubtitleData; + listener_.playing_callback = OnStateChangedToPlaying; + listener_.resource_conflicted_callback = OnResourceConflicted; ::RegisterListener(player_, &listener_, this); } @@ -259,6 +261,7 @@ bool PlusPlayer::Pause() { return false; } + SendIsPlayingState(false); return true; } @@ -734,7 +737,7 @@ void PlusPlayer::OnResourceConflicted(void *user_data) { LOG_ERROR("[PlusPlayer] Resource conflicted."); PlusPlayer *self = reinterpret_cast(user_data); - self->SendError("PlusPlayer error", "Resource conflicted"); + self->SendIsPlayingState(false); } std::string GetErrorMessage(plusplayer::ErrorType error_code) { @@ -861,4 +864,7 @@ void PlusPlayer::OnCueOutContEvent(const char *cue_out_cont_data, void PlusPlayer::OnChangeSourceDone(bool ret, void *user_data) {} -void PlusPlayer::OnStateChangedToPlaying(void *user_data) {} +void PlusPlayer::OnStateChangedToPlaying(void *user_data) { + PlusPlayer *self = reinterpret_cast(user_data); + self->SendIsPlayingState(true); +} diff --git a/packages/video_player_avplay/tizen/src/video_player.cc b/packages/video_player_avplay/tizen/src/video_player.cc index f33d34123..2f9c8a45c 100644 --- a/packages/video_player_avplay/tizen/src/video_player.cc +++ b/packages/video_player_avplay/tizen/src/video_player.cc @@ -163,6 +163,16 @@ void VideoPlayer::SendPlayCompleted() { PushEvent(flutter::EncodableValue(result)); } +void VideoPlayer::SendIsPlayingState(bool is_playing) { + flutter::EncodableMap result = { + {flutter::EncodableValue("event"), + flutter::EncodableValue("isPlayingStateUpdate")}, + {flutter::EncodableValue("isPlayingState"), + flutter::EncodableValue(is_playing)}, + }; + PushEvent(flutter::EncodableValue(result)); +} + void VideoPlayer::SendError(const std::string &error_code, const std::string &error_message) { if (event_sink_) { diff --git a/packages/video_player_avplay/tizen/src/video_player.h b/packages/video_player_avplay/tizen/src/video_player.h index 99cd3c705..c31b5a6af 100644 --- a/packages/video_player_avplay/tizen/src/video_player.h +++ b/packages/video_player_avplay/tizen/src/video_player.h @@ -71,6 +71,7 @@ class VideoPlayer { void SendBufferingEnd(); void SendSubtitleUpdate(int32_t duration, const std::string &text); void SendPlayCompleted(); + void SendIsPlayingState(bool is_playing); void SendError(const std::string &error_code, const std::string &error_message);