mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
* initial cast framework complete and mocked cast dialog working * wip casting * casting works! just need to add session key check and remote video controls * cleanup of classes * add session expiration checks * cast dialog now shows connected device at top of list with a list header. Discovered devices are also cached for app session. * cast video player finalized * show fullsize assets on casting * translation already happens on the text element * remove prints * fix lintings * code review changes from @shenlong-tanwen * fix connect method override * fix alphabetization * remove important * filter chromecast audio devices * fix some disconnect command ordering issues and unawaited futures * remove prints * only disconnect if we are connected * don't try to reconnect if its the current device * add cast button to top bar * format sessions api * more formatting issues fixed * add snack bar to tell user that we cannot cast an asset that is not uploaded to server * make casting icon change to primary color when casting is active * only show casting snackbar if we are casting * dont show cast button if asset is remote and we are not casting * stop playing media if we seek to an asset that is not remote * remove https check since it works with local http IP addresses * remove unneeded imports * fix recasting when socket closes * fix info plist formatting * only show cast button if there is an active websocket connection (ie the server is accessible) * add device capability bitmask checks * small comment about bitmask
76 lines
1.9 KiB
Dart
76 lines
1.9 KiB
Dart
import 'package:cast/device.dart';
|
|
import 'package:cast/session.dart';
|
|
import 'package:cast/session_manager.dart';
|
|
import 'package:cast/discovery_service.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
final gCastRepositoryProvider = Provider((_) {
|
|
return GCastRepository();
|
|
});
|
|
|
|
class GCastRepository {
|
|
CastSession? _castSession;
|
|
|
|
void Function(CastSessionState)? onCastStatus;
|
|
void Function(Map<String, dynamic>)? onCastMessage;
|
|
|
|
Map<String, dynamic>? _receiverStatus;
|
|
|
|
GCastRepository();
|
|
|
|
Future<void> connect(CastDevice device) async {
|
|
_castSession = await CastSessionManager().startSession(device);
|
|
|
|
_castSession?.stateStream.listen((state) {
|
|
onCastStatus?.call(state);
|
|
});
|
|
|
|
_castSession?.messageStream.listen((message) {
|
|
onCastMessage?.call(message);
|
|
if (message['type'] == 'RECEIVER_STATUS') {
|
|
_receiverStatus = message;
|
|
}
|
|
});
|
|
|
|
// open the default receiver
|
|
sendMessage(CastSession.kNamespaceReceiver, {
|
|
'type': 'LAUNCH',
|
|
'appId': 'CC1AD845',
|
|
});
|
|
}
|
|
|
|
Future<void> disconnect() async {
|
|
final sessionID = getSessionId();
|
|
|
|
sendMessage(CastSession.kNamespaceReceiver, {
|
|
'type': "STOP",
|
|
"sessionId": sessionID,
|
|
});
|
|
|
|
// wait 500ms to ensure the stop command is processed
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
|
|
await _castSession?.close();
|
|
}
|
|
|
|
String? getSessionId() {
|
|
if (_receiverStatus == null) {
|
|
return null;
|
|
}
|
|
return _receiverStatus!['status']['applications'][0]['sessionId'];
|
|
}
|
|
|
|
void sendMessage(String namespace, Map<String, dynamic> message) {
|
|
if (_castSession == null) {
|
|
throw Exception("Cast session is not established");
|
|
}
|
|
|
|
_castSession!.sendMessage(namespace, message);
|
|
}
|
|
|
|
Future<List<CastDevice>> listDestinations() async {
|
|
return await CastDiscoveryService()
|
|
.search(timeout: const Duration(seconds: 3));
|
|
}
|
|
}
|