Implement chrome.cast.requestSessionById

This commit is contained in:
hensm
2022-09-10 21:34:42 +01:00
parent 56bd6f841f
commit 0505b0d0b5
3 changed files with 104 additions and 69 deletions

View File

@@ -48,7 +48,7 @@ interface CastSession {
deviceId: string; deviceId: string;
appId: string; appId: string;
sessionId?: string; sessionId?: string;
initialContentContext?: ContentContext; autoJoinContexts: ContentContext[];
} }
/** Creates a cast session object and sets up messaging. */ /** Creates a cast session object and sets up messaging. */
@@ -71,9 +71,13 @@ async function createCastSession(opts: {
bridgePort: await bridge.connect(), bridgePort: await bridge.connect(),
deviceId: opts.deviceId, deviceId: opts.deviceId,
appId: opts.appId, appId: opts.appId,
initialContentContext: opts.instance.contentContext autoJoinContexts: []
}; };
if (opts.instance.contentContext) {
session.autoJoinContexts.push(opts.instance.contentContext);
}
opts.instance.session = session; opts.instance.session = session;
opts.instance.bridgeMessageListener = message => { opts.instance.bridgeMessageListener = message => {
handleBridgeMessage(opts.instance, message); handleBridgeMessage(opts.instance, message);
@@ -96,6 +100,56 @@ async function createCastSession(opts: {
return session; return session;
} }
function joinSession(instance: CastInstance, session: CastSession) {
if (!session.sessionId) return;
instance.session = session;
instance.bridgeMessageListener = message =>
handleBridgeMessage(instance, message);
session.bridgePort.onMessage.addListener(instance.bridgeMessageListener);
session.bridgePort.onDisconnect.addListener(() =>
destroyCastInstance(instance)
);
const device = deviceManager.getDeviceById(session.deviceId);
if (!device?.status?.applications?.length) {
throw logger.error("Invalid device state!");
}
/**
* Re-create sessionCreated message. Since the
* sender app hasn't requested a session, this
* will be handled by calling the session
* listener.
*/
const application = device?.status?.applications[0];
instance.contentPort.postMessage({
subject: "cast:sessionCreated",
data: {
appId: application.appId,
appImages: [],
displayName: application.displayName,
namespaces: application.namespaces,
receiver: createReceiver(device),
receiverFriendlyName: device.friendlyName,
receiverId: device.id,
senderApps: [],
sessionId: session.sessionId,
statusText: application.statusText,
transportId: session.sessionId,
volume: device.status.volume
}
});
if (instance.contentContext?.tabId) {
updateActionState(
ActionState.Connected,
instance.contentContext?.tabId
);
}
}
export interface CastInstance { export interface CastInstance {
contentPort: AnyPort; contentPort: AnyPort;
contentContext?: ContentContext; contentContext?: ContentContext;
@@ -180,6 +234,7 @@ function destroyCastInstance(instance: CastInstance) {
const allowedContentMessages: Array<Message["subject"]> = [ const allowedContentMessages: Array<Message["subject"]> = [
"main:initializeCastSdk", "main:initializeCastSdk",
"main:requestSession", "main:requestSession",
"main:requestSessionById",
"bridge:sendCastReceiverMessage", "bridge:sendCastReceiverMessage",
"bridge:sendCastSessionMessage" "bridge:sendCastSessionMessage"
]; ];
@@ -493,75 +548,29 @@ async function handleContentMessage(instance: CastInstance, message: Message) {
continue; continue;
} }
switch (instance.apiConfig.autoJoinPolicy) { // Check for valid auto join sessions
case AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED: const { autoJoinPolicy } = instance.apiConfig;
// Ensure matching content tontext if (
autoJoinPolicy === AutoJoinPolicy.ORIGIN_SCOPED ||
autoJoinPolicy === AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED
) {
for (const context of session.autoJoinContexts) {
// Check same origin
if ( if (
!isSameContext( context.origin !== instance.contentContext?.origin
instance.contentContext, ) {
session.initialContentContext continue;
) }
) // Check same context for tab scoped
break;
// eslint-disable-next-line no-fallthrough
case AutoJoinPolicy.ORIGIN_SCOPED: {
// Ensure matching origin
if ( if (
instance.contentContext?.origin !== autoJoinPolicy ===
session.initialContentContext?.origin AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED &&
) !isSameContext(context, instance.contentContext)
break; ) {
continue;
instance.session = session;
instance.bridgeMessageListener = message =>
handleBridgeMessage(instance, message);
session.bridgePort.onMessage.addListener(
instance.bridgeMessageListener
);
session.bridgePort.onDisconnect.addListener(() =>
destroyCastInstance(instance)
);
const device = deviceManager.getDeviceById(
session.deviceId
);
if (!device?.status?.applications?.length) {
throw logger.error("Invalid device state");
}
/**
* Re-create sessionCreated message. Since the
* sender app hasn't requested a session, this
* will be handled by calling the session
* listener.
*/
const application = device?.status?.applications[0];
instance.contentPort.postMessage({
subject: "cast:sessionCreated",
data: {
appId: application.appId,
appImages: [],
displayName: application.displayName,
namespaces: application.namespaces,
receiver: createReceiver(device),
receiverFriendlyName: device.friendlyName,
receiverId: device.id,
senderApps: [],
sessionId: session.sessionId,
statusText: application.statusText,
transportId: session.sessionId,
volume: device.status.volume
}
});
if (instance.contentContext?.tabId) {
updateActionState(
ActionState.Connected,
instance.contentContext?.tabId
);
} }
joinSession(instance, session);
break sessionLoop; break sessionLoop;
} }
} }
@@ -666,6 +675,27 @@ async function handleContentMessage(instance: CastInstance, message: Message) {
break; break;
} }
case "main:requestSessionById": {
const session = activeSessions.get(message.data.sessionId);
if (!session) {
logger.log(
`Session not found! (id: ${message.data.sessionId})`
);
break;
}
if (instance.apiConfig?.sessionRequest.appId === session.appId) {
joinSession(instance, session);
// If requesting by ID, add to the list of auto join contexts
if (instance.contentContext) {
session.autoJoinContexts.push(instance.contentContext);
}
}
break;
}
} }
} }

View File

@@ -349,8 +349,11 @@ export default class {
}); });
} }
requestSessionById(_sessionId: string) { requestSessionById(sessionId: string) {
logger.info("STUB :: cast.requestSessionById"); pageMessaging.page.sendMessage({
subject: "main:requestSessionById",
data: { sessionId }
});
} }
setCustomReceivers( setCustomReceivers(

View File

@@ -92,6 +92,8 @@ type ExtMessageDefinitions = {
/** Return message to the cast API when a selection is cancelled. */ /** Return message to the cast API when a selection is cancelled. */
"cast:sessionRequestCancelled": undefined; "cast:sessionRequestCancelled": undefined;
"main:requestSessionById": { sessionId: string };
"cast:instanceCreated": { isAvailable: boolean }; "cast:instanceCreated": { isAvailable: boolean };
"cast:receiverAvailabilityUpdated": { isAvailable: boolean }; "cast:receiverAvailabilityUpdated": { isAvailable: boolean };