libaribhtml5 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/dist/sdk/arib-vfs-sw.js +336 -0
- package/dist/sdk/libaribhtml5.js +11 -0
- package/dist/sdk/libaribhtml5.mjs +1353 -0
- package/dist/types/broadcast-document.d.ts +12 -0
- package/dist/types/broadcast-url.d.ts +9 -0
- package/dist/types/device-identifier.d.ts +4 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/media-plane.d.ts +79 -0
- package/dist/types/program-guide.d.ts +25 -0
- package/dist/types/program-info.d.ts +29 -0
- package/dist/types/receiver-host.d.ts +144 -0
- package/dist/types/runtime/clock.d.ts +5 -0
- package/dist/types/runtime/fonts.d.ts +4 -0
- package/dist/types/runtime/install.d.ts +31 -0
- package/dist/types/runtime/resources.d.ts +22 -0
- package/dist/types/runtime/romsound-markup.d.ts +5 -0
- package/dist/types/runtime/romsound.d.ts +4 -0
- package/dist/types/runtime/system-information.d.ts +14 -0
- package/dist/types/service-worker-vfs.d.ts +66 -0
- package/docs/android-program-guide.md +127 -0
- package/docs/broadcast-clock.md +57 -0
- package/docs/broadcast-resources-and-fonts.md +143 -0
- package/docs/media-plane-integration.md +227 -0
- package/docs/receiver-host-contracts.md +92 -0
- package/package.json +69 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type BroadcastDocumentOptions = {
|
|
2
|
+
/** Current carousel mount, for example /data-broadcast/sh4/. */
|
|
3
|
+
basePath?: string;
|
|
4
|
+
/** Worker/server scope containing the mount, for example /data-broadcast/. */
|
|
5
|
+
scopePath?: string;
|
|
6
|
+
/** Inline bootstrap inserted at the start of head, including its script tag. */
|
|
7
|
+
bootstrap?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function rewriteBroadcastObjectMarkup(source: string): string;
|
|
10
|
+
export declare function prefixBroadcastRootAttributes(source: string, basePath?: string, scopePath?: string): string;
|
|
11
|
+
export declare function prepareBroadcastStylesheet(source: string, options?: BroadcastDocumentOptions): string;
|
|
12
|
+
export declare function prepareBroadcastHtml(source: string, options?: BroadcastDocumentOptions): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const DEFAULT_BROADCAST_BASE_PATH = "/data-broadcast/";
|
|
2
|
+
export declare function normalizeBroadcastBaseUrl(value: string | URL | undefined, documentUrl: string | URL): URL;
|
|
3
|
+
/**
|
|
4
|
+
* Derive the current carousel mount from a served document URL.
|
|
5
|
+
* `/data-broadcast/<mount>/...` maps broadcast-root paths below `<mount>`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function deriveBroadcastRootUrl(documentUrl: string | URL, base: URL): URL;
|
|
8
|
+
/** Map a receiver-visible broadcast path into its isolated HTTP namespace. */
|
|
9
|
+
export declare function resolveBroadcastUrl(value: string | URL, base: URL, broadcastRoot?: URL): URL;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Current demo receiver identifier (48-bit hexadecimal ACAS source value). */
|
|
2
|
+
export declare const DEFAULT_RECEIVER_DEVICE_IDENTIFIER = "4194c4ae4730";
|
|
3
|
+
export type ReceiverDeviceIdentifierProvider = (kind: number) => string | null | undefined | Promise<string | null | undefined>;
|
|
4
|
+
export declare function resolveReceiverDeviceIdentifier(kind: number, provider?: ReceiverDeviceIdentifierProvider): Promise<string>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { AribReceiverHost } from './receiver-host';
|
|
2
|
+
export type { AribCaptionPacket, AribBroadcastClock, AribReceiverLifecycleEvent, AribReceiverHostOptions, } from './receiver-host';
|
|
3
|
+
export { BehindIframeMediaPlaneAdapter, DomObjectMediaPlaneAdapter, } from './media-plane';
|
|
4
|
+
export type { AribMediaPlane, AribMediaPlaneAdapter, AribMediaPlaneLayer, AribMediaPlaneStackEntry, AribMediaPlaneUnmountReason, AribVideoPlane, BehindIframeMediaPlaneAdapterOptions, DomObjectMediaPlaneAdapterOptions, } from './media-plane';
|
|
5
|
+
export { installRuntime } from './runtime/install';
|
|
6
|
+
export { createReceiverSystemInformation, RECEIVER_SYSTEM_IDENTITY, } from './runtime/system-information';
|
|
7
|
+
export type { ReceiverSystemIdentity, ReceiverSystemInformation, ReceiverSystemInformationOverrides, } from './runtime/system-information';
|
|
8
|
+
export { cloneProgramInfo } from './program-info';
|
|
9
|
+
export type { ProgramInfo } from './program-info';
|
|
10
|
+
export type { RuntimeEvent, RuntimeOptions, RuntimeWindow } from './runtime/install';
|
|
11
|
+
export { DEFAULT_RECEIVER_DEVICE_IDENTIFIER, resolveReceiverDeviceIdentifier, } from './device-identifier';
|
|
12
|
+
export type { ReceiverDeviceIdentifierProvider } from './device-identifier';
|
|
13
|
+
export type { BroadcastResourceCacheEvent, BroadcastResourceCacheListener, BroadcastResourceChange, BroadcastResourceStore, } from './runtime/resources';
|
|
14
|
+
export { installBroadcastClock } from './runtime/clock';
|
|
15
|
+
export type { BroadcastNowProvider } from './runtime/clock';
|
|
16
|
+
export { installAribSymbolFont } from './runtime/fonts';
|
|
17
|
+
export { DEFAULT_BROADCAST_BASE_PATH, deriveBroadcastRootUrl, normalizeBroadcastBaseUrl, resolveBroadcastUrl, } from './broadcast-url';
|
|
18
|
+
export { deferRomSoundMarkup, installRomSoundProtocol, resolveRomSoundUrl, } from './runtime/romsound';
|
|
19
|
+
export { prefixBroadcastRootAttributes, prepareBroadcastHtml, prepareBroadcastStylesheet, rewriteBroadcastObjectMarkup, } from './broadcast-document';
|
|
20
|
+
export type { BroadcastDocumentOptions } from './broadcast-document';
|
|
21
|
+
export { BroadcastVfsSession, ServiceWorkerBroadcastVfs } from './service-worker-vfs';
|
|
22
|
+
export type { BroadcastVfsBackend, BroadcastVfsResource, BroadcastVfsSessionOptions, ServiceWorkerBroadcastVfsOptions, } from './service-worker-vfs';
|
|
23
|
+
export type { AribProgramGuideHandler, AribProgramGuideRequest, AribProgramGuideUnavailableEvent, AribProgramGuideUnavailableHandler, AribProgramGuideUnavailableReason, } from './program-guide';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export type AribMediaPlaneStackEntry = {
|
|
2
|
+
tagName: string;
|
|
3
|
+
id?: string;
|
|
4
|
+
position: string;
|
|
5
|
+
zIndex: string;
|
|
6
|
+
display: string;
|
|
7
|
+
visibility: string;
|
|
8
|
+
opacity: number;
|
|
9
|
+
transform: string;
|
|
10
|
+
};
|
|
11
|
+
export type AribMediaPlaneLayer = {
|
|
12
|
+
documentOrder: number;
|
|
13
|
+
stackingPath: AribMediaPlaneStackEntry[];
|
|
14
|
+
};
|
|
15
|
+
export type AribMediaPlane = {
|
|
16
|
+
slotId: string;
|
|
17
|
+
visible: boolean;
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
screenWidth: number;
|
|
23
|
+
screenHeight: number;
|
|
24
|
+
videoSource?: string;
|
|
25
|
+
audioSource?: string;
|
|
26
|
+
layer: AribMediaPlaneLayer;
|
|
27
|
+
};
|
|
28
|
+
/** @deprecated Use AribMediaPlane. */
|
|
29
|
+
export type AribVideoPlane = AribMediaPlane;
|
|
30
|
+
export type AribMediaPlaneUnmountReason = 'slot-removed' | 'document-unload' | 'application-exit' | 'host-destroy';
|
|
31
|
+
export interface AribMediaPlaneAdapter {
|
|
32
|
+
/**
|
|
33
|
+
* `in-object` renders at the actual object position in the application DOM.
|
|
34
|
+
* `external` uses a host/native plane and receives the object's layer metadata.
|
|
35
|
+
*/
|
|
36
|
+
readonly renderMode: 'in-object' | 'external';
|
|
37
|
+
mountMediaPlane(object: HTMLElement, plane: AribMediaPlane): void;
|
|
38
|
+
updateMediaPlane(object: HTMLElement, plane: AribMediaPlane): void;
|
|
39
|
+
unmountMediaPlane(reason: AribMediaPlaneUnmountReason): void;
|
|
40
|
+
}
|
|
41
|
+
export type DomObjectMediaPlaneAdapterOptions = {
|
|
42
|
+
media: HTMLElement;
|
|
43
|
+
/** Container used by the ordinary player outside data-broadcast mode. */
|
|
44
|
+
normalPlayerContainer?: HTMLElement;
|
|
45
|
+
/** @deprecated Use normalPlayerContainer. */
|
|
46
|
+
parkingContainer?: HTMLElement;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Browser demo adapter which adopts the media element into the broadcast
|
|
50
|
+
* object's fallback content. This preserves the application's own DOM order.
|
|
51
|
+
*/
|
|
52
|
+
export declare class DomObjectMediaPlaneAdapter implements AribMediaPlaneAdapter {
|
|
53
|
+
readonly renderMode: "in-object";
|
|
54
|
+
private readonly media;
|
|
55
|
+
private readonly normalPlayerContainer?;
|
|
56
|
+
private mountedObject;
|
|
57
|
+
constructor(options: DomObjectMediaPlaneAdapterOptions);
|
|
58
|
+
mountMediaPlane(object: HTMLElement, plane: AribMediaPlane): void;
|
|
59
|
+
updateMediaPlane(object: HTMLElement, plane: AribMediaPlane): void;
|
|
60
|
+
unmountMediaPlane(reason: AribMediaPlaneUnmountReason): void;
|
|
61
|
+
}
|
|
62
|
+
export type BehindIframeMediaPlaneAdapterOptions = {
|
|
63
|
+
surface: HTMLElement;
|
|
64
|
+
keepVisible?: boolean;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Simplified compatibility fallback. It cannot interleave media with elements
|
|
68
|
+
* inside the application iframe; the complete iframe is always above it.
|
|
69
|
+
*/
|
|
70
|
+
export declare class BehindIframeMediaPlaneAdapter implements AribMediaPlaneAdapter {
|
|
71
|
+
readonly renderMode: "external";
|
|
72
|
+
private readonly surface;
|
|
73
|
+
private readonly keepVisible;
|
|
74
|
+
constructor(options: BehindIframeMediaPlaneAdapterOptions);
|
|
75
|
+
mountMediaPlane(_object: HTMLElement, plane: AribMediaPlane): void;
|
|
76
|
+
updateMediaPlane(_object: HTMLElement, plane: AribMediaPlane): void;
|
|
77
|
+
unmountMediaPlane(reason: AribMediaPlaneUnmountReason): void;
|
|
78
|
+
private apply;
|
|
79
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ProgramInfo } from './program-info.js';
|
|
2
|
+
export type AribProgramGuideRequest = {
|
|
3
|
+
/**
|
|
4
|
+
* Open the receiver's full program guide, or focus a particular program.
|
|
5
|
+
* Android/WebView hosts normally map `program-detail` to their native EPG UI.
|
|
6
|
+
*/
|
|
7
|
+
destination: 'program-guide' | 'program-detail';
|
|
8
|
+
/** Program identity and metadata supplied by the player/EPG search result. */
|
|
9
|
+
program?: ProgramInfo;
|
|
10
|
+
/** Presentation state used by the host; Android distinguishes live and future results. */
|
|
11
|
+
state?: 'current' | 'future';
|
|
12
|
+
};
|
|
13
|
+
export type AribProgramGuideHandler = (request: AribProgramGuideRequest) => boolean | void | Promise<boolean | void>;
|
|
14
|
+
export type AribProgramGuideUnavailableReason = 'unsupported' | 'rejected' | 'error';
|
|
15
|
+
export type AribProgramGuideUnavailableEvent = {
|
|
16
|
+
request: AribProgramGuideRequest;
|
|
17
|
+
reason: AribProgramGuideUnavailableReason;
|
|
18
|
+
error?: unknown;
|
|
19
|
+
};
|
|
20
|
+
export type AribProgramGuideUnavailableHandler = (event: AribProgramGuideUnavailableEvent) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Dispatch a receiver-owned EPG transition without coupling the SDK to a
|
|
23
|
+
* particular Android activity, WebView bridge, or browser player UI.
|
|
24
|
+
*/
|
|
25
|
+
export declare function dispatchProgramGuideRequest(request: AribProgramGuideRequest, handler?: AribProgramGuideHandler, unavailable?: AribProgramGuideUnavailableHandler): Promise<boolean>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Receiver-owned current/following event information exposed to broadcast apps.
|
|
3
|
+
* Dates are JavaScript Date objects and durations are milliseconds.
|
|
4
|
+
*/
|
|
5
|
+
export type ProgramInfo = {
|
|
6
|
+
original_network_id?: number;
|
|
7
|
+
transport_stream_id?: number;
|
|
8
|
+
service_id?: number;
|
|
9
|
+
event_id?: number;
|
|
10
|
+
name?: string;
|
|
11
|
+
event_name?: string;
|
|
12
|
+
start_time?: Date;
|
|
13
|
+
/** Event duration in milliseconds. */
|
|
14
|
+
duration?: number;
|
|
15
|
+
desc?: string;
|
|
16
|
+
event_text?: string;
|
|
17
|
+
event_extended_text?: string;
|
|
18
|
+
running_status?: number;
|
|
19
|
+
free_ca_mode?: boolean;
|
|
20
|
+
f_event_id?: number;
|
|
21
|
+
f_name?: string;
|
|
22
|
+
f_start_time?: Date;
|
|
23
|
+
/** Following-event duration in milliseconds. */
|
|
24
|
+
f_duration?: number;
|
|
25
|
+
f_desc?: string;
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
};
|
|
28
|
+
/** Validate and detach program information before it crosses the host boundary. */
|
|
29
|
+
export declare function cloneProgramInfo(value: ProgramInfo): ProgramInfo;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { type RuntimeEvent, type RuntimeWindow } from './runtime/install';
|
|
2
|
+
import { type ProgramInfo } from './program-info';
|
|
3
|
+
import type { ReceiverSystemInformationOverrides } from './runtime/system-information';
|
|
4
|
+
import type { ReceiverDeviceIdentifierProvider } from './device-identifier';
|
|
5
|
+
import { type AribMediaPlane, type AribMediaPlaneAdapter } from './media-plane';
|
|
6
|
+
import type { BroadcastResourceChange, BroadcastResourceStore } from './runtime/resources';
|
|
7
|
+
import { type AribProgramGuideHandler, type AribProgramGuideRequest, type AribProgramGuideUnavailableHandler } from './program-guide';
|
|
8
|
+
export type { AribMediaPlane, AribMediaPlaneAdapter, AribMediaPlaneLayer, AribMediaPlaneStackEntry, AribMediaPlaneUnmountReason, AribVideoPlane, } from './media-plane';
|
|
9
|
+
export type AribCaptionPacket = {
|
|
10
|
+
componentTag: number;
|
|
11
|
+
payload?: string;
|
|
12
|
+
dataType?: string;
|
|
13
|
+
tmd?: string;
|
|
14
|
+
data?: string;
|
|
15
|
+
};
|
|
16
|
+
export type AribBroadcastClock = {
|
|
17
|
+
/** Absolute broadcast time at the anchor, as Unix epoch milliseconds. */
|
|
18
|
+
epochMilliseconds: number;
|
|
19
|
+
/** Media timeline value which corresponds to epochMilliseconds. */
|
|
20
|
+
mediaTimeSeconds?: number;
|
|
21
|
+
/** Current playback position; enables pause, rate, and seek aware projection. */
|
|
22
|
+
currentMediaTimeSeconds?: () => number;
|
|
23
|
+
};
|
|
24
|
+
export type AribReceiverLifecycleEvent = {
|
|
25
|
+
type: 'loading';
|
|
26
|
+
url: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'installed';
|
|
29
|
+
url: string;
|
|
30
|
+
runtimeId: string;
|
|
31
|
+
} | {
|
|
32
|
+
type: 'navigating';
|
|
33
|
+
url: string;
|
|
34
|
+
} | {
|
|
35
|
+
type: 'exited';
|
|
36
|
+
} | {
|
|
37
|
+
type: 'navigation-blocked';
|
|
38
|
+
url: string;
|
|
39
|
+
} | {
|
|
40
|
+
type: 'frame-blocked';
|
|
41
|
+
url: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: 'error';
|
|
44
|
+
message: string;
|
|
45
|
+
};
|
|
46
|
+
export type AribReceiverHostOptions = {
|
|
47
|
+
iframe: HTMLIFrameElement;
|
|
48
|
+
viewport: HTMLElement;
|
|
49
|
+
/** Surface used only by the behind-iframe compatibility adapter. */
|
|
50
|
+
videoSurface?: HTMLElement;
|
|
51
|
+
mediaPlaneAdapter?: AribMediaPlaneAdapter;
|
|
52
|
+
onStatus?: (status: string) => void;
|
|
53
|
+
/** Machine-readable application/runtime lifecycle; never branch on onStatus text. */
|
|
54
|
+
onLifecycle?: (event: AribReceiverLifecycleEvent) => void;
|
|
55
|
+
onUrlChange?: (url: string) => void;
|
|
56
|
+
onMediaPlane?: (plane: AribMediaPlane) => void;
|
|
57
|
+
/** @deprecated Use onMediaPlane. */
|
|
58
|
+
onVideoPlane?: (plane: AribMediaPlane) => void;
|
|
59
|
+
keepVideoVisible?: boolean;
|
|
60
|
+
/** Allow broadcaster applications to use HTTP origins outside this host. */
|
|
61
|
+
allowExternalNetwork?: boolean;
|
|
62
|
+
/** Same-origin namespace where a Worker or HTTP server exposes carousel data. */
|
|
63
|
+
broadcastBaseUrl?: string | URL;
|
|
64
|
+
/** Optional bridge to a Service Worker, Cache Storage, or carousel VFS. */
|
|
65
|
+
resourceStore?: BroadcastResourceStore;
|
|
66
|
+
/** Receiver/WebView bridge which opens the native EPG or a program detail page. */
|
|
67
|
+
onOpenProgramGuide?: AribProgramGuideHandler;
|
|
68
|
+
/** Override the default browser alert when the receiver cannot open the EPG. */
|
|
69
|
+
onProgramGuideUnavailable?: AribProgramGuideUnavailableHandler;
|
|
70
|
+
/** Receiver identity/capabilities exposed to the broadcast application. */
|
|
71
|
+
systemInformation?: ReceiverSystemInformationOverrides;
|
|
72
|
+
/** Resolve receiver/CAS identifiers; defaults to the bundled Huggy demo identity. */
|
|
73
|
+
getDeviceIdentifier?: ReceiverDeviceIdentifierProvider;
|
|
74
|
+
};
|
|
75
|
+
export declare class AribReceiverHost {
|
|
76
|
+
readonly iframe: HTMLIFrameElement;
|
|
77
|
+
readonly viewport: HTMLElement;
|
|
78
|
+
readonly videoSurface?: HTMLElement;
|
|
79
|
+
private readonly ownerWindow;
|
|
80
|
+
private readonly origin;
|
|
81
|
+
private readonly onStatus?;
|
|
82
|
+
private readonly onLifecycle?;
|
|
83
|
+
private readonly onUrlChange?;
|
|
84
|
+
private readonly onMediaPlane?;
|
|
85
|
+
private readonly onVideoPlane?;
|
|
86
|
+
private readonly mediaPlaneAdapter?;
|
|
87
|
+
private readonly runtimeMediaPlaneAdapter?;
|
|
88
|
+
private readonly allowExternalNetwork;
|
|
89
|
+
private readonly broadcastBaseUrl;
|
|
90
|
+
private readonly resourceStore?;
|
|
91
|
+
private readonly onOpenProgramGuide?;
|
|
92
|
+
private readonly onProgramGuideUnavailable?;
|
|
93
|
+
private readonly systemInformation?;
|
|
94
|
+
private readonly getDeviceIdentifier?;
|
|
95
|
+
private readonly resizeObserver;
|
|
96
|
+
private activeRuntimeId;
|
|
97
|
+
private logicalWidth;
|
|
98
|
+
private logicalHeight;
|
|
99
|
+
private captionComponentTags;
|
|
100
|
+
private programInfo;
|
|
101
|
+
private broadcastClock;
|
|
102
|
+
private video;
|
|
103
|
+
private mediaPlaneEnabled;
|
|
104
|
+
private applicationExited;
|
|
105
|
+
private destroyed;
|
|
106
|
+
constructor(options: AribReceiverHostOptions);
|
|
107
|
+
installRuntime(target: RuntimeWindow): void;
|
|
108
|
+
/** @deprecated Pass an AribMediaPlaneAdapter to the constructor. */
|
|
109
|
+
attachVideo(video: HTMLVideoElement): void;
|
|
110
|
+
loadApplication(url: string, status?: string): void;
|
|
111
|
+
/** Leave data-broadcast mode and restore media to the ordinary player. */
|
|
112
|
+
exitApplication(status?: string): void;
|
|
113
|
+
dispatchKey(code: number): void;
|
|
114
|
+
setCaptionTracks(componentTags: number[]): void;
|
|
115
|
+
pushCaption(packet: AribCaptionPacket): void;
|
|
116
|
+
resetCaptions(): void;
|
|
117
|
+
/** Notify a stored carousel resource after the receiver updates or removes it. */
|
|
118
|
+
notifyDataResource(path: string, change: BroadcastResourceChange): void;
|
|
119
|
+
setProgramInfo(value: ProgramInfo): void;
|
|
120
|
+
/** Clear stale EIT state while changing services or broadcast sessions. */
|
|
121
|
+
clearProgramInfo(): void;
|
|
122
|
+
/**
|
|
123
|
+
* Ask the receiver host to open its EPG. A WebView host can bridge this to a
|
|
124
|
+
* native activity; an ordinary browser receives a clear unsupported notice.
|
|
125
|
+
*/
|
|
126
|
+
openProgramGuide(request?: AribProgramGuideRequest): Promise<boolean>;
|
|
127
|
+
/** Set a free-running broadcast clock from an absolute Unix time. */
|
|
128
|
+
setBroadcastTime(value: number | Date): void;
|
|
129
|
+
/** Set an absolute clock anchor, optionally projected from the media timeline. */
|
|
130
|
+
setBroadcastClock(value: AribBroadcastClock): void;
|
|
131
|
+
clearBroadcastClock(): void;
|
|
132
|
+
getBroadcastTime(): number;
|
|
133
|
+
emitStreamEvent(value: RuntimeEvent): void;
|
|
134
|
+
destroy(): void;
|
|
135
|
+
private readonly handleFrameLoad;
|
|
136
|
+
private readonly reportProgramGuideUnavailable;
|
|
137
|
+
private readonly handleRuntimeMessage;
|
|
138
|
+
private applyMediaPlane;
|
|
139
|
+
private readMediaLayer;
|
|
140
|
+
private postToRuntime;
|
|
141
|
+
private invalidateRuntime;
|
|
142
|
+
private fitBroadcastCanvas;
|
|
143
|
+
private assertAlive;
|
|
144
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
type ClockWindow = Window & typeof globalThis & Record<string, unknown>;
|
|
2
|
+
export type BroadcastNowProvider = () => number;
|
|
3
|
+
/** Override only the zero-argument Date paths used for the receiver clock. */
|
|
4
|
+
export declare function installBroadcastClock(target: ClockWindow, provider?: BroadcastNowProvider): void;
|
|
5
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type BroadcastNowProvider } from './clock';
|
|
2
|
+
import type { AribMediaPlaneAdapter } from '../media-plane';
|
|
3
|
+
import { type BroadcastResourceStore } from './resources';
|
|
4
|
+
import { type ReceiverSystemInformationOverrides } from './system-information';
|
|
5
|
+
import { type ReceiverDeviceIdentifierProvider } from '../device-identifier';
|
|
6
|
+
export type { ProgramInfo } from '../program-info';
|
|
7
|
+
export type RuntimeWindow = Window & typeof globalThis & Record<string, unknown>;
|
|
8
|
+
export type RuntimeEvent = {
|
|
9
|
+
source: {
|
|
10
|
+
event_message_tag: number;
|
|
11
|
+
};
|
|
12
|
+
message_id: number;
|
|
13
|
+
private_data_byte: string;
|
|
14
|
+
};
|
|
15
|
+
export type RuntimeOptions = {
|
|
16
|
+
/** Permit HTTP requests outside the receiver-managed application origin. */
|
|
17
|
+
allowExternalNetwork?: boolean;
|
|
18
|
+
/** Same-origin namespace where receiver-managed broadcast resources live. */
|
|
19
|
+
broadcastBaseUrl?: string | URL;
|
|
20
|
+
/** Optional Worker/cache bridge used by storeDataResource(). */
|
|
21
|
+
resourceStore?: BroadcastResourceStore;
|
|
22
|
+
/** Bind the broadcast object to a browser, native, or compositor media plane. */
|
|
23
|
+
mediaPlaneAdapter?: AribMediaPlaneAdapter;
|
|
24
|
+
/** Return current broadcast time as Unix epoch milliseconds. */
|
|
25
|
+
now?: BroadcastNowProvider;
|
|
26
|
+
/** Receiver identity/capabilities exposed by receiverDevice.getSystemInformation(). */
|
|
27
|
+
systemInformation?: ReceiverSystemInformationOverrides;
|
|
28
|
+
/** Resolve receiver/CAS identifiers by receiverDevice identifier kind. */
|
|
29
|
+
getDeviceIdentifier?: ReceiverDeviceIdentifierProvider;
|
|
30
|
+
};
|
|
31
|
+
export declare function installRuntime(target: RuntimeWindow, options?: RuntimeOptions): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type BroadcastResourceChange = 'updated' | 'deleted';
|
|
2
|
+
export type BroadcastResourceCacheEvent = 'store_finished' | 'store_failed' | BroadcastResourceChange;
|
|
3
|
+
export type BroadcastResourceStore = {
|
|
4
|
+
/** Resolve and retain a complete carousel resource. */
|
|
5
|
+
store: (url: string, options: {
|
|
6
|
+
signal: AbortSignal;
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
/** Drop receiver-managed state for a previously retained resource. */
|
|
9
|
+
release?: (url: string) => void | Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export type BroadcastResourceCacheListener = (path: string, event: BroadcastResourceCacheEvent) => void;
|
|
12
|
+
type RuntimeWindow = Window & typeof globalThis;
|
|
13
|
+
export type BroadcastResourceCache = {
|
|
14
|
+
addListener: (path: string, listener: BroadcastResourceCacheListener) => boolean;
|
|
15
|
+
removeListener: (path: string, listener?: BroadcastResourceCacheListener) => boolean;
|
|
16
|
+
store: (path: string, listener?: BroadcastResourceCacheListener) => boolean;
|
|
17
|
+
release: (path?: string) => boolean;
|
|
18
|
+
change: (path: string, event: BroadcastResourceChange) => void;
|
|
19
|
+
dispose: () => void;
|
|
20
|
+
};
|
|
21
|
+
export declare function createBroadcastResourceCache(target: RuntimeWindow, resolve: (path: string) => URL, configuredStore?: BroadcastResourceStore): BroadcastResourceCache;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { deferRomSoundMarkup } from './romsound-markup';
|
|
2
|
+
type RuntimeWindow = Window & typeof globalThis & Record<string, unknown>;
|
|
3
|
+
export declare function resolveRomSoundUrl(value: unknown): string | null;
|
|
4
|
+
export declare function installRomSoundProtocol(target: RuntimeWindow): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ReceiverSystemIdentity = {
|
|
2
|
+
browsername: string;
|
|
3
|
+
browserversion: string;
|
|
4
|
+
makerid: string;
|
|
5
|
+
modelname: string;
|
|
6
|
+
};
|
|
7
|
+
export type ReceiverSystemInformation = ReceiverSystemIdentity & {
|
|
8
|
+
baseurl: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
/** Additional receiver-owned fields. baseurl is always derived from the VFS mount. */
|
|
12
|
+
export type ReceiverSystemInformationOverrides = Partial<ReceiverSystemIdentity> & Record<string, unknown>;
|
|
13
|
+
export declare const RECEIVER_SYSTEM_IDENTITY: Readonly<ReceiverSystemIdentity>;
|
|
14
|
+
export declare function createReceiverSystemInformation(baseurl: string, overrides?: ReceiverSystemInformationOverrides): ReceiverSystemInformation;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type BroadcastVfsResource = {
|
|
2
|
+
path: string;
|
|
3
|
+
contentType?: string;
|
|
4
|
+
data: Uint8Array | ArrayBuffer;
|
|
5
|
+
};
|
|
6
|
+
export type ServiceWorkerBroadcastVfsOptions = {
|
|
7
|
+
workerUrl: string | URL;
|
|
8
|
+
/** Same-origin scope used to expose broadcast files. */
|
|
9
|
+
baseUrl?: string | URL;
|
|
10
|
+
/** Compatibility fallback for applications which omit a carousel directory. */
|
|
11
|
+
uniqueBasenameFallback?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type BroadcastVfsBackend = {
|
|
14
|
+
begin(): Promise<void>;
|
|
15
|
+
put(resource: BroadcastVfsResource): Promise<void>;
|
|
16
|
+
canRead(path: string): Promise<boolean>;
|
|
17
|
+
};
|
|
18
|
+
export type BroadcastVfsSessionOptions = {
|
|
19
|
+
/** Report background write failures; ensure() still rejects to its caller. */
|
|
20
|
+
onError?: (error: unknown) => void;
|
|
21
|
+
/** Override background scheduling, primarily for embedded hosts and tests. */
|
|
22
|
+
schedule?: (task: () => void) => void;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Ordered, recoverable write session above a VFS backend. enqueue() copies
|
|
26
|
+
* callback-lifetime data synchronously and returns a revision barrier.
|
|
27
|
+
*/
|
|
28
|
+
export declare class BroadcastVfsSession {
|
|
29
|
+
private readonly backend;
|
|
30
|
+
private readonly onError?;
|
|
31
|
+
private readonly scheduleTask;
|
|
32
|
+
private readonly mirror;
|
|
33
|
+
private readonly queue;
|
|
34
|
+
private waiters;
|
|
35
|
+
private generation;
|
|
36
|
+
private nextRevision;
|
|
37
|
+
private completedRevision;
|
|
38
|
+
private drainScheduled;
|
|
39
|
+
private ioTail;
|
|
40
|
+
private sessionReady;
|
|
41
|
+
constructor(backend: BroadcastVfsBackend, options?: BroadcastVfsSessionOptions);
|
|
42
|
+
beginSession(): Promise<void>;
|
|
43
|
+
enqueue(resource: BroadcastVfsResource): number;
|
|
44
|
+
waitFor(revision: number): Promise<void>;
|
|
45
|
+
/** Ensure a staged path is readable, replaying the page-owned mirror if needed. */
|
|
46
|
+
ensure(path: string, revision?: number): Promise<void>;
|
|
47
|
+
private appendIo;
|
|
48
|
+
private scheduleDrain;
|
|
49
|
+
private drainOne;
|
|
50
|
+
private resolveWaiters;
|
|
51
|
+
}
|
|
52
|
+
export declare class ServiceWorkerBroadcastVfs {
|
|
53
|
+
private readonly workerUrl;
|
|
54
|
+
private readonly scopeUrl;
|
|
55
|
+
private readonly uniqueBasenameFallback;
|
|
56
|
+
private registration;
|
|
57
|
+
private ready;
|
|
58
|
+
constructor(options: ServiceWorkerBroadcastVfsOptions);
|
|
59
|
+
initialize(): Promise<ServiceWorkerRegistration>;
|
|
60
|
+
begin(): Promise<void>;
|
|
61
|
+
put(resource: BroadcastVfsResource): Promise<void>;
|
|
62
|
+
canRead(path: string): Promise<boolean>;
|
|
63
|
+
reset(): Promise<void>;
|
|
64
|
+
private request;
|
|
65
|
+
private waitForActivation;
|
|
66
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Android の「放送予定」と番組表連携
|
|
2
|
+
|
|
3
|
+
## Android ファームウェアで確認できた処理
|
|
4
|
+
|
|
5
|
+
「放送予定」は放送 HTML 内のページではなく、受信機が所有する EPG 機能です。
|
|
6
|
+
SMB400 rev24.24 では次の経路になっています。
|
|
7
|
+
|
|
8
|
+
1. `ProgramInfoProvider` がチューナーの `program_info.sqlite3` を検索用 DB へ同期する。
|
|
9
|
+
2. `ProgramInfoOpenHelper` が現在時刻と番組の開始・終了時刻を比較する。
|
|
10
|
+
放送中は `live`、開始前は `future` とし、future の検索タイトルへ
|
|
11
|
+
`[放送予定]` を付ける。
|
|
12
|
+
3. Android TV の検索結果を選ぶと `SearchableProgramInfo` が
|
|
13
|
+
`TvTunerService` を起動し、番組情報と `future` を渡す。
|
|
14
|
+
4. `TvTunerService` は future の場合に `StartMode.Reserve` を選び、別パッケージの
|
|
15
|
+
`jp.pixela.atv_app.MainActivity` を起動する。
|
|
16
|
+
5. その Activity の WebView は次の内蔵ページを開く。
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
file:///android_asset/programList/index.html?ts=...
|
|
20
|
+
#/?program_id=...&broadcast_type=...&service_id=...&event_id=...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
したがって、これは任意の外部 URL を開く機能ではありません。検索結果から受信機所有の
|
|
24
|
+
番組詳細・予約 UI へ移る、明示的なホスト機能です。
|
|
25
|
+
|
|
26
|
+
### future 判定と検索データ
|
|
27
|
+
|
|
28
|
+
`ProgramInfoOpenHelper` の判定は単純な派生状態です。番組時刻は DB 内では秒単位で、
|
|
29
|
+
比較時にミリ秒へ変換されます。
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
now >= start + duration -> 検索結果に入れない
|
|
33
|
+
start <= now < end -> live
|
|
34
|
+
now < start -> future(最大 50 件)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
future の `suggest_text_1` は `[放送予定] 番組名` になります。同じ放送種別、
|
|
38
|
+
service ID、event ID の有効な予約があれば `[予約済]` も追加されます。
|
|
39
|
+
`suggest_intent_extra_data` には番組 JSON と `#future`、live の場合は `#live` が入り、
|
|
40
|
+
クリック後の `TvTunerService` はこの suffix で遷移を分けます。
|
|
41
|
+
|
|
42
|
+
Provider は次の標準 suggestion 列を公開します。
|
|
43
|
+
|
|
44
|
+
- `suggest_text_1` / `suggest_text_2`
|
|
45
|
+
- `suggest_result_card_image`(ジャンル別 320 x 180 画像)
|
|
46
|
+
- `suggest_is_live`
|
|
47
|
+
- `suggest_intent_extra_data`
|
|
48
|
+
- `suggest_intent_data_id`
|
|
49
|
+
|
|
50
|
+
Katniss 側のローカル suggestion 変換では、タイトル、説明、カード画像、intent extra data
|
|
51
|
+
をそのまま読み、`suggest_is_live` 自体では分岐していません。したがって、この機種で
|
|
52
|
+
future を決定している本体は `ProgramInfoOpenHelper` と `#future` の受け側です。
|
|
53
|
+
|
|
54
|
+
また、APK の日本語リソースに存在する原文は `[放送予定]` で、括弧なしの
|
|
55
|
+
`放送予定` という独立した文字列リソースは見つかりません。スクリーンショットの括弧なし
|
|
56
|
+
表示は検索 UI 側のプレゼンテーションであり、放送 HTML やフォントが生成する状態では
|
|
57
|
+
ありません。
|
|
58
|
+
|
|
59
|
+
### EPG の保存と更新
|
|
60
|
+
|
|
61
|
+
検索時に放送波を直接スキャンしているわけではありません。ネイティブチューナーが持つ
|
|
62
|
+
`program_info.sqlite3` の更新時刻を監視し、検索用の `program_info.db` へコピーします。
|
|
63
|
+
検索要求ごとに一時 `suggest_content.db` を作り直し、番組名・説明とチャンネル名を検索します。
|
|
64
|
+
|
|
65
|
+
バックグラウンド更新は起動後 5 分、その後 30 分ごとに判定されます。EPG スキャンを
|
|
66
|
+
実行する JST の時間帯はコード上で次の二つです。
|
|
67
|
+
|
|
68
|
+
- 04:38–07:37
|
|
69
|
+
- 16:38–19:37
|
|
70
|
+
|
|
71
|
+
更新サービスは `StartMode.UpdateEPG` でチューナーを初期化し、EPG cache target `0` を
|
|
72
|
+
更新して最大 120 秒待ちます。録画対応機では録画コンテンツ target `5` と予約 target `6`
|
|
73
|
+
も更新します。テレビアプリが前面へ出た場合、バックグラウンド更新は中止されます。
|
|
74
|
+
|
|
75
|
+
なお、ARIB STD-B62 Volume 2 には `receiverDevice.scheduleToTune()` などの
|
|
76
|
+
視聴・録画予約 API もありますが、上記の Android 検索結果から番組詳細を開く処理とは
|
|
77
|
+
別のインターフェースです。
|
|
78
|
+
|
|
79
|
+
## libaribhtml5 のホストインターフェース
|
|
80
|
+
|
|
81
|
+
プレーヤー側は `AribReceiverHost` の `onOpenProgramGuide` で、WebView または
|
|
82
|
+
ネイティブの番組表へ接続できます。SDK は任意 URL を受け取らず、番組情報だけを渡します。
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const host = new ARIBHTML5.AribReceiverHost({
|
|
86
|
+
iframe,
|
|
87
|
+
viewport,
|
|
88
|
+
onOpenProgramGuide(request) {
|
|
89
|
+
const bridge = window.ARIBNative
|
|
90
|
+
if (!bridge?.openProgramGuide) return false
|
|
91
|
+
|
|
92
|
+
bridge.openProgramGuide(JSON.stringify(request))
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
await host.openProgramGuide({
|
|
97
|
+
destination: 'program-detail',
|
|
98
|
+
state: 'future',
|
|
99
|
+
program: {
|
|
100
|
+
original_network_id: 4,
|
|
101
|
+
tlv_stream_id: 1,
|
|
102
|
+
service_id: 101,
|
|
103
|
+
event_id: 42,
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Android 側では JSON 内の識別子を検証したうえで、自アプリの番組詳細 Activity を開きます。
|
|
109
|
+
URL を JSON からそのままロードしてはいけません。
|
|
110
|
+
|
|
111
|
+
`onOpenProgramGuide` が未設定、`false` を返す、または例外を送出した場合、SDK は
|
|
112
|
+
`false` を返して次の標準メッセージを表示します。
|
|
113
|
+
|
|
114
|
+
- 番組詳細: `このプレーヤーでは放送予定の番組詳細を表示できません。`
|
|
115
|
+
- 番組表: `このプレーヤーでは番組表を表示できません。`
|
|
116
|
+
|
|
117
|
+
独自のダイアログや toast を使う場合は `onProgramGuideUnavailable` を指定します。
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const host = new ARIBHTML5.AribReceiverHost({
|
|
121
|
+
iframe,
|
|
122
|
+
viewport,
|
|
123
|
+
onProgramGuideUnavailable({ request, reason, error }) {
|
|
124
|
+
showPlayerNotice({ request, reason, error })
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
```
|