From 4c34bfb4b9314e67fad5fd765ac97eeee652b67e Mon Sep 17 00:00:00 2001 From: gianlucaparadise Date: Thu, 9 Dec 2021 18:14:58 +0100 Subject: [PATCH] SessionManager castDevice pigeon, android, ios --- .../PlatformBridgeApis.java | 82 ++++++++++++++++--- .../FlutterCastFrameworkPlugin.kt | 14 +++- ios/Classes/PlatformBridgeApis.h | 8 ++ ios/Classes/PlatformBridgeApis.m | 73 ++++++++++++++--- .../SwiftFlutterCastFrameworkPlugin.swift | 16 ++++ lib/src/PlatformBridgeApis.dart | 74 ++++++++++++++--- lib/src/cast/SessionManager.dart | 5 ++ pigeon/PlatformBridgeApisDefinition.dart | 7 ++ 8 files changed, 245 insertions(+), 34 deletions(-) diff --git a/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java b/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java index ee03f8a..1e6299f 100644 --- a/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java +++ b/android/src/main/java/com/gianlucaparadise/flutter_cast_framework/PlatformBridgeApis.java @@ -266,6 +266,39 @@ public class PlatformBridgeApis { } } + /** Generated class from Pigeon that represents data sent in messages. */ + public static class CastDevice { + private String deviceId; + public String getDeviceId() { return deviceId; } + public void setDeviceId(String setterArg) { this.deviceId = setterArg; } + + private String friendlyName; + public String getFriendlyName() { return friendlyName; } + public void setFriendlyName(String setterArg) { this.friendlyName = setterArg; } + + private String modelName; + public String getModelName() { return modelName; } + public void setModelName(String setterArg) { this.modelName = setterArg; } + + Map toMap() { + Map toMapResult = new HashMap<>(); + toMapResult.put("deviceId", deviceId); + toMapResult.put("friendlyName", friendlyName); + toMapResult.put("modelName", modelName); + return toMapResult; + } + static CastDevice fromMap(Map map) { + CastDevice fromMapResult = new CastDevice(); + Object deviceId = map.get("deviceId"); + fromMapResult.deviceId = (String)deviceId; + Object friendlyName = map.get("friendlyName"); + fromMapResult.friendlyName = (String)friendlyName; + Object modelName = map.get("modelName"); + fromMapResult.modelName = (String)modelName; + return fromMapResult; + } + } + /** Generated class from Pigeon that represents data sent in messages. */ public static class CastMessage { private String namespace; @@ -298,21 +331,24 @@ public class PlatformBridgeApis { protected Object readValueOfType(byte type, ByteBuffer buffer) { switch (type) { case (byte)128: - return CastMessage.fromMap((Map) readValue(buffer)); + return CastDevice.fromMap((Map) readValue(buffer)); case (byte)129: - return MediaInfo.fromMap((Map) readValue(buffer)); + return CastMessage.fromMap((Map) readValue(buffer)); case (byte)130: - return MediaLoadRequestData.fromMap((Map) readValue(buffer)); + return MediaInfo.fromMap((Map) readValue(buffer)); case (byte)131: - return MediaMetadata.fromMap((Map) readValue(buffer)); + return MediaLoadRequestData.fromMap((Map) readValue(buffer)); case (byte)132: - return MediaTrack.fromMap((Map) readValue(buffer)); + return MediaMetadata.fromMap((Map) readValue(buffer)); case (byte)133: + return MediaTrack.fromMap((Map) readValue(buffer)); + + case (byte)134: return WebImage.fromMap((Map) readValue(buffer)); default: @@ -322,28 +358,32 @@ public class PlatformBridgeApis { } @Override protected void writeValue(ByteArrayOutputStream stream, Object value) { - if (value instanceof CastMessage) { + if (value instanceof CastDevice) { stream.write(128); + writeValue(stream, ((CastDevice) value).toMap()); + } else + if (value instanceof CastMessage) { + stream.write(129); writeValue(stream, ((CastMessage) value).toMap()); } else if (value instanceof MediaInfo) { - stream.write(129); + stream.write(130); writeValue(stream, ((MediaInfo) value).toMap()); } else if (value instanceof MediaLoadRequestData) { - stream.write(130); + stream.write(131); writeValue(stream, ((MediaLoadRequestData) value).toMap()); } else if (value instanceof MediaMetadata) { - stream.write(131); + stream.write(132); writeValue(stream, ((MediaMetadata) value).toMap()); } else if (value instanceof MediaTrack) { - stream.write(132); + stream.write(133); writeValue(stream, ((MediaTrack) value).toMap()); } else if (value instanceof WebImage) { - stream.write(133); + stream.write(134); writeValue(stream, ((WebImage) value).toMap()); } else { @@ -357,6 +397,7 @@ public class PlatformBridgeApis { void sendMessage(CastMessage message); void showCastDialog(); void setMute(Boolean muted); + CastDevice getCastDevice(); void loadMediaLoadRequestData(MediaLoadRequestData request); MediaInfo getMediaInfo(); void play(); @@ -437,6 +478,25 @@ public class PlatformBridgeApis { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.CastHostApi.getCastDevice", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + Map wrapped = new HashMap<>(); + try { + CastDevice output = api.getCastDevice(); + wrapped.put("result", output); + } + catch (Error | RuntimeException exception) { + wrapped.put("error", wrapError(exception)); + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.CastHostApi.loadMediaLoadRequestData", getCodec()); diff --git a/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt b/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt index aa959ac..ce85895 100644 --- a/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt +++ b/android/src/main/kotlin/com/gianlucaparadise/flutter_cast_framework/FlutterCastFrameworkPlugin.kt @@ -250,7 +250,7 @@ class FlutterCastFrameworkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwa override fun getMediaInfo(): PlatformBridgeApis.MediaInfo { val remoteMediaClient: RemoteMediaClient = remoteMediaClient - ?: return PlatformBridgeApis.MediaInfo() + ?: throw IllegalStateException("Missing cast session") val hostMediaInfo = remoteMediaClient.mediaInfo ?: return PlatformBridgeApis.MediaInfo() @@ -277,6 +277,18 @@ class FlutterCastFrameworkPlugin : FlutterPlugin, MethodCallHandler, ActivityAwa val castSession = mCastSession ?: return castSession.isMute = muted } + + override fun getCastDevice(): PlatformBridgeApis.CastDevice { + val castSession = mCastSession ?: throw IllegalStateException("Missing cast session") + + val castDevice = castSession.castDevice + + return PlatformBridgeApis.CastDevice().apply { + deviceId = castDevice.deviceId + friendlyName = castDevice.friendlyName + modelName = castDevice.modelName + } + } } private fun getOnNamespaceResult(oldSession: CastSession?, newSession: CastSession?) = PlatformBridgeApis.CastFlutterApi.Reply> { namespaces -> diff --git a/ios/Classes/PlatformBridgeApis.h b/ios/Classes/PlatformBridgeApis.h index a57052e..8a9caa6 100644 --- a/ios/Classes/PlatformBridgeApis.h +++ b/ios/Classes/PlatformBridgeApis.h @@ -47,6 +47,7 @@ typedef NS_ENUM(NSUInteger, TrackSubtype) { @class MediaMetadata; @class WebImage; @class MediaTrack; +@class CastDevice; @class CastMessage; @interface MediaLoadRequestData : NSObject @@ -83,6 +84,12 @@ typedef NS_ENUM(NSUInteger, TrackSubtype) { @property(nonatomic, copy, nullable) NSString * language; @end +@interface CastDevice : NSObject +@property(nonatomic, copy, nullable) NSString * deviceId; +@property(nonatomic, copy, nullable) NSString * friendlyName; +@property(nonatomic, copy, nullable) NSString * modelName; +@end + @interface CastMessage : NSObject @property(nonatomic, copy, nullable) NSString * namespace; @property(nonatomic, copy, nullable) NSString * message; @@ -95,6 +102,7 @@ NSObject *CastHostApiGetCodec(void); - (void)sendMessageMessage:(CastMessage *)message error:(FlutterError *_Nullable *_Nonnull)error; - (void)showCastDialogWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)setMuteMuted:(NSNumber *)muted error:(FlutterError *_Nullable *_Nonnull)error; +- (nullable CastDevice *)getCastDeviceWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)loadMediaLoadRequestDataRequest:(MediaLoadRequestData *)request error:(FlutterError *_Nullable *_Nonnull)error; - (nullable MediaInfo *)getMediaInfoWithError:(FlutterError *_Nullable *_Nonnull)error; - (void)playWithError:(FlutterError *_Nullable *_Nonnull)error; diff --git a/ios/Classes/PlatformBridgeApis.m b/ios/Classes/PlatformBridgeApis.m index 3b59396..804f16f 100644 --- a/ios/Classes/PlatformBridgeApis.m +++ b/ios/Classes/PlatformBridgeApis.m @@ -42,6 +42,10 @@ static NSDictionary *wrapResult(id result, FlutterError *error) + (MediaTrack *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @end +@interface CastDevice () ++ (CastDevice *)fromMap:(NSDictionary *)dict; +- (NSDictionary *)toMap; +@end @interface CastMessage () + (CastMessage *)fromMap:(NSDictionary *)dict; - (NSDictionary *)toMap; @@ -161,6 +165,28 @@ static NSDictionary *wrapResult(id result, FlutterError *error) } @end +@implementation CastDevice ++ (CastDevice *)fromMap:(NSDictionary *)dict { + CastDevice *result = [[CastDevice alloc] init]; + result.deviceId = dict[@"deviceId"]; + if ((NSNull *)result.deviceId == [NSNull null]) { + result.deviceId = nil; + } + result.friendlyName = dict[@"friendlyName"]; + if ((NSNull *)result.friendlyName == [NSNull null]) { + result.friendlyName = nil; + } + result.modelName = dict[@"modelName"]; + if ((NSNull *)result.modelName == [NSNull null]) { + result.modelName = nil; + } + return result; +} +- (NSDictionary *)toMap { + return [NSDictionary dictionaryWithObjectsAndKeys:(self.deviceId ? self.deviceId : [NSNull null]), @"deviceId", (self.friendlyName ? self.friendlyName : [NSNull null]), @"friendlyName", (self.modelName ? self.modelName : [NSNull null]), @"modelName", nil]; +} +@end + @implementation CastMessage + (CastMessage *)fromMap:(NSDictionary *)dict { CastMessage *result = [[CastMessage alloc] init]; @@ -186,21 +212,24 @@ static NSDictionary *wrapResult(id result, FlutterError *error) { switch (type) { case 128: - return [CastMessage fromMap:[self readValue]]; + return [CastDevice fromMap:[self readValue]]; case 129: - return [MediaInfo fromMap:[self readValue]]; + return [CastMessage fromMap:[self readValue]]; case 130: - return [MediaLoadRequestData fromMap:[self readValue]]; + return [MediaInfo fromMap:[self readValue]]; case 131: - return [MediaMetadata fromMap:[self readValue]]; + return [MediaLoadRequestData fromMap:[self readValue]]; case 132: - return [MediaTrack fromMap:[self readValue]]; + return [MediaMetadata fromMap:[self readValue]]; case 133: + return [MediaTrack fromMap:[self readValue]]; + + case 134: return [WebImage fromMap:[self readValue]]; default: @@ -215,30 +244,34 @@ static NSDictionary *wrapResult(id result, FlutterError *error) @implementation CastHostApiCodecWriter - (void)writeValue:(id)value { - if ([value isKindOfClass:[CastMessage class]]) { + if ([value isKindOfClass:[CastDevice class]]) { [self writeByte:128]; [self writeValue:[value toMap]]; } else - if ([value isKindOfClass:[MediaInfo class]]) { + if ([value isKindOfClass:[CastMessage class]]) { [self writeByte:129]; [self writeValue:[value toMap]]; } else - if ([value isKindOfClass:[MediaLoadRequestData class]]) { + if ([value isKindOfClass:[MediaInfo class]]) { [self writeByte:130]; [self writeValue:[value toMap]]; } else - if ([value isKindOfClass:[MediaMetadata class]]) { + if ([value isKindOfClass:[MediaLoadRequestData class]]) { [self writeByte:131]; [self writeValue:[value toMap]]; } else - if ([value isKindOfClass:[MediaTrack class]]) { + if ([value isKindOfClass:[MediaMetadata class]]) { [self writeByte:132]; [self writeValue:[value toMap]]; } else - if ([value isKindOfClass:[WebImage class]]) { + if ([value isKindOfClass:[MediaTrack class]]) { [self writeByte:133]; [self writeValue:[value toMap]]; } else + if ([value isKindOfClass:[WebImage class]]) { + [self writeByte:134]; + [self writeValue:[value toMap]]; + } else { [super writeValue:value]; } @@ -326,6 +359,24 @@ void CastHostApiSetup(id binaryMessenger, NSObject) -> CastDevice? { + let castDevice = castSession?.device + + if (castDevice == nil) { + return CastDevice() + } + + let result = CastDevice() + + result.deviceId = castDevice?.deviceID + result.friendlyName = castDevice?.friendlyName + result.modelName = castDevice?.modelName + + return result + } + // MARK: - GCKSessionManagerListener // onSessionSuspended diff --git a/lib/src/PlatformBridgeApis.dart b/lib/src/PlatformBridgeApis.dart index db572db..457d602 100644 --- a/lib/src/PlatformBridgeApis.dart +++ b/lib/src/PlatformBridgeApis.dart @@ -176,6 +176,28 @@ class MediaTrack { } } +class CastDevice { + String? deviceId; + String? friendlyName; + String? modelName; + + Object encode() { + final Map pigeonMap = {}; + pigeonMap['deviceId'] = deviceId; + pigeonMap['friendlyName'] = friendlyName; + pigeonMap['modelName'] = modelName; + return pigeonMap; + } + + static CastDevice decode(Object message) { + final Map pigeonMap = message as Map; + return CastDevice() + ..deviceId = pigeonMap['deviceId'] as String? + ..friendlyName = pigeonMap['friendlyName'] as String? + ..modelName = pigeonMap['modelName'] as String?; + } +} + class CastMessage { String? namespace; String? message; @@ -199,30 +221,34 @@ class _CastHostApiCodec extends StandardMessageCodec { const _CastHostApiCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is CastMessage) { + if (value is CastDevice) { buffer.putUint8(128); writeValue(buffer, value.encode()); } else - if (value is MediaInfo) { + if (value is CastMessage) { buffer.putUint8(129); writeValue(buffer, value.encode()); } else - if (value is MediaLoadRequestData) { + if (value is MediaInfo) { buffer.putUint8(130); writeValue(buffer, value.encode()); } else - if (value is MediaMetadata) { + if (value is MediaLoadRequestData) { buffer.putUint8(131); writeValue(buffer, value.encode()); } else - if (value is MediaTrack) { + if (value is MediaMetadata) { buffer.putUint8(132); writeValue(buffer, value.encode()); } else - if (value is WebImage) { + if (value is MediaTrack) { buffer.putUint8(133); writeValue(buffer, value.encode()); } else + if (value is WebImage) { + buffer.putUint8(134); + writeValue(buffer, value.encode()); + } else { super.writeValue(buffer, value); } @@ -231,21 +257,24 @@ class _CastHostApiCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 128: - return CastMessage.decode(readValue(buffer)!); + return CastDevice.decode(readValue(buffer)!); case 129: - return MediaInfo.decode(readValue(buffer)!); + return CastMessage.decode(readValue(buffer)!); case 130: - return MediaLoadRequestData.decode(readValue(buffer)!); + return MediaInfo.decode(readValue(buffer)!); case 131: - return MediaMetadata.decode(readValue(buffer)!); + return MediaLoadRequestData.decode(readValue(buffer)!); case 132: - return MediaTrack.decode(readValue(buffer)!); + return MediaMetadata.decode(readValue(buffer)!); case 133: + return MediaTrack.decode(readValue(buffer)!); + + case 134: return WebImage.decode(readValue(buffer)!); default: @@ -334,6 +363,29 @@ class CastHostApi { } } + Future getCastDevice() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.CastHostApi.getCastDevice', codec, binaryMessenger: _binaryMessenger); + final Map? replyMap = + await channel.send(null) as Map?; + if (replyMap == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + details: null, + ); + } else if (replyMap['error'] != null) { + final Map error = (replyMap['error'] as Map?)!; + throw PlatformException( + code: (error['code'] as String?)!, + message: error['message'] as String?, + details: error['details'], + ); + } else { + return (replyMap['result'] as CastDevice?)!; + } + } + Future loadMediaLoadRequestData(MediaLoadRequestData arg_request) async { final BasicMessageChannel channel = BasicMessageChannel( 'dev.flutter.pigeon.CastHostApi.loadMediaLoadRequestData', codec, binaryMessenger: _binaryMessenger); diff --git a/lib/src/cast/SessionManager.dart b/lib/src/cast/SessionManager.dart index 3587bf0..d942a28 100644 --- a/lib/src/cast/SessionManager.dart +++ b/lib/src/cast/SessionManager.dart @@ -63,6 +63,11 @@ class SessionManager { _hostApi.setMute(muted); } + /// Returns the currently connected cast device + Future getCastDevice() async { + return await _hostApi.getCastDevice(); + } + RemoteMediaClient? _remoteMediaClient; /// Returns the RemoteMediaClient for remote media control. diff --git a/pigeon/PlatformBridgeApisDefinition.dart b/pigeon/PlatformBridgeApisDefinition.dart index e653546..30143f4 100644 --- a/pigeon/PlatformBridgeApisDefinition.dart +++ b/pigeon/PlatformBridgeApisDefinition.dart @@ -212,6 +212,12 @@ enum TrackSubtype { //#endregion +class CastDevice { + String? deviceId; + String? friendlyName; + String? modelName; +} + class CastMessage { String? namespace; String? message; @@ -222,6 +228,7 @@ abstract class CastHostApi { void sendMessage(CastMessage message); void showCastDialog(); void setMute(bool muted); + CastDevice getCastDevice(); //region RemoteMediaClient void loadMediaLoadRequestData(MediaLoadRequestData request);