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;
appId: string;
sessionId?: string;
initialContentContext?: ContentContext;
autoJoinContexts: ContentContext[];
}
/** Creates a cast session object and sets up messaging. */
@@ -71,9 +71,13 @@ async function createCastSession(opts: {
bridgePort: await bridge.connect(),
deviceId: opts.deviceId,
appId: opts.appId,
initialContentContext: opts.instance.contentContext
autoJoinContexts: []
};
if (opts.instance.contentContext) {
session.autoJoinContexts.push(opts.instance.contentContext);
}
opts.instance.session = session;
opts.instance.bridgeMessageListener = message => {
handleBridgeMessage(opts.instance, message);
@@ -96,6 +100,56 @@ async function createCastSession(opts: {
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 {
contentPort: AnyPort;
contentContext?: ContentContext;
@@ -180,6 +234,7 @@ function destroyCastInstance(instance: CastInstance) {
const allowedContentMessages: Array<Message["subject"]> = [
"main:initializeCastSdk",
"main:requestSession",
"main:requestSessionById",
"bridge:sendCastReceiverMessage",
"bridge:sendCastSessionMessage"
];
@@ -493,75 +548,29 @@ async function handleContentMessage(instance: CastInstance, message: Message) {
continue;
}
switch (instance.apiConfig.autoJoinPolicy) {
case AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED:
// Ensure matching content tontext
// Check for valid auto join sessions
const { autoJoinPolicy } = instance.apiConfig;
if (
autoJoinPolicy === AutoJoinPolicy.ORIGIN_SCOPED ||
autoJoinPolicy === AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED
) {
for (const context of session.autoJoinContexts) {
// Check same origin
if (
!isSameContext(
instance.contentContext,
session.initialContentContext
)
)
break;
// eslint-disable-next-line no-fallthrough
case AutoJoinPolicy.ORIGIN_SCOPED: {
// Ensure matching origin
context.origin !== instance.contentContext?.origin
) {
continue;
}
// Check same context for tab scoped
if (
instance.contentContext?.origin !==
session.initialContentContext?.origin
)
break;
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
);
autoJoinPolicy ===
AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED &&
!isSameContext(context, instance.contentContext)
) {
continue;
}
joinSession(instance, session);
break sessionLoop;
}
}
@@ -666,6 +675,27 @@ async function handleContentMessage(instance: CastInstance, message: Message) {
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) {
logger.info("STUB :: cast.requestSessionById");
requestSessionById(sessionId: string) {
pageMessaging.page.sendMessage({
subject: "main:requestSessionById",
data: { sessionId }
});
}
setCustomReceivers(

View File

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