diff --git a/.gitignore b/.gitignore index 5c134814..feb91f29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ +# Do not remove or rename entries in this file, only add new ones +# See https://github.com/flutter/flutter/issues/128635 for more context. + # Miscellaneous *.class +*.lock *.log *.pyc *.swp @@ -8,7 +12,11 @@ .buildlog/ .history .svn/ -migrate_working_dir/ + +# As packages are no longer pinned, we use a lockfile for testing locally. +# When unpinning packages, Using lockfiles ensures that failures in PRs are +# actually due to those PRs, not due to a package being updated. +!/pubspec.lock # IntelliJ related *.iml @@ -16,20 +24,142 @@ migrate_working_dir/ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +# Visual Studio Code related +.classpath +.project +.settings/ +.vscode/* +.ccls-cache + +# This file, on the master branch, should never exist or be checked-in. +# +# On a *final* release branch, that is, what will ship to stable or beta, the +# file can be force added (git add --force) and checked-in in order to effectively +# "pin" the engine artifact version so the flutter tool does not need to use git +# to determine the engine artifacts. +# +# See https://github.com/flutter/flutter/blob/main/docs/tool/Engine-artifacts.md. +/bin/internal/engine.version + +# Flutter repo-specific +/bin/cache/ +/bin/internal/bootstrap.bat +/bin/internal/bootstrap.sh +/bin/internal/engine.realm +/bin/mingit/ +/dev/benchmarks/mega_gallery/ +/dev/bots/.recipe_deps +/dev/bots/android_tools/ +/dev/devicelab/ABresults*.json +/dev/docs/doc/ +/dev/docs/api_docs.zip +/dev/docs/flutter.docs.zip +/dev/docs/lib/ +/dev/docs/pubspec.yaml +/dev/integration_tests/**/xcuserdata +/dev/integration_tests/**/Pods +/packages/flutter/coverage/ +version +analysis_benchmark.json + +# packages file containing multi-root paths +.packages.generated # Flutter/Dart/Pub related -# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. -/pubspec.lock **/doc/api/ .dart_tool/ +.flutter-plugins-dependencies +**/generated_plugin_registrant.dart .packages +.pub-preload-cache/ +.pub-cache/ +.pub/ build/ +flutter_*.png +linked_*.ds +unlinked.ds +unlinked_spec.ds + +# Android related +**/android/**/gradle-wrapper.jar +.gradle/ +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/**/GeneratedPluginRegistrant.java +**/android/key.properties +*.jks +local.properties +**/.cxx/ + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# macOS +**/Flutter/ephemeral/ +**/Pods/ +**/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/ephemeral +**/xcuserdata/ + +# Windows +**/windows/flutter/ephemeral/ +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h +**/windows/flutter/generated_plugins.cmake + +# Linux +**/linux/flutter/ephemeral/ +**/linux/flutter/generated_plugin_registrant.cc +**/linux/flutter/generated_plugin_registrant.h +**/linux/flutter/generated_plugins.cmake + +# Coverage +coverage/ + +# Symbols +app.*.symbols -**/dgph +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!/dev/ci/**/Gemfile.lock +!.vscode/settings.json -# Mkdocs (has own branch) -site \ No newline at end of file +# Monorepo +.cipd +.gclient +.gclient_entries +.python-version +.gclient_previous_custom_vars +.gclient_previous_sync_commits \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 0ece0cf3..5c954331 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -66,6 +66,7 @@ dependencies { def media3_version = "1.7.1" implementation "androidx.media3:media3-exoplayer:$media3_version" implementation "androidx.media3:media3-exoplayer-hls:$media3_version" + implementation "androidx.media3:media3-exoplayer-dash:$media3_version" implementation "androidx.media3:media3-cast:$media3_version" implementation "androidx.media3:media3-test-utils:$media3_version" implementation "androidx.media3:media3-session:$media3_version" diff --git a/android/src/main/java/media/bcc/bccm_player/pigeon/PlaybackPlatformApi.java b/android/src/main/java/media/bcc/bccm_player/pigeon/PlaybackPlatformApi.java index a713fa1e..b960ccc6 100644 --- a/android/src/main/java/media/bcc/bccm_player/pigeon/PlaybackPlatformApi.java +++ b/android/src/main/java/media/bcc/bccm_player/pigeon/PlaybackPlatformApi.java @@ -94,6 +94,17 @@ public enum RepeatMode { } } + public enum DrmType { + WIDEVINE(0), + FAIRPLAY(1); + + final int index; + + DrmType(final int index) { + this.index = index; + } + } + public enum PlaybackState { STOPPED(0), PAUSED(1), @@ -410,77 +421,161 @@ ArrayList toList() { } /** Generated class from Pigeon that represents data sent in messages. */ - public static final class User { - private @Nullable String id; + public static final class DrmConfiguration { + private @NonNull DrmType drmType; - public @Nullable String getId() { - return id; + public @NonNull DrmType getDrmType() { + return drmType; } - public void setId(@Nullable String setterArg) { - this.id = setterArg; + public void setDrmType(@NonNull DrmType setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"drmType\" is null."); + } + this.drmType = setterArg; + } + + private @Nullable String contentKeyId; + + public @Nullable String getContentKeyId() { + return contentKeyId; + } + + public void setContentKeyId(@Nullable String setterArg) { + this.contentKeyId = setterArg; + } + + private @Nullable String fpsCertificateUrl; + + public @Nullable String getFpsCertificateUrl() { + return fpsCertificateUrl; + } + + public void setFpsCertificateUrl(@Nullable String setterArg) { + this.fpsCertificateUrl = setterArg; + } + + private @NonNull String licenseServerUrl; + + public @NonNull String getLicenseServerUrl() { + return licenseServerUrl; } + public void setLicenseServerUrl(@NonNull String setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"licenseServerUrl\" is null."); + } + this.licenseServerUrl = setterArg; + } + + private @Nullable Map licenseRequestHeaders; + + public @Nullable Map getLicenseRequestHeaders() { + return licenseRequestHeaders; + } + + public void setLicenseRequestHeaders(@Nullable Map setterArg) { + this.licenseRequestHeaders = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + DrmConfiguration() {} + @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - User that = (User) o; - return Objects.equals(id, that.id); + DrmConfiguration that = (DrmConfiguration) o; + return drmType.equals(that.drmType) && Objects.equals(contentKeyId, that.contentKeyId) && Objects.equals(fpsCertificateUrl, that.fpsCertificateUrl) && licenseServerUrl.equals(that.licenseServerUrl) && Objects.equals(licenseRequestHeaders, that.licenseRequestHeaders); } @Override public int hashCode() { - return Objects.hash(id); + return Objects.hash(drmType, contentKeyId, fpsCertificateUrl, licenseServerUrl, licenseRequestHeaders); } public static final class Builder { - private @Nullable String id; + private @Nullable DrmType drmType; @CanIgnoreReturnValue - public @NonNull Builder setId(@Nullable String setterArg) { - this.id = setterArg; + public @NonNull Builder setDrmType(@NonNull DrmType setterArg) { + this.drmType = setterArg; return this; } - public @NonNull User build() { - User pigeonReturn = new User(); - pigeonReturn.setId(id); + private @Nullable String contentKeyId; + + @CanIgnoreReturnValue + public @NonNull Builder setContentKeyId(@Nullable String setterArg) { + this.contentKeyId = setterArg; + return this; + } + + private @Nullable String fpsCertificateUrl; + + @CanIgnoreReturnValue + public @NonNull Builder setFpsCertificateUrl(@Nullable String setterArg) { + this.fpsCertificateUrl = setterArg; + return this; + } + + private @Nullable String licenseServerUrl; + + @CanIgnoreReturnValue + public @NonNull Builder setLicenseServerUrl(@NonNull String setterArg) { + this.licenseServerUrl = setterArg; + return this; + } + + private @Nullable Map licenseRequestHeaders; + + @CanIgnoreReturnValue + public @NonNull Builder setLicenseRequestHeaders(@Nullable Map setterArg) { + this.licenseRequestHeaders = setterArg; + return this; + } + + public @NonNull DrmConfiguration build() { + DrmConfiguration pigeonReturn = new DrmConfiguration(); + pigeonReturn.setDrmType(drmType); + pigeonReturn.setContentKeyId(contentKeyId); + pigeonReturn.setFpsCertificateUrl(fpsCertificateUrl); + pigeonReturn.setLicenseServerUrl(licenseServerUrl); + pigeonReturn.setLicenseRequestHeaders(licenseRequestHeaders); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList<>(1); - toListResult.add(id); + ArrayList toListResult = new ArrayList<>(5); + toListResult.add(drmType); + toListResult.add(contentKeyId); + toListResult.add(fpsCertificateUrl); + toListResult.add(licenseServerUrl); + toListResult.add(licenseRequestHeaders); return toListResult; } - static @NonNull User fromList(@NonNull ArrayList pigeonVar_list) { - User pigeonResult = new User(); - Object id = pigeonVar_list.get(0); - pigeonResult.setId((String) id); + static @NonNull DrmConfiguration fromList(@NonNull ArrayList pigeonVar_list) { + DrmConfiguration pigeonResult = new DrmConfiguration(); + Object drmType = pigeonVar_list.get(0); + pigeonResult.setDrmType((DrmType) drmType); + Object contentKeyId = pigeonVar_list.get(1); + pigeonResult.setContentKeyId((String) contentKeyId); + Object fpsCertificateUrl = pigeonVar_list.get(2); + pigeonResult.setFpsCertificateUrl((String) fpsCertificateUrl); + Object licenseServerUrl = pigeonVar_list.get(3); + pigeonResult.setLicenseServerUrl((String) licenseServerUrl); + Object licenseRequestHeaders = pigeonVar_list.get(4); + pigeonResult.setLicenseRequestHeaders((Map) licenseRequestHeaders); return pigeonResult; } } /** Generated class from Pigeon that represents data sent in messages. */ - public static final class SetUrlArgs { - private @NonNull String playerId; - - public @NonNull String getPlayerId() { - return playerId; - } - - public void setPlayerId(@NonNull String setterArg) { - if (setterArg == null) { - throw new IllegalStateException("Nonnull field \"playerId\" is null."); - } - this.playerId = setterArg; - } - + public static final class CastMedia { private @NonNull String url; public @NonNull String getUrl() { @@ -494,42 +589,34 @@ public void setUrl(@NonNull String setterArg) { this.url = setterArg; } - private @Nullable Boolean isLive; + private @Nullable Map customData; - public @Nullable Boolean getIsLive() { - return isLive; + public @Nullable Map getCustomData() { + return customData; } - public void setIsLive(@Nullable Boolean setterArg) { - this.isLive = setterArg; + public void setCustomData(@Nullable Map setterArg) { + this.customData = setterArg; } /** Constructor is non-public to enforce null safety; use Builder. */ - SetUrlArgs() {} + CastMedia() {} @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - SetUrlArgs that = (SetUrlArgs) o; - return playerId.equals(that.playerId) && url.equals(that.url) && Objects.equals(isLive, that.isLive); + CastMedia that = (CastMedia) o; + return url.equals(that.url) && Objects.equals(customData, that.customData); } @Override public int hashCode() { - return Objects.hash(playerId, url, isLive); + return Objects.hash(url, customData); } public static final class Builder { - private @Nullable String playerId; - - @CanIgnoreReturnValue - public @NonNull Builder setPlayerId(@NonNull String setterArg) { - this.playerId = setterArg; - return this; - } - private @Nullable String url; @CanIgnoreReturnValue @@ -538,40 +625,36 @@ public static final class Builder { return this; } - private @Nullable Boolean isLive; + private @Nullable Map customData; @CanIgnoreReturnValue - public @NonNull Builder setIsLive(@Nullable Boolean setterArg) { - this.isLive = setterArg; + public @NonNull Builder setCustomData(@Nullable Map setterArg) { + this.customData = setterArg; return this; } - public @NonNull SetUrlArgs build() { - SetUrlArgs pigeonReturn = new SetUrlArgs(); - pigeonReturn.setPlayerId(playerId); + public @NonNull CastMedia build() { + CastMedia pigeonReturn = new CastMedia(); pigeonReturn.setUrl(url); - pigeonReturn.setIsLive(isLive); + pigeonReturn.setCustomData(customData); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList<>(3); - toListResult.add(playerId); + ArrayList toListResult = new ArrayList<>(2); toListResult.add(url); - toListResult.add(isLive); + toListResult.add(customData); return toListResult; } - static @NonNull SetUrlArgs fromList(@NonNull ArrayList pigeonVar_list) { - SetUrlArgs pigeonResult = new SetUrlArgs(); - Object playerId = pigeonVar_list.get(0); - pigeonResult.setPlayerId((String) playerId); - Object url = pigeonVar_list.get(1); + static @NonNull CastMedia fromList(@NonNull ArrayList pigeonVar_list) { + CastMedia pigeonResult = new CastMedia(); + Object url = pigeonVar_list.get(0); pigeonResult.setUrl((String) url); - Object isLive = pigeonVar_list.get(2); - pigeonResult.setIsLive((Boolean) isLive); + Object customData = pigeonVar_list.get(1); + pigeonResult.setCustomData((Map) customData); return pigeonResult; } } @@ -668,17 +751,37 @@ public void setLastKnownSubtitleLanguage(@Nullable String setterArg) { this.lastKnownSubtitleLanguage = setterArg; } + private @Nullable DrmConfiguration drmConfiguration; + + public @Nullable DrmConfiguration getDrmConfiguration() { + return drmConfiguration; + } + + public void setDrmConfiguration(@Nullable DrmConfiguration setterArg) { + this.drmConfiguration = setterArg; + } + + private @Nullable CastMedia castMedia; + + public @Nullable CastMedia getCastMedia() { + return castMedia; + } + + public void setCastMedia(@Nullable CastMedia setterArg) { + this.castMedia = setterArg; + } + @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } MediaItem that = (MediaItem) o; - return Objects.equals(id, that.id) && Objects.equals(url, that.url) && Objects.equals(mimeType, that.mimeType) && Objects.equals(metadata, that.metadata) && Objects.equals(isLive, that.isLive) && Objects.equals(isOffline, that.isOffline) && Objects.equals(playbackStartPositionMs, that.playbackStartPositionMs) && Objects.equals(lastKnownAudioLanguage, that.lastKnownAudioLanguage) && Objects.equals(lastKnownSubtitleLanguage, that.lastKnownSubtitleLanguage); + return Objects.equals(id, that.id) && Objects.equals(url, that.url) && Objects.equals(mimeType, that.mimeType) && Objects.equals(metadata, that.metadata) && Objects.equals(isLive, that.isLive) && Objects.equals(isOffline, that.isOffline) && Objects.equals(playbackStartPositionMs, that.playbackStartPositionMs) && Objects.equals(lastKnownAudioLanguage, that.lastKnownAudioLanguage) && Objects.equals(lastKnownSubtitleLanguage, that.lastKnownSubtitleLanguage) && Objects.equals(drmConfiguration, that.drmConfiguration) && Objects.equals(castMedia, that.castMedia); } @Override public int hashCode() { - return Objects.hash(id, url, mimeType, metadata, isLive, isOffline, playbackStartPositionMs, lastKnownAudioLanguage, lastKnownSubtitleLanguage); + return Objects.hash(id, url, mimeType, metadata, isLive, isOffline, playbackStartPositionMs, lastKnownAudioLanguage, lastKnownSubtitleLanguage, drmConfiguration, castMedia); } public static final class Builder { @@ -755,6 +858,22 @@ public static final class Builder { return this; } + private @Nullable DrmConfiguration drmConfiguration; + + @CanIgnoreReturnValue + public @NonNull Builder setDrmConfiguration(@Nullable DrmConfiguration setterArg) { + this.drmConfiguration = setterArg; + return this; + } + + private @Nullable CastMedia castMedia; + + @CanIgnoreReturnValue + public @NonNull Builder setCastMedia(@Nullable CastMedia setterArg) { + this.castMedia = setterArg; + return this; + } + public @NonNull MediaItem build() { MediaItem pigeonReturn = new MediaItem(); pigeonReturn.setId(id); @@ -766,13 +885,15 @@ public static final class Builder { pigeonReturn.setPlaybackStartPositionMs(playbackStartPositionMs); pigeonReturn.setLastKnownAudioLanguage(lastKnownAudioLanguage); pigeonReturn.setLastKnownSubtitleLanguage(lastKnownSubtitleLanguage); + pigeonReturn.setDrmConfiguration(drmConfiguration); + pigeonReturn.setCastMedia(castMedia); return pigeonReturn; } } @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList<>(9); + ArrayList toListResult = new ArrayList<>(11); toListResult.add(id); toListResult.add(url); toListResult.add(mimeType); @@ -782,6 +903,8 @@ ArrayList toList() { toListResult.add(playbackStartPositionMs); toListResult.add(lastKnownAudioLanguage); toListResult.add(lastKnownSubtitleLanguage); + toListResult.add(drmConfiguration); + toListResult.add(castMedia); return toListResult; } @@ -805,6 +928,10 @@ ArrayList toList() { pigeonResult.setLastKnownAudioLanguage((String) lastKnownAudioLanguage); Object lastKnownSubtitleLanguage = pigeonVar_list.get(8); pigeonResult.setLastKnownSubtitleLanguage((String) lastKnownSubtitleLanguage); + Object drmConfiguration = pigeonVar_list.get(9); + pigeonResult.setDrmConfiguration((DrmConfiguration) drmConfiguration); + Object castMedia = pigeonVar_list.get(10); + pigeonResult.setCastMedia((CastMedia) castMedia); return pigeonResult; } } @@ -1240,7 +1367,7 @@ ArrayList toList() { Object playbackPositionMs = pigeonVar_list.get(7); pigeonResult.setPlaybackPositionMs((Double) playbackPositionMs); Object textureId = pigeonVar_list.get(8); - pigeonResult.setTextureId((Long) textureId); + pigeonResult.setTextureId((textureId == null) ? null : ((textureId instanceof Integer) ? (Integer) textureId : (Long) textureId)); Object volume = pigeonVar_list.get(9); pigeonResult.setVolume((Double) volume); Object error = pigeonVar_list.get(10); @@ -1409,9 +1536,9 @@ ArrayList toList() { static @NonNull VideoSize fromList(@NonNull ArrayList pigeonVar_list) { VideoSize pigeonResult = new VideoSize(); Object width = pigeonVar_list.get(0); - pigeonResult.setWidth((Long) width); + pigeonResult.setWidth((width == null) ? null : ((width instanceof Integer) ? (Integer) width : (Long) width)); Object height = pigeonVar_list.get(1); - pigeonResult.setHeight((Long) height); + pigeonResult.setHeight((height == null) ? null : ((height instanceof Integer) ? (Integer) height : (Long) height)); return pigeonResult; } } @@ -1981,11 +2108,11 @@ ArrayList toList() { Object frameRate = pigeonVar_list.get(3); pigeonResult.setFrameRate((Double) frameRate); Object bitrate = pigeonVar_list.get(4); - pigeonResult.setBitrate((Long) bitrate); + pigeonResult.setBitrate((bitrate == null) ? null : ((bitrate instanceof Integer) ? (Integer) bitrate : (Long) bitrate)); Object width = pigeonVar_list.get(5); - pigeonResult.setWidth((Long) width); + pigeonResult.setWidth((width == null) ? null : ((width instanceof Integer) ? (Integer) width : (Long) width)); Object height = pigeonVar_list.get(6); - pigeonResult.setHeight((Long) height); + pigeonResult.setHeight((height == null) ? null : ((height instanceof Integer) ? (Integer) height : (Long) height)); Object downloaded = pigeonVar_list.get(7); pigeonResult.setDownloaded((Boolean) downloaded); Object isSelected = pigeonVar_list.get(8); @@ -2605,63 +2732,67 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 129: { Object value = readValue(buffer); - return value == null ? null : BufferMode.values()[((Long) value).intValue()]; + return value == null ? null : BufferMode.values()[(int) value]; } case (byte) 130: { Object value = readValue(buffer); - return value == null ? null : RepeatMode.values()[((Long) value).intValue()]; + return value == null ? null : RepeatMode.values()[(int) value]; } case (byte) 131: { Object value = readValue(buffer); - return value == null ? null : PlaybackState.values()[((Long) value).intValue()]; + return value == null ? null : DrmType.values()[(int) value]; } case (byte) 132: { Object value = readValue(buffer); - return value == null ? null : CastConnectionState.values()[((Long) value).intValue()]; + return value == null ? null : PlaybackState.values()[(int) value]; } case (byte) 133: { Object value = readValue(buffer); - return value == null ? null : TrackType.values()[((Long) value).intValue()]; + return value == null ? null : CastConnectionState.values()[(int) value]; + } + case (byte) 134: { + Object value = readValue(buffer); + return value == null ? null : TrackType.values()[(int) value]; } - case (byte) 134: - return NpawConfig.fromList((ArrayList) readValue(buffer)); case (byte) 135: - return AppConfig.fromList((ArrayList) readValue(buffer)); + return NpawConfig.fromList((ArrayList) readValue(buffer)); case (byte) 136: - return User.fromList((ArrayList) readValue(buffer)); + return AppConfig.fromList((ArrayList) readValue(buffer)); case (byte) 137: - return SetUrlArgs.fromList((ArrayList) readValue(buffer)); + return DrmConfiguration.fromList((ArrayList) readValue(buffer)); case (byte) 138: - return MediaItem.fromList((ArrayList) readValue(buffer)); + return CastMedia.fromList((ArrayList) readValue(buffer)); case (byte) 139: - return MediaMetadata.fromList((ArrayList) readValue(buffer)); + return MediaItem.fromList((ArrayList) readValue(buffer)); case (byte) 140: - return PlayerStateSnapshot.fromList((ArrayList) readValue(buffer)); + return MediaMetadata.fromList((ArrayList) readValue(buffer)); case (byte) 141: - return PlayerError.fromList((ArrayList) readValue(buffer)); + return PlayerStateSnapshot.fromList((ArrayList) readValue(buffer)); case (byte) 142: - return VideoSize.fromList((ArrayList) readValue(buffer)); + return PlayerError.fromList((ArrayList) readValue(buffer)); case (byte) 143: - return ChromecastState.fromList((ArrayList) readValue(buffer)); + return VideoSize.fromList((ArrayList) readValue(buffer)); case (byte) 144: - return MediaInfo.fromList((ArrayList) readValue(buffer)); + return ChromecastState.fromList((ArrayList) readValue(buffer)); case (byte) 145: - return PlayerTracksSnapshot.fromList((ArrayList) readValue(buffer)); + return MediaInfo.fromList((ArrayList) readValue(buffer)); case (byte) 146: - return Track.fromList((ArrayList) readValue(buffer)); + return PlayerTracksSnapshot.fromList((ArrayList) readValue(buffer)); case (byte) 147: - return PrimaryPlayerChangedEvent.fromList((ArrayList) readValue(buffer)); + return Track.fromList((ArrayList) readValue(buffer)); case (byte) 148: - return PlayerStateUpdateEvent.fromList((ArrayList) readValue(buffer)); + return PrimaryPlayerChangedEvent.fromList((ArrayList) readValue(buffer)); case (byte) 149: - return PositionDiscontinuityEvent.fromList((ArrayList) readValue(buffer)); + return PlayerStateUpdateEvent.fromList((ArrayList) readValue(buffer)); case (byte) 150: - return PlaybackStateChangedEvent.fromList((ArrayList) readValue(buffer)); + return PositionDiscontinuityEvent.fromList((ArrayList) readValue(buffer)); case (byte) 151: - return PlaybackEndedEvent.fromList((ArrayList) readValue(buffer)); + return PlaybackStateChangedEvent.fromList((ArrayList) readValue(buffer)); case (byte) 152: - return PictureInPictureModeChangedEvent.fromList((ArrayList) readValue(buffer)); + return PlaybackEndedEvent.fromList((ArrayList) readValue(buffer)); case (byte) 153: + return PictureInPictureModeChangedEvent.fromList((ArrayList) readValue(buffer)); + case (byte) 154: return MediaItemTransitionEvent.fromList((ArrayList) readValue(buffer)); default: return super.readValueOfType(type, buffer); @@ -2676,74 +2807,77 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { } else if (value instanceof RepeatMode) { stream.write(130); writeValue(stream, value == null ? null : ((RepeatMode) value).index); - } else if (value instanceof PlaybackState) { + } else if (value instanceof DrmType) { stream.write(131); + writeValue(stream, value == null ? null : ((DrmType) value).index); + } else if (value instanceof PlaybackState) { + stream.write(132); writeValue(stream, value == null ? null : ((PlaybackState) value).index); } else if (value instanceof CastConnectionState) { - stream.write(132); + stream.write(133); writeValue(stream, value == null ? null : ((CastConnectionState) value).index); } else if (value instanceof TrackType) { - stream.write(133); + stream.write(134); writeValue(stream, value == null ? null : ((TrackType) value).index); } else if (value instanceof NpawConfig) { - stream.write(134); + stream.write(135); writeValue(stream, ((NpawConfig) value).toList()); } else if (value instanceof AppConfig) { - stream.write(135); - writeValue(stream, ((AppConfig) value).toList()); - } else if (value instanceof User) { stream.write(136); - writeValue(stream, ((User) value).toList()); - } else if (value instanceof SetUrlArgs) { + writeValue(stream, ((AppConfig) value).toList()); + } else if (value instanceof DrmConfiguration) { stream.write(137); - writeValue(stream, ((SetUrlArgs) value).toList()); - } else if (value instanceof MediaItem) { + writeValue(stream, ((DrmConfiguration) value).toList()); + } else if (value instanceof CastMedia) { stream.write(138); + writeValue(stream, ((CastMedia) value).toList()); + } else if (value instanceof MediaItem) { + stream.write(139); writeValue(stream, ((MediaItem) value).toList()); } else if (value instanceof MediaMetadata) { - stream.write(139); + stream.write(140); writeValue(stream, ((MediaMetadata) value).toList()); } else if (value instanceof PlayerStateSnapshot) { - stream.write(140); + stream.write(141); writeValue(stream, ((PlayerStateSnapshot) value).toList()); } else if (value instanceof PlayerError) { - stream.write(141); + stream.write(142); writeValue(stream, ((PlayerError) value).toList()); } else if (value instanceof VideoSize) { - stream.write(142); + stream.write(143); writeValue(stream, ((VideoSize) value).toList()); } else if (value instanceof ChromecastState) { - stream.write(143); + stream.write(144); writeValue(stream, ((ChromecastState) value).toList()); } else if (value instanceof MediaInfo) { - stream.write(144); + stream.write(145); writeValue(stream, ((MediaInfo) value).toList()); } else if (value instanceof PlayerTracksSnapshot) { - stream.write(145); + stream.write(146); writeValue(stream, ((PlayerTracksSnapshot) value).toList()); } else if (value instanceof Track) { - stream.write(146); + stream.write(147); writeValue(stream, ((Track) value).toList()); } else if (value instanceof PrimaryPlayerChangedEvent) { - stream.write(147); + stream.write(148); writeValue(stream, ((PrimaryPlayerChangedEvent) value).toList()); } else if (value instanceof PlayerStateUpdateEvent) { - stream.write(148); + stream.write(149); writeValue(stream, ((PlayerStateUpdateEvent) value).toList()); } else if (value instanceof PositionDiscontinuityEvent) { - stream.write(149); + stream.write(150); writeValue(stream, ((PositionDiscontinuityEvent) value).toList()); } else if (value instanceof PlaybackStateChangedEvent) { - stream.write(150); + stream.write(151); writeValue(stream, ((PlaybackStateChangedEvent) value).toList()); } else if (value instanceof PlaybackEndedEvent) { - stream.write(151); + stream.write(152); writeValue(stream, ((PlaybackEndedEvent) value).toList()); } else if (value instanceof PictureInPictureModeChangedEvent) { - stream.write(152); + stream.write(153); writeValue(stream, ((PictureInPictureModeChangedEvent) value).toList()); } else if (value instanceof MediaItemTransitionEvent) { - stream.write(153); + stream.write(154); writeValue(stream, ((MediaItemTransitionEvent) value).toList()); } else { super.writeValue(stream, value); @@ -2944,7 +3078,7 @@ public void error(Throwable error) { (message, reply) -> { ArrayList wrapped = new ArrayList<>(); ArrayList args = (ArrayList) message; - Long textureIdArg = (Long) args.get(0); + Number textureIdArg = (Number) args.get(0); Result resultCallback = new Result() { public void success(Boolean result) { @@ -2958,7 +3092,7 @@ public void error(Throwable error) { } }; - api.disposeVideoTexture(textureIdArg, resultCallback); + api.disposeVideoTexture((textureIdArg == null) ? null : textureIdArg.longValue(), resultCallback); }); } else { channel.setMessageHandler(null); @@ -2974,7 +3108,7 @@ public void error(Throwable error) { ArrayList wrapped = new ArrayList<>(); ArrayList args = (ArrayList) message; String playerIdArg = (String) args.get(0); - Long textureIdArg = (Long) args.get(1); + Number textureIdArg = (Number) args.get(1); Result resultCallback = new Result() { public void success(Long result) { @@ -2988,7 +3122,7 @@ public void error(Throwable error) { } }; - api.switchToVideoTexture(playerIdArg, textureIdArg, resultCallback); + api.switchToVideoTexture(playerIdArg, (textureIdArg == null) ? null : textureIdArg.longValue(), resultCallback); }); } else { channel.setMessageHandler(null); @@ -3064,10 +3198,10 @@ public void error(Throwable error) { (message, reply) -> { ArrayList wrapped = new ArrayList<>(); ArrayList args = (ArrayList) message; - Long viewIdArg = (Long) args.get(0); + Number viewIdArg = (Number) args.get(0); Boolean visibleArg = (Boolean) args.get(1); try { - api.setPlayerViewVisibility(viewIdArg, visibleArg); + api.setPlayerViewVisibility((viewIdArg == null) ? null : viewIdArg.longValue(), visibleArg); wrapped.add(0, null); } catch (Throwable exception) { diff --git a/android/src/main/kotlin/media/bcc/bccm_player/players/PlayerController.kt b/android/src/main/kotlin/media/bcc/bccm_player/players/PlayerController.kt index 389a5dd4..39779a3f 100644 --- a/android/src/main/kotlin/media/bcc/bccm_player/players/PlayerController.kt +++ b/android/src/main/kotlin/media/bcc/bccm_player/players/PlayerController.kt @@ -9,6 +9,7 @@ import androidx.core.math.MathUtils.clamp import androidx.media3.common.C import androidx.media3.common.C.TRACK_TYPE_AUDIO import androidx.media3.common.MediaItem +import androidx.media3.common.MediaItem.DrmConfiguration import androidx.media3.common.MediaMetadata import androidx.media3.common.Player import androidx.media3.common.TrackSelectionOverride @@ -32,6 +33,14 @@ import media.bcc.bccm_player.utils.NoOpVoidResult import media.bcc.bccm_player.utils.TrackUtils import java.util.UUID +import android.util.Log +import org.json.JSONArray +import org.json.JSONObject +import media.bcc.bccm_player.players.chromecast.CastMediaItemConverter.Companion.PLAYER_DATA_DRM_LICENSE_SERVER_URL +import media.bcc.bccm_player.players.chromecast.CastMediaItemConverter.Companion.PLAYER_DATA_CAST_URL +import media.bcc.bccm_player.players.chromecast.CastMediaItemConverter.Companion.PLAYER_DATA_CAST_CUSTOM_DATA +import media.bcc.bccm_player.players.chromecast.CastMediaItemConverter.Companion.PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS + abstract class PlayerController : Player.Listener { abstract val id: String @@ -110,20 +119,28 @@ abstract class PlayerController : Player.Listener { @SuppressLint("UnsafeOptInUsageError") fun replaceCurrentMediaItem(mediaItem: PlaybackPlatformApi.MediaItem, autoplay: Boolean?) { - this.isLive = mediaItem.isLive ?: false - var androidMi = mapMediaItem(mediaItem) - var playbackStartPositionMs: Double? = null - if (!this.isLive && mediaItem.playbackStartPositionMs != null) { - playbackStartPositionMs = mediaItem.playbackStartPositionMs - } + try { + this.isLive = mediaItem.isLive ?: false + var androidMi = mapMediaItem(mediaItem) + var playbackStartPositionMs: Double? = null + if (!this.isLive && mediaItem.playbackStartPositionMs != null) { + playbackStartPositionMs = mediaItem.playbackStartPositionMs + } - player.setMediaItem(androidMi, playbackStartPositionMs?.toLong() ?: 0) - if (playbackStartPositionMs != null) { - player.seekTo(playbackStartPositionMs.toLong()) + player.setMediaItem(androidMi, playbackStartPositionMs?.toLong() ?: 0) + if (playbackStartPositionMs != null) { + player.seekTo(playbackStartPositionMs.toLong()) + } + manualUpdateEvent() + player.playWhenReady = autoplay == true + player.prepare() + } catch (e: Exception) { + Log.e( + "bccm-@PlayerController-replaceCurrentMediaItem", + "Something went wrong: $e" + ); + throw e; } - manualUpdateEvent() - player.playWhenReady = autoplay == true - player.prepare() } fun manualUpdateEvent() { @@ -147,6 +164,7 @@ abstract class PlayerController : Player.Listener { return extraMeta } + // map for android @SuppressLint("UnsafeOptInUsageError") private fun mapMediaItem(mediaItem: PlaybackPlatformApi.MediaItem): MediaItem { val metaBuilder = MediaMetadata.Builder() @@ -189,6 +207,24 @@ abstract class PlayerController : Player.Listener { } } + var drmConfiguration: DrmConfiguration? = null + if (mediaItem.drmConfiguration != null && mediaItem.drmConfiguration?.drmType != null && mediaItem.drmConfiguration?.drmType == PlaybackPlatformApi.DrmType.WIDEVINE && mediaItem.drmConfiguration?.licenseServerUrl != null && mediaItem.drmConfiguration?.licenseServerUrl?.isNotEmpty() == true) { + exoExtras.putString(PLAYER_DATA_DRM_LICENSE_SERVER_URL, mediaItem.drmConfiguration?.licenseServerUrl) + if (!mediaItem.drmConfiguration?.licenseRequestHeaders.isNullOrEmpty()) { + exoExtras.putString( + PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS, + if (mediaItem.drmConfiguration?.licenseRequestHeaders != null) JSONObject( + mediaItem.drmConfiguration?.licenseRequestHeaders as Map + ).toString() else null + ) + } + + drmConfiguration = DrmConfiguration.Builder(C.WIDEVINE_UUID) + .setLicenseUri(mediaItem.drmConfiguration?.licenseServerUrl) + .setLicenseRequestHeaders(mediaItem.drmConfiguration?.licenseRequestHeaders as Map) + .build() + } + metaBuilder .setTitle(mediaItem.metadata?.title) .setArtist(mediaItem.metadata?.artist) @@ -218,9 +254,12 @@ abstract class PlayerController : Player.Listener { .setUri(mediaItem.url) .setMimeType(mimeType) .setMediaId(mediaItem.id ?: UUID.randomUUID().toString()) - .setMediaMetadata(metaBuilder.build()).build() + .setMediaMetadata(metaBuilder.build()) + .setDrmConfiguration(drmConfiguration) + .build() } + // map for dart fun mapMediaItem(mediaItem: MediaItem): PlaybackPlatformApi.MediaItem { val metaBuilder = PlaybackPlatformApi.MediaMetadata.Builder() if (mediaItem.mediaMetadata.artworkUri != null) { @@ -253,6 +292,36 @@ abstract class PlayerController : Player.Listener { } else if (mediaItem.localConfiguration?.mimeType != null) { miBuilder.setMimeType(mediaItem.localConfiguration?.mimeType) } + + if (extraMeta.containsKey(PLAYER_DATA_DRM_LICENSE_SERVER_URL)) { + var drmLicenseRequestHeaders: Map? = null + + if (extraMeta.containsKey(PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS) && !extraMeta[PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS].isNullOrEmpty()) { + drmLicenseRequestHeaders = JSONObject(extraMeta[PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS]!!).toMap() as Map + } + + val drmConfiguration = PlaybackPlatformApi.DrmConfiguration.Builder() + .setDrmType(PlaybackPlatformApi.DrmType.WIDEVINE) + .setFpsCertificateUrl(null) + .setLicenseServerUrl(extraMeta[PLAYER_DATA_DRM_LICENSE_SERVER_URL]!!) + .setLicenseRequestHeaders(drmLicenseRequestHeaders) + .build() + miBuilder.setDrmConfiguration(drmConfiguration) + } + if (extraMeta.containsKey(PLAYER_DATA_CAST_URL)) { + var customData: Map? = null + + if (extraMeta.containsKey(PLAYER_DATA_CAST_CUSTOM_DATA) && !extraMeta[PLAYER_DATA_CAST_CUSTOM_DATA].isNullOrEmpty()) { + customData = JSONObject(extraMeta[PLAYER_DATA_CAST_CUSTOM_DATA]!!).toMap() as Map + } + + val castMedia = PlaybackPlatformApi.CastMedia.Builder() + .setUrl(extraMeta[PLAYER_DATA_CAST_URL]!!) + .setCustomData(customData) + .build() + miBuilder.setCastMedia(castMedia) + } + miBuilder.setId(mediaItem.mediaId) return miBuilder.build() @@ -455,4 +524,18 @@ abstract class PlayerController : Player.Listener { } abstract fun setMixWithOthers(mixWithOthers: Boolean); + + private fun JSONObject.toMap(): Map = keys().asSequence().associateWith { + when (val value = this[it]) + { + is JSONArray -> + { + val map = (0 until value.length()).associate { Pair(it.toString(), value[it]) } + JSONObject(map).toMap().values.toList() + } + is JSONObject -> value.toMap() + JSONObject.NULL -> null + else -> value + } + } } \ No newline at end of file diff --git a/android/src/main/kotlin/media/bcc/bccm_player/players/chromecast/CastMediaItemConverter.kt b/android/src/main/kotlin/media/bcc/bccm_player/players/chromecast/CastMediaItemConverter.kt index acf66ad7..5f105c79 100644 --- a/android/src/main/kotlin/media/bcc/bccm_player/players/chromecast/CastMediaItemConverter.kt +++ b/android/src/main/kotlin/media/bcc/bccm_player/players/chromecast/CastMediaItemConverter.kt @@ -196,10 +196,12 @@ class CastMediaItemConverter : MediaItemConverter { const val PLAYER_DATA_IS_OFFLINE = "$BCCM_PLAYER_DATA.is_offline" const val PLAYER_DATA_MIME_TYPE = "$BCCM_PLAYER_DATA.mime_type" const val PLAYER_DATA_DURATION = "$BCCM_PLAYER_DATA.durationMs" - const val PLAYER_DATA_LAST_KNOWN_AUDIO_LANGUAGE = - "$BCCM_PLAYER_DATA.last_known_audio_language" - const val PLAYER_DATA_LAST_KNOWN_SUBTITLE_LANGUAGE = - "$BCCM_PLAYER_DATA.last_known_subtitle_language" + const val PLAYER_DATA_LAST_KNOWN_AUDIO_LANGUAGE = "$BCCM_PLAYER_DATA.last_known_audio_language" + const val PLAYER_DATA_LAST_KNOWN_SUBTITLE_LANGUAGE = "$BCCM_PLAYER_DATA.last_known_subtitle_language" + const val PLAYER_DATA_DRM_LICENSE_SERVER_URL = "$BCCM_PLAYER_DATA.drm.license_server.url" + const val PLAYER_DATA_DRM_LICENSE_REQUEST_HEADERS = "$BCCM_PLAYER_DATA.drm.license_server.request_headers" + const val PLAYER_DATA_CAST_URL = "$BCCM_PLAYER_DATA.cast.url" + const val PLAYER_DATA_CAST_CUSTOM_DATA = "$BCCM_PLAYER_DATA.cast.custom_data" // Serialization. private fun getCustomData(mediaItem: MediaItem): JSONObject { diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 4f2b532f..fab6c9fa 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -2,5 +2,5 @@ PictureInPicture Dummy Button DUMMY\nCONTENT - + exo-download-notification-channel-name \ No newline at end of file diff --git a/example/.flutter-plugins b/example/.flutter-plugins new file mode 100644 index 00000000..11f3beb6 --- /dev/null +++ b/example/.flutter-plugins @@ -0,0 +1,7 @@ +# This is a generated file; do not edit or check into version control. +bccm_player=/Users/kautsaralbana/Downloads/works/bccm-player/ +connectivity_plus=/Users/kautsaralbana/.puro/shared/pub_cache/hosted/pub.dev/connectivity_plus-6.1.4/ +flutter_plugin_android_lifecycle=/Users/kautsaralbana/.puro/shared/pub_cache/hosted/pub.dev/flutter_plugin_android_lifecycle-2.0.28/ +package_info_plus=/Users/kautsaralbana/.puro/shared/pub_cache/hosted/pub.dev/package_info_plus-8.3.0/ +screen_protector=/Users/kautsaralbana/.puro/shared/pub_cache/hosted/pub.dev/screen_protector-1.4.2+1/ +wakelock_plus=/Users/kautsaralbana/.puro/shared/pub_cache/hosted/pub.dev/wakelock_plus-1.3.2/ diff --git a/example/.gitignore b/example/.gitignore index 24476c5d..feb91f29 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,5 +1,9 @@ +# Do not remove or rename entries in this file, only add new ones +# See https://github.com/flutter/flutter/issues/128635 for more context. + # Miscellaneous *.class +*.lock *.log *.pyc *.swp @@ -8,7 +12,11 @@ .buildlog/ .history .svn/ -migrate_working_dir/ + +# As packages are no longer pinned, we use a lockfile for testing locally. +# When unpinning packages, Using lockfiles ensures that failures in PRs are +# actually due to those PRs, not due to a package being updated. +!/pubspec.lock # IntelliJ related *.iml @@ -16,29 +24,142 @@ migrate_working_dir/ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +# Visual Studio Code related +.classpath +.project +.settings/ +.vscode/* +.ccls-cache + +# This file, on the master branch, should never exist or be checked-in. +# +# On a *final* release branch, that is, what will ship to stable or beta, the +# file can be force added (git add --force) and checked-in in order to effectively +# "pin" the engine artifact version so the flutter tool does not need to use git +# to determine the engine artifacts. +# +# See https://github.com/flutter/flutter/blob/main/docs/tool/Engine-artifacts.md. +/bin/internal/engine.version + +# Flutter repo-specific +/bin/cache/ +/bin/internal/bootstrap.bat +/bin/internal/bootstrap.sh +/bin/internal/engine.realm +/bin/mingit/ +/dev/benchmarks/mega_gallery/ +/dev/bots/.recipe_deps +/dev/bots/android_tools/ +/dev/devicelab/ABresults*.json +/dev/docs/doc/ +/dev/docs/api_docs.zip +/dev/docs/flutter.docs.zip +/dev/docs/lib/ +/dev/docs/pubspec.yaml +/dev/integration_tests/**/xcuserdata +/dev/integration_tests/**/Pods +/packages/flutter/coverage/ +version +analysis_benchmark.json + +# packages file containing multi-root paths +.packages.generated # Flutter/Dart/Pub related **/doc/api/ -**/ios/Flutter/.last_build_id .dart_tool/ -.flutter-plugins .flutter-plugins-dependencies +**/generated_plugin_registrant.dart .packages +.pub-preload-cache/ .pub-cache/ .pub/ -/build/ +build/ +flutter_*.png +linked_*.ds +unlinked.ds +unlinked_spec.ds + +# Android related +**/android/**/gradle-wrapper.jar +.gradle/ +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/**/GeneratedPluginRegistrant.java +**/android/key.properties +*.jks +local.properties +**/.cxx/ + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# macOS +**/Flutter/ephemeral/ +**/Pods/ +**/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/ephemeral +**/xcuserdata/ + +# Windows +**/windows/flutter/ephemeral/ +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h +**/windows/flutter/generated_plugins.cmake + +# Linux +**/linux/flutter/ephemeral/ +**/linux/flutter/generated_plugin_registrant.cc +**/linux/flutter/generated_plugin_registrant.h +**/linux/flutter/generated_plugins.cmake + +# Coverage +coverage/ -# Symbolication related +# Symbols app.*.symbols -# Obfuscation related -app.*.map.json +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!/dev/ci/**/Gemfile.lock +!.vscode/settings.json -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release +# Monorepo +.cipd +.gclient +.gclient_entries +.python-version +.gclient_previous_custom_vars +.gclient_previous_sync_commits \ No newline at end of file diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml index 61b6c4de..04e69e71 100644 --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -7,6 +7,9 @@ # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. +analyzer: + errors: + prefer_const_constructors: ignore include: package:flutter_lints/flutter.yaml linter: diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index fcf9a863..0e54a9c7 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -14,7 +14,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/example/android/gradle.properties b/example/android/gradle.properties index d4a6d5f9..abac32bb 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-Xmx4608m android.useAndroidX=true android.enableJetifier=true -kotlin.code.style=official \ No newline at end of file +kotlin.code.style=official diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 57d50b18..c9924233 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/example/lib/app.dart b/example/lib/app.dart new file mode 100644 index 00000000..93c7c837 --- /dev/null +++ b/example/lib/app.dart @@ -0,0 +1,91 @@ +import 'package:bccm_player/bccm_player.dart'; +import 'package:bccm_player_example/examples/drm_player.dart'; +import 'package:bccm_player_example/examples/preload_players.dart'; +import 'package:bccm_player_example/examples/queue.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'examples/custom_controls.dart'; +import 'examples/downloader.dart'; +import 'examples/list_of_players.dart'; +import 'examples/native_controls.dart'; +import 'examples/playground.dart'; +import 'examples/simple_player.dart'; + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + return MediaQuery( + data: MediaQuery.of(context).copyWith(navigationMode: NavigationMode.directional), + child: Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), + }, + child: Scaffold( + appBar: AppBar( + backgroundColor: Colors.primaries.first, + title: const Text('Plugin example app', style: TextStyle(color: Colors.white)), + actions: const [ + Padding( + padding: EdgeInsets.only(right: 16), + child: CastButton(color: Colors.black), + ), + ], + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(width: double.infinity), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => QueueExample())), + child: Text('Queu'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => Playground())), + child: Text('Playground'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => ListOfPlayers())), + child: Text('List of Players'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => SimplePlayer())), + child: Text('Simple Players'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => CustomControls())), + child: Text('Custom Controls'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => NativeControls())), + child: Text('Native Controls'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => Downloader())), + child: Text('Downloader'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => DrmPlayer())), + child: Text('DRM Player'), + ), + TextButton( + onPressed: () => Navigator.of(context).push(MaterialPageRoute(builder: (context) => PreloadPlayerPage())), + child: Text('Preload Player'), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/example/lib/examples/drm_player.dart b/example/lib/examples/drm_player.dart new file mode 100644 index 00000000..948f6b63 --- /dev/null +++ b/example/lib/examples/drm_player.dart @@ -0,0 +1,71 @@ +import 'dart:io'; + +import 'package:bccm_player/bccm_player.dart'; +import 'package:flutter/material.dart'; + +class DrmPlayer extends StatefulWidget { + const DrmPlayer({super.key}); + + @override + State createState() => _DrmPlayerState(); +} + +class _DrmPlayerState extends State { + late BccmPlayerController playerController; + + @override + void initState() { + playerController = BccmPlayerController(MediaItem( + url: TempDrmSource.file, + mimeType: Platform.isAndroid ? 'application/dash+xml' : 'application/vnd.apple.mpegurl', + drmConfiguration: DrmConfiguration( + drmType: DrmType.widevine, + licenseServerUrl: TempDrmSource.licenseUrl, + licenseRequestHeaders: {'X-AxDRM-Message': TempDrmSource.token}, + ), + )); + playerController.addListener(playerListener); + playerController.events.listen(playerEventListener); + playerController.initialize().then((_) => playerController.setMixWithOthers(false)); + super.initState(); + } + + void playerListener() { + final result = playerController.value; + print('@playerListener: ${result.playbackState}'); + } + + void playerEventListener(dynamic event) { + print('@playerEventListener: $event'); + } + + @override + void dispose() { + playerController.removeListener(playerListener); + playerController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Column( + children: [ + BccmPlayerView( + playerController, + config: BccmPlayerViewConfig(useSurfaceView: true), + ), + ], + ), + ); + } +} + +class TempDrmSource { + TempDrmSource._(); + + static const String file = 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd'; + static const String token = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU'; + static const String licenseUrl = 'https://drm-widevine-licensing.axtest.net/AcquireLicense'; +} diff --git a/example/lib/examples/list_of_players.dart b/example/lib/examples/list_of_players.dart index 7f739114..7b2d4104 100644 --- a/example/lib/examples/list_of_players.dart +++ b/example/lib/examples/list_of_players.dart @@ -1,6 +1,7 @@ import 'package:bccm_player/bccm_player.dart'; import 'package:bccm_player_example/example_videos.dart'; import 'package:flutter/material.dart'; +import 'package:screen_protector/screen_protector.dart'; class ListOfPlayers extends StatefulWidget { const ListOfPlayers({super.key}); @@ -14,6 +15,8 @@ class _ListOfPlayersState extends State { @override void initState() { + ScreenProtector.preventScreenshotOn(); + ScreenProtector.protectDataLeakageWithBlur(); controllers = [ BccmPlayerController.empty(), ...exampleVideos.map( @@ -29,6 +32,8 @@ class _ListOfPlayersState extends State { @override void dispose() { + ScreenProtector.preventScreenshotOff(); + ScreenProtector.protectDataLeakageWithBlurOff(); for (var element in controllers) { if (!element.isPrimary) element.dispose(); } @@ -37,21 +42,23 @@ class _ListOfPlayersState extends State { @override Widget build(BuildContext context) { - return ListView( - children: [ - ...controllers.map( - (controller) => Column( - children: [ - BccmPlayerView(controller), - ElevatedButton( - onPressed: () { - controller.setPrimary(); - }, - child: const Text('Make primary')), - ], - ), - ) - ], + return Scaffold( + body: ListView( + children: [ + ...controllers.map( + (controller) => Column( + children: [ + BccmPlayerView(controller), + ElevatedButton( + onPressed: () { + controller.setPrimary(); + }, + child: const Text('Make primary')), + ], + ), + ) + ], + ), ); } } diff --git a/example/lib/examples/preload_players.dart b/example/lib/examples/preload_players.dart new file mode 100644 index 00000000..9d4143bc --- /dev/null +++ b/example/lib/examples/preload_players.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:bccm_player/bccm_player.dart'; +import 'package:bccm_player_example/example_videos.dart'; +import 'package:flutter/material.dart'; +import 'package:preload_page_view/preload_page_view.dart'; + +class PreloadPlayerPage extends StatefulWidget { + const PreloadPlayerPage({super.key}); + + @override + State createState() => _PreloadPlayerPageState(); +} + +class _PreloadPlayerPageState extends State { + int initialIndex = 0; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Preload Players"), + ), + body: PreloadPageView.builder( + itemCount: exampleVideos.length, + preloadPagesCount: exampleVideos.length, + scrollDirection: Axis.vertical, + itemBuilder: (BuildContext context, int index) { + final MediaItem mediaItem = exampleVideos[index]; + return _PortraitPlayer( + mediaItem: mediaItem, + isPrimary: initialIndex == index, + currentIndex: initialIndex, + ); + }, + controller: PreloadPageController(), + onPageChanged: (int position) { + setState(() => initialIndex = position); + print('page changed. current: $position'); + }, + ), + ); + } +} + +class _PortraitPlayer extends StatefulWidget { + final MediaItem mediaItem; + final bool isPrimary; + final int currentIndex; + const _PortraitPlayer({ + required this.mediaItem, + required this.isPrimary, + required this.currentIndex, + }); + + @override + State<_PortraitPlayer> createState() => __PortraitPlayerState(); +} + +class __PortraitPlayerState extends State<_PortraitPlayer> { + late BccmPlayerController playerController; + late BccmPlayerViewController viewController; + + FutureOr setupPlayer() async { + playerController = BccmPlayerController(widget.mediaItem); + viewController = BccmPlayerViewController( + playerController: playerController, + config: BccmPlayerViewConfig(useSurfaceView: false, videoFit: BoxFit.contain), + ); + + playerController.initialize().then((_) { + playerController.setMixWithOthers(true); + playerController.play(); + }); + } + + @override + void initState() { + setupPlayer(); + super.initState(); + } + + @override + void dispose() { + playerController.stop(reset: false); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + if (!widget.isPrimary) return Text('Is not primary = ${widget.isPrimary} - ${widget.currentIndex}'); + return Column( + children: [ + AspectRatio( + aspectRatio: 16 / 9, + child: BccmPlayerView(playerController, config: viewController.config), + ), + Text('${widget.currentIndex}'), + ], + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 095c1324..8de2b12d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,79 +1,11 @@ import 'dart:async'; import 'package:bccm_player/bccm_player.dart'; -import 'package:bccm_player_example/examples/queue.dart'; +import 'package:bccm_player_example/app.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'examples/list_of_players.dart'; -import 'examples/playground.dart'; -import 'examples/native_controls.dart'; -import 'examples/custom_controls.dart'; -import 'examples/simple_player.dart'; -import 'examples/downloader.dart'; - -Future main() async { +FutureOr main() async { await BccmPlayerInterface.instance.setup(); - // FocusDebugger.instance.activate(); - - runApp(const MyApp()); -} - -class MyApp extends StatefulWidget { - const MyApp({super.key}); - - @override - State createState() => _MyAppState(); -} - -class _MyAppState extends State { - @override - Widget build(BuildContext context) { - return MediaQuery( - data: MediaQuery.of(context).copyWith(navigationMode: NavigationMode.directional), - child: Shortcuts( - shortcuts: { - LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), - }, - child: DefaultTabController( - length: 7, - child: MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Plugin example app'), - actions: const [ - Padding( - padding: EdgeInsets.only(right: 16), - child: CastButton(color: Colors.white), - ), - ], - bottom: const TabBar(tabs: [ - Tab(text: 'Queue'), - Tab(text: 'Playground'), - Tab(text: 'List Of Players'), - Tab(text: 'Simple player'), - Tab(text: 'Custom controls'), - Tab(text: 'Native controls'), - Tab(text: 'Downloader') - ]), - ), - // tabs with Playground #1 then a new "ListOfPlayers" tab at #2 and controls to navigate between the tabs - body: const TabBarView( - children: [ - QueueExample(), - Playground(), - ListOfPlayers(), - SimplePlayer(), - CustomControls(), - NativeControls(), - Downloader(), - ], - ), - ), - ), - ), - ), - ); - } + runApp(const MaterialApp(home: MyApp())); } diff --git a/example/pubspec.lock b/example/pubspec.lock index e0b95339..67c363f3 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.13.0" + version: "2.12.0" bccm_player: dependency: "direct main" description: @@ -156,10 +156,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: @@ -307,10 +307,10 @@ packages: dependency: transitive description: name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -323,10 +323,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -455,6 +455,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + preload_page_view: + dependency: "direct main" + description: + name: preload_page_view + sha256: "488a10c158c5c2e9ba9d77e5dbc09b1e49e37a20df2301e5ba02992eac802b7a" + url: "https://pub.dev" + source: hosted + version: "0.2.0" provider: dependency: transitive description: @@ -487,6 +495,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.6.1" + screen_protector: + dependency: "direct main" + description: + name: screen_protector + sha256: "305fd157f6f0b210afe216e790022bfe469c3b1d1f2e0d3dcc5906cc9c49c3e9" + url: "https://pub.dev" + source: hosted + version: "1.4.2+1" sky_engine: dependency: transitive description: flutter @@ -624,10 +640,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" wakelock_plus: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 3a00f55f..5f5e4515 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -35,6 +35,8 @@ dependencies: hooks_riverpod: ^2.3.6 focus_debugger: ^0.0.1 connectivity_plus: ^6.0.0 + preload_page_view: ^0.2.0 + screen_protector: ^1.4.2+1 flutter_web_plugins: sdk: flutter diff --git a/ios/Classes/Pigeon/PlaybackPlatformApi.h b/ios/Classes/Pigeon/PlaybackPlatformApi.h index 728a5ec3..42d5a01c 100644 --- a/ios/Classes/Pigeon/PlaybackPlatformApi.h +++ b/ios/Classes/Pigeon/PlaybackPlatformApi.h @@ -32,6 +32,17 @@ typedef NS_ENUM(NSUInteger, RepeatMode) { - (instancetype)initWithValue:(RepeatMode)value; @end +typedef NS_ENUM(NSUInteger, DrmType) { + DrmTypeWidevine = 0, + DrmTypeFairplay = 1, +}; + +/// Wrapper for DrmType to allow for nullability. +@interface DrmTypeBox : NSObject +@property(nonatomic, assign) DrmType value; +- (instancetype)initWithValue:(DrmType)value; +@end + typedef NS_ENUM(NSUInteger, PlaybackState) { PlaybackStateStopped = 0, PlaybackStatePaused = 1, @@ -72,8 +83,8 @@ typedef NS_ENUM(NSUInteger, TrackType) { @class NpawConfig; @class AppConfig; -@class User; -@class SetUrlArgs; +@class DrmConfiguration; +@class CastMedia; @class MediaItem; @class MediaMetadata; @class PlayerStateSnapshot; @@ -117,20 +128,28 @@ typedef NS_ENUM(NSUInteger, TrackType) { @property(nonatomic, copy, nullable) NSString * sessionId; @end -@interface User : NSObject -+ (instancetype)makeWithId:(nullable NSString *)id; -@property(nonatomic, copy, nullable) NSString * id; +@interface DrmConfiguration : NSObject +/// `init` unavailable to enforce nonnull fields, see the `make` class method. +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)makeWithDrmType:(DrmType)drmType + contentKeyId:(nullable NSString *)contentKeyId + fpsCertificateUrl:(nullable NSString *)fpsCertificateUrl + licenseServerUrl:(NSString *)licenseServerUrl + licenseRequestHeaders:(nullable NSDictionary *)licenseRequestHeaders; +@property(nonatomic, assign) DrmType drmType; +@property(nonatomic, copy, nullable) NSString * contentKeyId; +@property(nonatomic, copy, nullable) NSString * fpsCertificateUrl; +@property(nonatomic, copy) NSString * licenseServerUrl; +@property(nonatomic, copy, nullable) NSDictionary * licenseRequestHeaders; @end -@interface SetUrlArgs : NSObject +@interface CastMedia : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithPlayerId:(NSString *)playerId - url:(NSString *)url - isLive:(nullable NSNumber *)isLive; -@property(nonatomic, copy) NSString * playerId; ++ (instancetype)makeWithUrl:(NSString *)url + customData:(nullable NSDictionary *)customData; @property(nonatomic, copy) NSString * url; -@property(nonatomic, strong, nullable) NSNumber * isLive; +@property(nonatomic, copy, nullable) NSDictionary * customData; @end @interface MediaItem : NSObject @@ -142,7 +161,9 @@ typedef NS_ENUM(NSUInteger, TrackType) { isOffline:(nullable NSNumber *)isOffline playbackStartPositionMs:(nullable NSNumber *)playbackStartPositionMs lastKnownAudioLanguage:(nullable NSString *)lastKnownAudioLanguage - lastKnownSubtitleLanguage:(nullable NSString *)lastKnownSubtitleLanguage; + lastKnownSubtitleLanguage:(nullable NSString *)lastKnownSubtitleLanguage + drmConfiguration:(nullable DrmConfiguration *)drmConfiguration + castMedia:(nullable CastMedia *)castMedia; @property(nonatomic, copy, nullable) NSString * id; @property(nonatomic, copy, nullable) NSString * url; @property(nonatomic, copy, nullable) NSString * mimeType; @@ -152,6 +173,8 @@ typedef NS_ENUM(NSUInteger, TrackType) { @property(nonatomic, strong, nullable) NSNumber * playbackStartPositionMs; @property(nonatomic, copy, nullable) NSString * lastKnownAudioLanguage; @property(nonatomic, copy, nullable) NSString * lastKnownSubtitleLanguage; +@property(nonatomic, strong, nullable) DrmConfiguration * drmConfiguration; +@property(nonatomic, strong, nullable) CastMedia * castMedia; @end @interface MediaMetadata : NSObject diff --git a/ios/Classes/Pigeon/PlaybackPlatformApi.m b/ios/Classes/Pigeon/PlaybackPlatformApi.m index 1352ff54..9dcbce10 100644 --- a/ios/Classes/Pigeon/PlaybackPlatformApi.m +++ b/ios/Classes/Pigeon/PlaybackPlatformApi.m @@ -51,6 +51,16 @@ - (instancetype)initWithValue:(RepeatMode)value { } @end +@implementation DrmTypeBox +- (instancetype)initWithValue:(DrmType)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + @implementation PlaybackStateBox - (instancetype)initWithValue:(PlaybackState)value { self = [super init]; @@ -93,15 +103,15 @@ + (nullable AppConfig *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end -@interface User () -+ (User *)fromList:(NSArray *)list; -+ (nullable User *)nullableFromList:(NSArray *)list; +@interface DrmConfiguration () ++ (DrmConfiguration *)fromList:(NSArray *)list; ++ (nullable DrmConfiguration *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end -@interface SetUrlArgs () -+ (SetUrlArgs *)fromList:(NSArray *)list; -+ (nullable SetUrlArgs *)nullableFromList:(NSArray *)list; +@interface CastMedia () ++ (CastMedia *)fromList:(NSArray *)list; ++ (nullable CastMedia *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end @@ -271,52 +281,65 @@ + (nullable AppConfig *)nullableFromList:(NSArray *)list { } @end -@implementation User -+ (instancetype)makeWithId:(nullable NSString *)id { - User* pigeonResult = [[User alloc] init]; - pigeonResult.id = id; +@implementation DrmConfiguration ++ (instancetype)makeWithDrmType:(DrmType)drmType + contentKeyId:(nullable NSString *)contentKeyId + fpsCertificateUrl:(nullable NSString *)fpsCertificateUrl + licenseServerUrl:(NSString *)licenseServerUrl + licenseRequestHeaders:(nullable NSDictionary *)licenseRequestHeaders { + DrmConfiguration* pigeonResult = [[DrmConfiguration alloc] init]; + pigeonResult.drmType = drmType; + pigeonResult.contentKeyId = contentKeyId; + pigeonResult.fpsCertificateUrl = fpsCertificateUrl; + pigeonResult.licenseServerUrl = licenseServerUrl; + pigeonResult.licenseRequestHeaders = licenseRequestHeaders; return pigeonResult; } -+ (User *)fromList:(NSArray *)list { - User *pigeonResult = [[User alloc] init]; - pigeonResult.id = GetNullableObjectAtIndex(list, 0); ++ (DrmConfiguration *)fromList:(NSArray *)list { + DrmConfiguration *pigeonResult = [[DrmConfiguration alloc] init]; + DrmTypeBox *boxedDrmType = GetNullableObjectAtIndex(list, 0); + pigeonResult.drmType = boxedDrmType.value; + pigeonResult.contentKeyId = GetNullableObjectAtIndex(list, 1); + pigeonResult.fpsCertificateUrl = GetNullableObjectAtIndex(list, 2); + pigeonResult.licenseServerUrl = GetNullableObjectAtIndex(list, 3); + pigeonResult.licenseRequestHeaders = GetNullableObjectAtIndex(list, 4); return pigeonResult; } -+ (nullable User *)nullableFromList:(NSArray *)list { - return (list) ? [User fromList:list] : nil; ++ (nullable DrmConfiguration *)nullableFromList:(NSArray *)list { + return (list) ? [DrmConfiguration fromList:list] : nil; } - (NSArray *)toList { return @[ - self.id ?: [NSNull null], + [[DrmTypeBox alloc] initWithValue:self.drmType], + self.contentKeyId ?: [NSNull null], + self.fpsCertificateUrl ?: [NSNull null], + self.licenseServerUrl ?: [NSNull null], + self.licenseRequestHeaders ?: [NSNull null], ]; } @end -@implementation SetUrlArgs -+ (instancetype)makeWithPlayerId:(NSString *)playerId - url:(NSString *)url - isLive:(nullable NSNumber *)isLive { - SetUrlArgs* pigeonResult = [[SetUrlArgs alloc] init]; - pigeonResult.playerId = playerId; +@implementation CastMedia ++ (instancetype)makeWithUrl:(NSString *)url + customData:(nullable NSDictionary *)customData { + CastMedia* pigeonResult = [[CastMedia alloc] init]; pigeonResult.url = url; - pigeonResult.isLive = isLive; + pigeonResult.customData = customData; return pigeonResult; } -+ (SetUrlArgs *)fromList:(NSArray *)list { - SetUrlArgs *pigeonResult = [[SetUrlArgs alloc] init]; - pigeonResult.playerId = GetNullableObjectAtIndex(list, 0); - pigeonResult.url = GetNullableObjectAtIndex(list, 1); - pigeonResult.isLive = GetNullableObjectAtIndex(list, 2); ++ (CastMedia *)fromList:(NSArray *)list { + CastMedia *pigeonResult = [[CastMedia alloc] init]; + pigeonResult.url = GetNullableObjectAtIndex(list, 0); + pigeonResult.customData = GetNullableObjectAtIndex(list, 1); return pigeonResult; } -+ (nullable SetUrlArgs *)nullableFromList:(NSArray *)list { - return (list) ? [SetUrlArgs fromList:list] : nil; ++ (nullable CastMedia *)nullableFromList:(NSArray *)list { + return (list) ? [CastMedia fromList:list] : nil; } - (NSArray *)toList { return @[ - self.playerId ?: [NSNull null], self.url ?: [NSNull null], - self.isLive ?: [NSNull null], + self.customData ?: [NSNull null], ]; } @end @@ -330,7 +353,9 @@ + (instancetype)makeWithId:(nullable NSString *)id isOffline:(nullable NSNumber *)isOffline playbackStartPositionMs:(nullable NSNumber *)playbackStartPositionMs lastKnownAudioLanguage:(nullable NSString *)lastKnownAudioLanguage - lastKnownSubtitleLanguage:(nullable NSString *)lastKnownSubtitleLanguage { + lastKnownSubtitleLanguage:(nullable NSString *)lastKnownSubtitleLanguage + drmConfiguration:(nullable DrmConfiguration *)drmConfiguration + castMedia:(nullable CastMedia *)castMedia { MediaItem* pigeonResult = [[MediaItem alloc] init]; pigeonResult.id = id; pigeonResult.url = url; @@ -341,6 +366,8 @@ + (instancetype)makeWithId:(nullable NSString *)id pigeonResult.playbackStartPositionMs = playbackStartPositionMs; pigeonResult.lastKnownAudioLanguage = lastKnownAudioLanguage; pigeonResult.lastKnownSubtitleLanguage = lastKnownSubtitleLanguage; + pigeonResult.drmConfiguration = drmConfiguration; + pigeonResult.castMedia = castMedia; return pigeonResult; } + (MediaItem *)fromList:(NSArray *)list { @@ -354,6 +381,8 @@ + (MediaItem *)fromList:(NSArray *)list { pigeonResult.playbackStartPositionMs = GetNullableObjectAtIndex(list, 6); pigeonResult.lastKnownAudioLanguage = GetNullableObjectAtIndex(list, 7); pigeonResult.lastKnownSubtitleLanguage = GetNullableObjectAtIndex(list, 8); + pigeonResult.drmConfiguration = GetNullableObjectAtIndex(list, 9); + pigeonResult.castMedia = GetNullableObjectAtIndex(list, 10); return pigeonResult; } + (nullable MediaItem *)nullableFromList:(NSArray *)list { @@ -370,6 +399,8 @@ + (nullable MediaItem *)nullableFromList:(NSArray *)list { self.playbackStartPositionMs ?: [NSNull null], self.lastKnownAudioLanguage ?: [NSNull null], self.lastKnownSubtitleLanguage ?: [NSNull null], + self.drmConfiguration ?: [NSNull null], + self.castMedia ?: [NSNull null], ]; } @end @@ -855,55 +886,59 @@ - (nullable id)readValueOfType:(UInt8)type { } case 131: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil : [[PlaybackStateBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[DrmTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 132: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil : [[CastConnectionStateBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[PlaybackStateBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 133: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil : [[CastConnectionStateBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 134: { NSNumber *enumAsNumber = [self readValue]; return enumAsNumber == nil ? nil : [[TrackTypeBox alloc] initWithValue:[enumAsNumber integerValue]]; } - case 134: - return [NpawConfig fromList:[self readValue]]; case 135: - return [AppConfig fromList:[self readValue]]; + return [NpawConfig fromList:[self readValue]]; case 136: - return [User fromList:[self readValue]]; + return [AppConfig fromList:[self readValue]]; case 137: - return [SetUrlArgs fromList:[self readValue]]; + return [DrmConfiguration fromList:[self readValue]]; case 138: - return [MediaItem fromList:[self readValue]]; + return [CastMedia fromList:[self readValue]]; case 139: - return [MediaMetadata fromList:[self readValue]]; + return [MediaItem fromList:[self readValue]]; case 140: - return [PlayerStateSnapshot fromList:[self readValue]]; + return [MediaMetadata fromList:[self readValue]]; case 141: - return [PlayerError fromList:[self readValue]]; + return [PlayerStateSnapshot fromList:[self readValue]]; case 142: - return [VideoSize fromList:[self readValue]]; + return [PlayerError fromList:[self readValue]]; case 143: - return [ChromecastState fromList:[self readValue]]; + return [VideoSize fromList:[self readValue]]; case 144: - return [MediaInfo fromList:[self readValue]]; + return [ChromecastState fromList:[self readValue]]; case 145: - return [PlayerTracksSnapshot fromList:[self readValue]]; + return [MediaInfo fromList:[self readValue]]; case 146: - return [Track fromList:[self readValue]]; + return [PlayerTracksSnapshot fromList:[self readValue]]; case 147: - return [PrimaryPlayerChangedEvent fromList:[self readValue]]; + return [Track fromList:[self readValue]]; case 148: - return [PlayerStateUpdateEvent fromList:[self readValue]]; + return [PrimaryPlayerChangedEvent fromList:[self readValue]]; case 149: - return [PositionDiscontinuityEvent fromList:[self readValue]]; + return [PlayerStateUpdateEvent fromList:[self readValue]]; case 150: - return [PlaybackStateChangedEvent fromList:[self readValue]]; + return [PositionDiscontinuityEvent fromList:[self readValue]]; case 151: - return [PlaybackEndedEvent fromList:[self readValue]]; + return [PlaybackStateChangedEvent fromList:[self readValue]]; case 152: - return [PictureInPictureModeChangedEvent fromList:[self readValue]]; + return [PlaybackEndedEvent fromList:[self readValue]]; case 153: + return [PictureInPictureModeChangedEvent fromList:[self readValue]]; + case 154: return [MediaItemTransitionEvent fromList:[self readValue]]; default: return [super readValueOfType:type]; @@ -923,78 +958,82 @@ - (void)writeValue:(id)value { RepeatModeBox *box = (RepeatModeBox *)value; [self writeByte:130]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[DrmTypeBox class]]) { + DrmTypeBox *box = (DrmTypeBox *)value; + [self writeByte:131]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; } else if ([value isKindOfClass:[PlaybackStateBox class]]) { PlaybackStateBox *box = (PlaybackStateBox *)value; - [self writeByte:131]; + [self writeByte:132]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; } else if ([value isKindOfClass:[CastConnectionStateBox class]]) { CastConnectionStateBox *box = (CastConnectionStateBox *)value; - [self writeByte:132]; + [self writeByte:133]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; } else if ([value isKindOfClass:[TrackTypeBox class]]) { TrackTypeBox *box = (TrackTypeBox *)value; - [self writeByte:133]; + [self writeByte:134]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; } else if ([value isKindOfClass:[NpawConfig class]]) { - [self writeByte:134]; - [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[AppConfig class]]) { [self writeByte:135]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[User class]]) { + } else if ([value isKindOfClass:[AppConfig class]]) { [self writeByte:136]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[SetUrlArgs class]]) { + } else if ([value isKindOfClass:[DrmConfiguration class]]) { [self writeByte:137]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[MediaItem class]]) { + } else if ([value isKindOfClass:[CastMedia class]]) { [self writeByte:138]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[MediaMetadata class]]) { + } else if ([value isKindOfClass:[MediaItem class]]) { [self writeByte:139]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlayerStateSnapshot class]]) { + } else if ([value isKindOfClass:[MediaMetadata class]]) { [self writeByte:140]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlayerError class]]) { + } else if ([value isKindOfClass:[PlayerStateSnapshot class]]) { [self writeByte:141]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[VideoSize class]]) { + } else if ([value isKindOfClass:[PlayerError class]]) { [self writeByte:142]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[ChromecastState class]]) { + } else if ([value isKindOfClass:[VideoSize class]]) { [self writeByte:143]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[MediaInfo class]]) { + } else if ([value isKindOfClass:[ChromecastState class]]) { [self writeByte:144]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlayerTracksSnapshot class]]) { + } else if ([value isKindOfClass:[MediaInfo class]]) { [self writeByte:145]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[Track class]]) { + } else if ([value isKindOfClass:[PlayerTracksSnapshot class]]) { [self writeByte:146]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PrimaryPlayerChangedEvent class]]) { + } else if ([value isKindOfClass:[Track class]]) { [self writeByte:147]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlayerStateUpdateEvent class]]) { + } else if ([value isKindOfClass:[PrimaryPlayerChangedEvent class]]) { [self writeByte:148]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PositionDiscontinuityEvent class]]) { + } else if ([value isKindOfClass:[PlayerStateUpdateEvent class]]) { [self writeByte:149]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlaybackStateChangedEvent class]]) { + } else if ([value isKindOfClass:[PositionDiscontinuityEvent class]]) { [self writeByte:150]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PlaybackEndedEvent class]]) { + } else if ([value isKindOfClass:[PlaybackStateChangedEvent class]]) { [self writeByte:151]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[PictureInPictureModeChangedEvent class]]) { + } else if ([value isKindOfClass:[PlaybackEndedEvent class]]) { [self writeByte:152]; [self writeValue:[value toList]]; - } else if ([value isKindOfClass:[MediaItemTransitionEvent class]]) { + } else if ([value isKindOfClass:[PictureInPictureModeChangedEvent class]]) { [self writeByte:153]; [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[MediaItemTransitionEvent class]]) { + [self writeByte:154]; + [self writeValue:[value toList]]; } else { [super writeValue:value]; } diff --git a/lib/bccm_player.dart b/lib/bccm_player.dart index 45f2f6d9..f85686cf 100644 --- a/lib/bccm_player.dart +++ b/lib/bccm_player.dart @@ -20,7 +20,10 @@ export 'src/pigeon/playback_platform_pigeon.g.dart' RepeatMode, PlayerError, BufferMode, - PictureInPictureModeChangedEvent; + PictureInPictureModeChangedEvent, + DrmType, + DrmConfiguration, + CastMedia; export 'src/state/player_state_notifier.dart'; export 'src/state/plugin_state_notifier.dart'; export 'src/state/player_controller.dart'; diff --git a/lib/src/pigeon/playback_platform_pigeon.g.dart b/lib/src/pigeon/playback_platform_pigeon.g.dart index 1f0fc477..87d33913 100644 --- a/lib/src/pigeon/playback_platform_pigeon.g.dart +++ b/lib/src/pigeon/playback_platform_pigeon.g.dart @@ -35,6 +35,11 @@ enum RepeatMode { one, } +enum DrmType { + widevine, + fairplay, +} + enum PlaybackState { stopped, paused, @@ -132,54 +137,69 @@ class AppConfig { } } -class User { - User({ - this.id, +class DrmConfiguration { + DrmConfiguration({ + required this.drmType, + this.contentKeyId, + this.fpsCertificateUrl, + required this.licenseServerUrl, + this.licenseRequestHeaders, }); - String? id; + DrmType drmType; + + String? contentKeyId; + + String? fpsCertificateUrl; + + String licenseServerUrl; + + Map? licenseRequestHeaders; Object encode() { return [ - id, + drmType, + contentKeyId, + fpsCertificateUrl, + licenseServerUrl, + licenseRequestHeaders, ]; } - static User decode(Object result) { + static DrmConfiguration decode(Object result) { result as List; - return User( - id: result[0] as String?, + return DrmConfiguration( + drmType: result[0]! as DrmType, + contentKeyId: result[1] as String?, + fpsCertificateUrl: result[2] as String?, + licenseServerUrl: result[3]! as String, + licenseRequestHeaders: (result[4] as Map?)?.cast(), ); } } -class SetUrlArgs { - SetUrlArgs({ - required this.playerId, +class CastMedia { + CastMedia({ required this.url, - this.isLive, + this.customData, }); - String playerId; - String url; - bool? isLive; + Map? customData; Object encode() { return [ - playerId, url, - isLive, + customData, ]; } - static SetUrlArgs decode(Object result) { + static CastMedia decode(Object result) { result as List; - return SetUrlArgs( - playerId: result[0]! as String, - url: result[1]! as String, - isLive: result[2] as bool?, + return CastMedia( + url: result[0]! as String, + customData: (result[1] as Map?)?.cast(), ); } } @@ -195,6 +215,8 @@ class MediaItem { this.playbackStartPositionMs, this.lastKnownAudioLanguage, this.lastKnownSubtitleLanguage, + this.drmConfiguration, + this.castMedia, }); String? id; @@ -215,6 +237,10 @@ class MediaItem { String? lastKnownSubtitleLanguage; + DrmConfiguration? drmConfiguration; + + CastMedia? castMedia; + Object encode() { return [ id, @@ -226,6 +252,8 @@ class MediaItem { playbackStartPositionMs, lastKnownAudioLanguage, lastKnownSubtitleLanguage, + drmConfiguration, + castMedia, ]; } @@ -241,6 +269,8 @@ class MediaItem { playbackStartPositionMs: result[6] as double?, lastKnownAudioLanguage: result[7] as String?, lastKnownSubtitleLanguage: result[8] as String?, + drmConfiguration: result[9] as DrmConfiguration?, + castMedia: result[10] as CastMedia?, ); } } @@ -750,84 +780,84 @@ class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is int) { - buffer.putUint8(4); - buffer.putInt64(value); - } else if (value is BufferMode) { + if (value is BufferMode) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is RepeatMode) { + } else if (value is RepeatMode) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is PlaybackState) { + } else if (value is DrmType) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is CastConnectionState) { + } else if (value is PlaybackState) { buffer.putUint8(132); writeValue(buffer, value.index); - } else if (value is TrackType) { + } else if (value is CastConnectionState) { buffer.putUint8(133); writeValue(buffer, value.index); - } else if (value is NpawConfig) { + } else if (value is TrackType) { buffer.putUint8(134); - writeValue(buffer, value.encode()); - } else if (value is AppConfig) { + writeValue(buffer, value.index); + } else if (value is NpawConfig) { buffer.putUint8(135); writeValue(buffer, value.encode()); - } else if (value is User) { + } else if (value is AppConfig) { buffer.putUint8(136); writeValue(buffer, value.encode()); - } else if (value is SetUrlArgs) { + } else if (value is DrmConfiguration) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is MediaItem) { + } else if (value is CastMedia) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is MediaMetadata) { + } else if (value is MediaItem) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is PlayerStateSnapshot) { + } else if (value is MediaMetadata) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PlayerError) { + } else if (value is PlayerStateSnapshot) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is VideoSize) { + } else if (value is PlayerError) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is ChromecastState) { + } else if (value is VideoSize) { buffer.putUint8(143); writeValue(buffer, value.encode()); - } else if (value is MediaInfo) { + } else if (value is ChromecastState) { buffer.putUint8(144); writeValue(buffer, value.encode()); - } else if (value is PlayerTracksSnapshot) { + } else if (value is MediaInfo) { buffer.putUint8(145); writeValue(buffer, value.encode()); - } else if (value is Track) { + } else if (value is PlayerTracksSnapshot) { buffer.putUint8(146); writeValue(buffer, value.encode()); - } else if (value is PrimaryPlayerChangedEvent) { + } else if (value is Track) { buffer.putUint8(147); writeValue(buffer, value.encode()); - } else if (value is PlayerStateUpdateEvent) { + } else if (value is PrimaryPlayerChangedEvent) { buffer.putUint8(148); writeValue(buffer, value.encode()); - } else if (value is PositionDiscontinuityEvent) { + } else if (value is PlayerStateUpdateEvent) { buffer.putUint8(149); writeValue(buffer, value.encode()); - } else if (value is PlaybackStateChangedEvent) { + } else if (value is PositionDiscontinuityEvent) { buffer.putUint8(150); writeValue(buffer, value.encode()); - } else if (value is PlaybackEndedEvent) { + } else if (value is PlaybackStateChangedEvent) { buffer.putUint8(151); writeValue(buffer, value.encode()); - } else if (value is PictureInPictureModeChangedEvent) { + } else if (value is PlaybackEndedEvent) { buffer.putUint8(152); writeValue(buffer, value.encode()); - } else if (value is MediaItemTransitionEvent) { + } else if (value is PictureInPictureModeChangedEvent) { buffer.putUint8(153); writeValue(buffer, value.encode()); + } else if (value is MediaItemTransitionEvent) { + buffer.putUint8(154); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -844,52 +874,55 @@ class _PigeonCodec extends StandardMessageCodec { return value == null ? null : RepeatMode.values[value]; case 131: final int? value = readValue(buffer) as int?; - return value == null ? null : PlaybackState.values[value]; + return value == null ? null : DrmType.values[value]; case 132: final int? value = readValue(buffer) as int?; - return value == null ? null : CastConnectionState.values[value]; + return value == null ? null : PlaybackState.values[value]; case 133: final int? value = readValue(buffer) as int?; - return value == null ? null : TrackType.values[value]; + return value == null ? null : CastConnectionState.values[value]; case 134: - return NpawConfig.decode(readValue(buffer)!); + final int? value = readValue(buffer) as int?; + return value == null ? null : TrackType.values[value]; case 135: - return AppConfig.decode(readValue(buffer)!); + return NpawConfig.decode(readValue(buffer)!); case 136: - return User.decode(readValue(buffer)!); + return AppConfig.decode(readValue(buffer)!); case 137: - return SetUrlArgs.decode(readValue(buffer)!); + return DrmConfiguration.decode(readValue(buffer)!); case 138: - return MediaItem.decode(readValue(buffer)!); + return CastMedia.decode(readValue(buffer)!); case 139: - return MediaMetadata.decode(readValue(buffer)!); + return MediaItem.decode(readValue(buffer)!); case 140: - return PlayerStateSnapshot.decode(readValue(buffer)!); + return MediaMetadata.decode(readValue(buffer)!); case 141: - return PlayerError.decode(readValue(buffer)!); + return PlayerStateSnapshot.decode(readValue(buffer)!); case 142: - return VideoSize.decode(readValue(buffer)!); + return PlayerError.decode(readValue(buffer)!); case 143: - return ChromecastState.decode(readValue(buffer)!); + return VideoSize.decode(readValue(buffer)!); case 144: - return MediaInfo.decode(readValue(buffer)!); + return ChromecastState.decode(readValue(buffer)!); case 145: - return PlayerTracksSnapshot.decode(readValue(buffer)!); + return MediaInfo.decode(readValue(buffer)!); case 146: - return Track.decode(readValue(buffer)!); + return PlayerTracksSnapshot.decode(readValue(buffer)!); case 147: - return PrimaryPlayerChangedEvent.decode(readValue(buffer)!); + return Track.decode(readValue(buffer)!); case 148: - return PlayerStateUpdateEvent.decode(readValue(buffer)!); + return PrimaryPlayerChangedEvent.decode(readValue(buffer)!); case 149: - return PositionDiscontinuityEvent.decode(readValue(buffer)!); + return PlayerStateUpdateEvent.decode(readValue(buffer)!); case 150: - return PlaybackStateChangedEvent.decode(readValue(buffer)!); + return PositionDiscontinuityEvent.decode(readValue(buffer)!); case 151: - return PlaybackEndedEvent.decode(readValue(buffer)!); + return PlaybackStateChangedEvent.decode(readValue(buffer)!); case 152: - return PictureInPictureModeChangedEvent.decode(readValue(buffer)!); + return PlaybackEndedEvent.decode(readValue(buffer)!); case 153: + return PictureInPictureModeChangedEvent.decode(readValue(buffer)!); + case 154: return MediaItemTransitionEvent.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); diff --git a/lib/src/playback_platform_interface.dart b/lib/src/playback_platform_interface.dart index c689df30..6aa36f79 100644 --- a/lib/src/playback_platform_interface.dart +++ b/lib/src/playback_platform_interface.dart @@ -41,7 +41,15 @@ abstract class BccmPlayerInterface extends PlatformInterface { } Future replaceCurrentMediaItem(String playerId, MediaItem mediaItem, {bool? playbackPositionFromPrimary, bool? autoplay = true}) { - throw UnimplementedError('setUrl() has not been implemented.'); + throw UnimplementedError('replaceCurrentMediaItem() has not been implemented.'); + } + + Future replaceCurrentOfflineAsset(String playerId, String downloadKey, {bool? playbackPositionFromPrimary, bool? autoplay = true}) { + throw UnimplementedError('replaceCurrentOfflineAsset() has not been implemented.'); + } + + Future queueMediaItem(String playerId, MediaItem mediaItem) async { + throw UnimplementedError('addMediaItem() has not been implemented.'); } Future getChromecastState() async { diff --git a/lib/src/state/player_state_notifier.freezed.dart b/lib/src/state/player_state_notifier.freezed.dart index e42ef4f4..74455b5e 100644 --- a/lib/src/state/player_state_notifier.freezed.dart +++ b/lib/src/state/player_state_notifier.freezed.dart @@ -30,9 +30,7 @@ mixin _$PlayerState { double? get volume => throw _privateConstructorUsedError; PlayerError? get error => throw _privateConstructorUsedError; - /// Create a copy of PlayerState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) $PlayerStateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -69,8 +67,6 @@ class _$PlayerStateCopyWithImpl<$Res, $Val extends PlayerState> // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of PlayerState - /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -177,8 +173,6 @@ class __$$PlayerStateImplCopyWithImpl<$Res> _$PlayerStateImpl _value, $Res Function(_$PlayerStateImpl) _then) : super(_value, _then); - /// Create a copy of PlayerState - /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -378,9 +372,7 @@ class _$PlayerStateImpl extends _PlayerState with DiagnosticableTreeMixin { volume, error); - /// Create a copy of PlayerState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') _$$PlayerStateImplCopyWith<_$PlayerStateImpl> get copyWith => @@ -430,11 +422,8 @@ abstract class _PlayerState extends PlayerState { double? get volume; @override PlayerError? get error; - - /// Create a copy of PlayerState - /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) _$$PlayerStateImplCopyWith<_$PlayerStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/src/state/plugin_state_notifier.freezed.dart b/lib/src/state/plugin_state_notifier.freezed.dart index edbae9b8..ed149fad 100644 --- a/lib/src/state/plugin_state_notifier.freezed.dart +++ b/lib/src/state/plugin_state_notifier.freezed.dart @@ -20,9 +20,7 @@ mixin _$PlayerPluginState { Map get players => throw _privateConstructorUsedError; - /// Create a copy of PlayerPluginState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) $PlayerPluginStateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -47,8 +45,6 @@ class _$PlayerPluginStateCopyWithImpl<$Res, $Val extends PlayerPluginState> // ignore: unused_field final $Res Function($Val) _then; - /// Create a copy of PlayerPluginState - /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -88,8 +84,6 @@ class __$$PlayerPluginStateImplCopyWithImpl<$Res> $Res Function(_$PlayerPluginStateImpl) _then) : super(_value, _then); - /// Create a copy of PlayerPluginState - /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -146,9 +140,7 @@ class _$PlayerPluginStateImpl implements _PlayerPluginState { int get hashCode => Object.hash(runtimeType, primaryPlayerId, const DeepCollectionEquality().hash(_players)); - /// Create a copy of PlayerPluginState - /// with the given fields replaced by the non-null parameter values. - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) @override @pragma('vm:prefer-inline') _$$PlayerPluginStateImplCopyWith<_$PlayerPluginStateImpl> get copyWith => @@ -166,11 +158,8 @@ abstract class _PlayerPluginState implements PlayerPluginState { String? get primaryPlayerId; @override Map get players; - - /// Create a copy of PlayerPluginState - /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(includeFromJson: false, includeToJson: false) + @JsonKey(ignore: true) _$$PlayerPluginStateImplCopyWith<_$PlayerPluginStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/pigeons/playback_platform_pigeon.dart b/pigeons/playback_platform_pigeon.dart index b1fc07fb..756ca18c 100644 --- a/pigeons/playback_platform_pigeon.dart +++ b/pigeons/playback_platform_pigeon.dart @@ -138,6 +138,11 @@ enum RepeatMode { one, } +enum DrmType { + widevine, + fairplay, +} + class NpawConfig { late String? appName; late String? appReleaseVersion; @@ -163,6 +168,19 @@ class SetUrlArgs { bool? isLive; } +class DrmConfiguration { + late DrmType drmType; + String? contentKeyId; + String? fpsCertificateUrl; + late String licenseServerUrl; + Map? licenseRequestHeaders; +} + +class CastMedia { + late String url; + Map? customData; +} + class MediaItem { String? id; String? url; @@ -173,6 +191,8 @@ class MediaItem { double? playbackStartPositionMs; String? lastKnownAudioLanguage; String? lastKnownSubtitleLanguage; + DrmConfiguration? drmConfiguration; + CastMedia? castMedia; } class MediaMetadata { diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 00000000..5d7c5f9a --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,807 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + url: "https://pub.dev" + source: hosted + version: "76.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.3" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + url: "https://pub.dev" + source: hosted + version: "6.11.0" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + url: "https://pub.dev" + source: hosted + version: "2.12.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + url: "https://pub.dev" + source: hosted + version: "4.0.4" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + url: "https://pub.dev" + source: hosted + version: "9.1.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27" + url: "https://pub.dev" + source: hosted + version: "8.10.1" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" + url: "https://pub.dev" + source: hosted + version: "4.10.1" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820" + url: "https://pub.dev" + source: hosted + version: "2.3.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + url: "https://pub.dev" + source: hosted + version: "1.3.2" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_hooks: + dependency: "direct main" + description: + name: flutter_hooks + sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70 + url: "https://pub.dev" + source: hosted + version: "0.20.5" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_plugin_android_lifecycle: + dependency: "direct main" + description: + name: flutter_plugin_android_lifecycle + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e + url: "https://pub.dev" + source: hosted + version: "2.0.28" + flutter_state_notifier: + dependency: "direct main" + description: + name: flutter_state_notifier + sha256: bd8d4eabd4b74f11733409305369c112fa2f7989290f73ee75ae2cbfcf04b8a3 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + flutter_svg: + dependency: "direct main" + description: + name: flutter_svg + sha256: cd57f7969b4679317c17af6fd16ee233c1e60a82ed209d8a475c54fd6fd6f845 + url: "https://pub.dev" + source: hosted + version: "2.2.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct main" + description: + name: freezed + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" + url: "https://pub.dev" + source: hosted + version: "2.5.7" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + http: + dependency: transitive + description: + name: http + sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b" + url: "https://pub.dev" + source: hosted + version: "1.4.0" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + js: + dependency: "direct main" + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + url: "https://pub.dev" + source: hosted + version: "10.0.8" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" + url: "https://pub.dev" + source: hosted + version: "0.1.3-main.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: "direct main" + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + mockito: + dependency: "direct dev" + description: + name: mockito + sha256: f99d8d072e249f719a5531735d146d8cf04c580d93920b04de75bef6dfb2daf6 + url: "https://pub.dev" + source: hosted + version: "5.4.5" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: "7976bfe4c583170d6cdc7077e3237560b364149fcd268b5f53d95a991963b191" + url: "https://pub.dev" + source: hosted + version: "8.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "6c935fb612dff8e3cc9632c2b301720c77450a126114126ffaafe28d2e87956c" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + pigeon: + dependency: "direct dev" + description: + name: pigeon + sha256: f938cbea2249d68843f96953da7c787a99960578066492ac5962da1da8cabf67 + url: "https://pub.dev" + source: hosted + version: "21.2.0" + plugin_platform_interface: + dependency: "direct main" + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + riverpod: + dependency: "direct main" + description: + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + state_notifier: + dependency: "direct main" + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + universal_io: + dependency: "direct main" + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + uuid: + dependency: "direct main" + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + url: "https://pub.dev" + source: hosted + version: "1.1.19" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" + url: "https://pub.dev" + source: hosted + version: "1.1.13" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "557a315b7d2a6dbb0aaaff84d857967ce6bdc96a63dc6ee2a57ce5a6ee5d3331" + url: "https://pub.dev" + source: hosted + version: "1.1.17" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + url: "https://pub.dev" + source: hosted + version: "14.3.1" + wakelock_plus: + dependency: "direct main" + description: + name: wakelock_plus + sha256: a474e314c3e8fb5adef1f9ae2d247e57467ad557fa7483a2b895bc1b421c5678 + url: "https://pub.dev" + source: hosted + version: "1.3.2" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: e10444072e50dbc4999d7316fd303f7ea53d31c824aa5eb05d7ccbdd98985207 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + watcher: + dependency: transitive + description: + name: watcher + sha256: "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + win32: + dependency: transitive + description: + name: win32 + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + url: "https://pub.dev" + source: hosted + version: "5.13.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/pubspec.yaml b/pubspec.yaml index ae8fc0b1..0fc245d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,20 +20,21 @@ dependencies: sdk: flutter freezed: ^2.3.2 freezed_annotation: ^2.2.0 - js: ^0.7.1 + js: ^0.6.3 meta: ^1.9.1 plugin_platform_interface: ^2.0.2 riverpod: ^2.2.0 state_notifier: ^1.0.0 universal_io: ^2.0.4 uuid: ^4.5.0 - wakelock_plus: ^1.1.1 + wakelock_plus: ^1.2.10 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^4.0.0 - pigeon: ^22.3.0 + # pigeon: ^22.2.0 + pigeon: ^21.2.0 build_runner: ^2.3.3 mockito: ^5.4.2 diff --git a/test/utils/mocks.mocks.dart b/test/utils/mocks.mocks.dart index 14097523..8e044552 100644 --- a/test/utils/mocks.mocks.dart +++ b/test/utils/mocks.mocks.dart @@ -251,6 +251,46 @@ class MockBccmPlayerInterface extends _i1.Mock returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); + @override + _i3.Future replaceCurrentOfflineAsset( + String? playerId, + String? downloadKey, { + bool? playbackPositionFromPrimary, + bool? autoplay = true, + }) => + (super.noSuchMethod( + Invocation.method( + #replaceCurrentOfflineAsset, + [ + playerId, + downloadKey, + ], + { + #playbackPositionFromPrimary: playbackPositionFromPrimary, + #autoplay: autoplay, + }, + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future queueMediaItem( + String? playerId, + _i2.MediaItem? mediaItem, + ) => + (super.noSuchMethod( + Invocation.method( + #queueMediaItem, + [ + playerId, + mediaItem, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future<_i7.ChromecastState?> getChromecastState() => (super.noSuchMethod( Invocation.method(