@oddin-gg/havik-player 1.0.2
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 +15 -0
- package/README.md +300 -0
- package/THIRD_PARTY_NOTICES.txt +59 -0
- package/dist/havik-player.global.js +147 -0
- package/dist/havik-player.global.js.map +1 -0
- package/dist/index.cjs +108 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +795 -0
- package/dist/index.d.ts +795 -0
- package/dist/index.js +1919 -0
- package/dist/index.js.map +1 -0
- package/docs/API.md +1115 -0
- package/docs/STABILITY.md +56 -0
- package/embed/index.html +26 -0
- package/examples/README.md +17 -0
- package/examples/Vue.vue +37 -0
- package/examples/react.tsx +47 -0
- package/examples/vanilla.html +41 -0
- package/package.json +101 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oddin.gg
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# @oddin-gg/havik-player
|
|
2
|
+
|
|
3
|
+
HTML5 player SDK for Oddin live streams — **LL-HLS + DRM** against the
|
|
4
|
+
[havik-streams](https://github.com/oddin-gg/havik-streams) API, in three
|
|
5
|
+
integration modes:
|
|
6
|
+
|
|
7
|
+
| Mode | Entry | You provide | SDK owns |
|
|
8
|
+
| ----------------------------- | ---------------------------- | ---------------------- | -------------------------------------------------- |
|
|
9
|
+
| **A — Managed** | `createPlayer()` | a `<video>` element | hls.js, LL-HLS, DRM/EME, retries |
|
|
10
|
+
| **B — Bring-your-own-player** | `resolveStream()` | the player + `<video>` | auth → catalog → playback resolution + DRM helpers |
|
|
11
|
+
| **C — Iframe embed** | `mountEmbed()` / hosted page | an iframe slot | everything, behind a `postMessage` API |
|
|
12
|
+
|
|
13
|
+
Widevine (Chrome/Firefox/Edge/Android) is fully supported. Safari/iOS plays via
|
|
14
|
+
native passthrough; full FairPlay EME is a tracked fast-follow. See [Limitations](#limitations).
|
|
15
|
+
|
|
16
|
+
> 📖 **Full API reference:** [docs/API.md](docs/API.md) · **Examples** (vanilla / React / Vue): [examples/](examples/) · **API stability & versioning:** [docs/STABILITY.md](docs/STABILITY.md)
|
|
17
|
+
|
|
18
|
+
> ⚠️ **Before you integrate — a server-side prerequisite that is out of your code's hands:**
|
|
19
|
+
> the api-key's **AllowedOrigins** (and, for iframes, **AllowedIframeParents**) **and** the
|
|
20
|
+
> DRM service's **CORS allow-list** must both include every origin you serve the player from,
|
|
21
|
+
> or requests fail their preflight and DRM never starts. Onboard your origins with Oddin
|
|
22
|
+
> first; allow a few minutes for propagation. Never use a `["*"]` allow-list in production.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @oddin-gg/havik-player
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or via CDN (`<script>` / iframe), exposing `window.HavikPlayer`:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<script src="https://cdn.jsdelivr.net/npm/@oddin-gg/havik-player/dist/havik-player.global.js"></script>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
You need two things to play a stream: a **match URN** (`od:match:…`) and a
|
|
39
|
+
**publishable api-key** (`pk_live_…` / `pk_test_…`) whose **AllowedOrigins**
|
|
40
|
+
includes the origin your player runs on. See [Auth & onboarding](#auth--onboarding).
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Mode A — Managed player
|
|
45
|
+
|
|
46
|
+
The SDK owns the `<video>`, bundles hls.js, and wires LL-HLS + Widevine DRM.
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { createPlayer } from '@oddin-gg/havik-player';
|
|
50
|
+
|
|
51
|
+
const player = await createPlayer({
|
|
52
|
+
video: document.querySelector('video')!,
|
|
53
|
+
baseUrl: 'https://streams.oddin.gg',
|
|
54
|
+
matchUrn: 'od:match:1234',
|
|
55
|
+
credential: { apiKey: 'pk_live_…' },
|
|
56
|
+
autoplay: true,
|
|
57
|
+
muted: true, // required for reliable autoplay
|
|
58
|
+
waitForLive: true, // arm on an upcoming match, auto-play at go-live
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
player.on('statechange', (s) => console.log('state', s)); // loading|waiting|playing|buffering|paused|ended|error
|
|
62
|
+
player.on('waiting', (w) => console.log('go-live in', w.retryInMs, 'ms')); // armed countdown
|
|
63
|
+
player.on('stats', (s) => console.log(s)); // dropped frames, latency, bitrate, level
|
|
64
|
+
player.on('error', (e) => console.error(e.code, e.httpStatus, e.message));
|
|
65
|
+
|
|
66
|
+
// later
|
|
67
|
+
player.destroy();
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The managed player handles `425 TOO_EARLY` retries (honoring `Retry-After`),
|
|
71
|
+
buffering recovery, and silent DRM **license-URL refresh** for long sessions.
|
|
72
|
+
|
|
73
|
+
### Controls & skinning
|
|
74
|
+
|
|
75
|
+
Out of the box, Mode A renders a **branded, fully skinnable control bar** — seek,
|
|
76
|
+
play/pause, volume, a live badge + go-live, quality / audio / subtitle menus,
|
|
77
|
+
Picture-in-Picture, fullscreen, buffering + error/retry overlays, auto-hide, and
|
|
78
|
+
keyboard a11y. Re-skin it to match your brand with a `theme` (or by overriding the
|
|
79
|
+
`--havik-*` CSS variables); or opt out with `controls: 'native'` / `'none'`.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
await createPlayer({
|
|
83
|
+
video,
|
|
84
|
+
baseUrl,
|
|
85
|
+
matchUrn,
|
|
86
|
+
credential: { apiKey },
|
|
87
|
+
controls: 'custom', // 'custom' (default, branded bar) | 'native' | 'none'
|
|
88
|
+
theme: { accent: '#14b8a6', surface: '#0f172a' }, // merged over the Oddin defaults
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
See [Controls & theming](docs/API.md#controls--theming) for the full theme/CSS-variable reference.
|
|
93
|
+
|
|
94
|
+
## Mode B — Bring your own player
|
|
95
|
+
|
|
96
|
+
The SDK resolves the stream and gives you the DRM header helpers; you own the
|
|
97
|
+
`<video>` and the playback engine.
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { resolveStream, licenseRequestHeaders, getDeviceId } from '@oddin-gg/havik-player';
|
|
101
|
+
|
|
102
|
+
const cred = { apiKey: 'pk_live_…' };
|
|
103
|
+
const stream = await resolveStream({
|
|
104
|
+
baseUrl: 'https://streams.oddin.gg',
|
|
105
|
+
matchUrn: 'od:match:1234',
|
|
106
|
+
credential: cred,
|
|
107
|
+
waitForLive: true,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// stream = { manifestUrl, drmEnabled, drm: { widevine: { licenseUrl } }, … }
|
|
111
|
+
// Wire into YOUR player. For hls.js, attach the license headers in licenseXhrSetup
|
|
112
|
+
// (NOT xhrSetup — EME license requests route through licenseXhrSetup):
|
|
113
|
+
const headers = licenseRequestHeaders(stream, cred); // { 'x-api-key', 'X-Match-Urn', 'X-Device-Id', 'Content-Type' }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
> **DRM rule:** POST to `drm.widevine.licenseUrl` **verbatim** — its signed query
|
|
117
|
+
> string _is_ the token. Never rewrite/normalize the URL, and use the **same
|
|
118
|
+
> api-key** on playback and license requests or the license 403s.
|
|
119
|
+
|
|
120
|
+
Discovery helpers (there is no push channel — polling only):
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { fetchCatalog, watchStatus } from '@oddin-gg/havik-player';
|
|
124
|
+
|
|
125
|
+
const catalog = await fetchCatalog({ baseUrl, credential: cred }); // tournaments → matches (metadata only)
|
|
126
|
+
const watcher = watchStatus({
|
|
127
|
+
baseUrl,
|
|
128
|
+
matchUrn,
|
|
129
|
+
credential: cred,
|
|
130
|
+
onChange: (m) => console.log(m.status),
|
|
131
|
+
});
|
|
132
|
+
// watcher.stop();
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Mode C — Iframe embed
|
|
136
|
+
|
|
137
|
+
Drop in the hosted player page and control it over `postMessage`:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { mountEmbed } from '@oddin-gg/havik-player';
|
|
141
|
+
|
|
142
|
+
const embed = mountEmbed({
|
|
143
|
+
container: document.querySelector('#player')!,
|
|
144
|
+
src: 'https://player.oddin.gg/embed/', // the hosted embed page
|
|
145
|
+
baseUrl: 'https://streams.oddin.gg',
|
|
146
|
+
matchUrn: 'od:match:1234',
|
|
147
|
+
// apiKey is DEV-ONLY here; in production the hosted page injects it server-side.
|
|
148
|
+
onEvent: (msg) => console.log(msg), // { type: 'oddin:ready' | 'oddin:state' | 'oddin:waiting' | 'oddin:stats' | 'oddin:error' }
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
embed.play();
|
|
152
|
+
embed.setMuted(false);
|
|
153
|
+
// embed.destroy();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Both ends verify `event.origin` on every message. The embed page reads its
|
|
157
|
+
config from `window.HAVIK_EMBED_CONFIG` (server-injected) or the URL query.
|
|
158
|
+
A ready-to-host page is shipped at `embed/index.html`.
|
|
159
|
+
|
|
160
|
+
> **Iframe auth:** the key's **AllowedIframeParents** must include the embedding
|
|
161
|
+
> page's origin — iframe navigations send a `Referer`/`Sec-Fetch-Dest: iframe`,
|
|
162
|
+
> which is what havik-streams matches against (no `Origin` header on a top-level
|
|
163
|
+
> iframe nav).
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Live pickup (`waitForLive`)
|
|
168
|
+
|
|
169
|
+
A live match isn't playable until the stream is actually live. With `waitForLive`,
|
|
170
|
+
the player arms and auto-attaches the instant it goes live — no user action.
|
|
171
|
+
|
|
172
|
+
**By default it does this over a push channel (SSE), not polling.** While the
|
|
173
|
+
live-state stream is connected the player makes **zero** `/v1/playback` requests — it
|
|
174
|
+
waits for the pushed go-live, then resolves once (so it doesn't repeatedly poll while
|
|
175
|
+
waiting for kickoff). If the push channel is unavailable it transparently falls back
|
|
176
|
+
to **polling** `425 TOO_EARLY` + `Retry-After` (scaled ~30s→1s near kickoff, never
|
|
177
|
+
faster than the server asks). Set `liveStateEvents: false` to force polling.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
waitForLive: {
|
|
181
|
+
timeoutMs: 30 * 60_000, // overall arm budget (default: unbounded)
|
|
182
|
+
floorMs: 1000, // min poll interval (default 1000, server minimum)
|
|
183
|
+
ceilMs: 30_000, // cap far-from-kickoff backoff
|
|
184
|
+
onState: (s) => console.log(s.phase, s.retryInMs, s.attempt),
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**End of stream** is detected automatically: when the live stream finishes the player
|
|
189
|
+
stops and fires `ended` — it never sits buffering on a stream that's over. See
|
|
190
|
+
[`subscribeLiveState`](docs/API.md#subscribelivestate) to consume the live-state
|
|
191
|
+
channel directly.
|
|
192
|
+
|
|
193
|
+
## Error handling
|
|
194
|
+
|
|
195
|
+
All API errors are a typed `PlaybackError` with `{ code, httpStatus, retryAfterMs?, requestId? }`:
|
|
196
|
+
|
|
197
|
+
| code | HTTP | meaning | retry? |
|
|
198
|
+
| ---------------------------- | --------- | --------------------------------------------------- | ----------------- |
|
|
199
|
+
| `INVALID_URN` | 400 | malformed URN | no |
|
|
200
|
+
| `NOT_FOUND` | 404 | unknown URN **or** not entitled (indistinguishable) | no |
|
|
201
|
+
| `GONE` | 410 | ended past catchup window | no |
|
|
202
|
+
| `TOO_EARLY` | 425 | upcoming, not live yet | yes (waitForLive) |
|
|
203
|
+
| `UNAVAILABLE` | 503 | should-be-live, origin warming up | yes |
|
|
204
|
+
| `UNAUTHORIZED` / `FORBIDDEN` | 401 / 403 | bad key / origin not allowed / DRM rejected | no |
|
|
205
|
+
| `RATE_LIMITED` | 429 | per-IP limiter | back off |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Auth & onboarding
|
|
210
|
+
|
|
211
|
+
The `x-api-key` is a **publishable** key, by design embeddable in browser JS. Its
|
|
212
|
+
only guardrail is the **server-side per-key allowlist** — so onboarding each
|
|
213
|
+
integrator origin is a hard dependency:
|
|
214
|
+
|
|
215
|
+
1. **havik-streams**: the key's `AllowedOrigins` must include every origin your
|
|
216
|
+
player runs on (and `AllowedIframeParents` for Mode C). Never ship `["*"]` to
|
|
217
|
+
prod — it disables the guardrail.
|
|
218
|
+
2. **havik-drm (`drm-proxy`)**: its `CORS_ALLOWED_ORIGINS` must also include those
|
|
219
|
+
origins, or the cross-origin license POST fails its preflight and DRM never
|
|
220
|
+
starts (silent black video).
|
|
221
|
+
3. Scope the key's entitlements to the tournaments you serve.
|
|
222
|
+
|
|
223
|
+
Revocation isn't instant (≤5min validation cache + ≤24h rotation grace).
|
|
224
|
+
|
|
225
|
+
**Forward-compatible credentials:** `credential` also accepts an async function
|
|
226
|
+
`() => Promise<{ apiKey }>`, so you can later swap in a short-lived-token mint
|
|
227
|
+
service without changing your integration. (No such service exists today.)
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Demo app
|
|
232
|
+
|
|
233
|
+
A full catalog-browser + live-watch + iframe demo lives in `demo/`:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
cp demo/.env.local.example demo/.env.local # set VITE_HAVIK_BASE_URL + VITE_HAVIK_API_KEY
|
|
237
|
+
npm run dev # http://localhost:5173
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The key's `AllowedOrigins` must include `http://localhost:5173`.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Limitations
|
|
245
|
+
|
|
246
|
+
- **FairPlay (Safari/iOS)**: not implemented in v1. Safari uses native HLS
|
|
247
|
+
passthrough, which only plays DRM where the OS already trusts the origins. Full
|
|
248
|
+
FairPlay EME (via a Shaka adapter behind the `PlaybackEngine` seam) is a tracked
|
|
249
|
+
fast-follow.
|
|
250
|
+
- **HLS only** (no DASH); **Widevine + FairPlay** key systems (no PlayReady — Edge
|
|
251
|
+
uses Widevine). Container CMAF/fMP4, encryption cbcs.
|
|
252
|
+
- hls.js is pinned to `1.7.0-beta.1` (the first version that plays this LL-HLS+DRM
|
|
253
|
+
content; 1.6.x has a fatal sourceBuffer bug). Pin to `1.7.0` stable when released.
|
|
254
|
+
|
|
255
|
+
## Privacy
|
|
256
|
+
|
|
257
|
+
The SDK persists a random per-device id in `localStorage` and sends it as
|
|
258
|
+
`X-Device-Id` on every DRM license request (required by the license server). It is a
|
|
259
|
+
stable cross-session identifier — disclose it in your privacy policy and offer a reset
|
|
260
|
+
via [`clearDeviceId()`](docs/API.md#getdeviceid--cleardeviceid). No other personal
|
|
261
|
+
data is collected by the SDK.
|
|
262
|
+
|
|
263
|
+
## Browser & runtime support
|
|
264
|
+
|
|
265
|
+
- **Browser-only.** Importing the package is side-effect-safe (verified in CI), but
|
|
266
|
+
the SDK must be used **client-side** — call `createPlayer`/`mountEmbed` in the
|
|
267
|
+
browser, not during SSR (e.g. dynamic-import it in a Next.js client component).
|
|
268
|
+
- Supported targets: see [`.browserslistrc`](.browserslistrc) (Chrome/Edge ≥94,
|
|
269
|
+
Firefox ≥91, Safari/iOS ≥15). DRM = Widevine on Chrome/Edge/Firefox/Android;
|
|
270
|
+
FairPlay (Safari/iOS) is not yet implemented.
|
|
271
|
+
|
|
272
|
+
## Development
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
npm run build # ESM lib (dist/index.js) + IIFE bundle (dist/havik-player.global.js)
|
|
276
|
+
npm run typecheck
|
|
277
|
+
npm run lint
|
|
278
|
+
npm test # vitest
|
|
279
|
+
npm run test:coverage
|
|
280
|
+
npm run dev # demo app
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Security
|
|
284
|
+
|
|
285
|
+
See [SECURITY.md](SECURITY.md) for the vulnerability-disclosure policy.
|
|
286
|
+
|
|
287
|
+
## License
|
|
288
|
+
|
|
289
|
+
ISC — see [LICENSE](LICENSE).
|
|
290
|
+
|
|
291
|
+
### Third-party licenses
|
|
292
|
+
|
|
293
|
+
This package depends on, and the CDN bundle (`dist/havik-player.global.js`) statically
|
|
294
|
+
embeds, **hls.js** ([Apache-2.0](https://github.com/video-dev/hls.js/blob/master/LICENSE),
|
|
295
|
+
© Dailymotion). Full attribution is in [THIRD_PARTY_NOTICES.txt](THIRD_PARTY_NOTICES.txt),
|
|
296
|
+
which ships with the package and whose attribution is preserved in the bundle banner.
|
|
297
|
+
|
|
298
|
+
DRM uses the browser's built-in EME/CDM; Widevine™ (Google), FairPlay®/AirPlay® (Apple)
|
|
299
|
+
and PlayReady (Microsoft) are trademarks of their respective owners and no CDM is
|
|
300
|
+
distributed with this package.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
THIRD-PARTY SOFTWARE NOTICES AND INFORMATION
|
|
2
|
+
============================================
|
|
3
|
+
|
|
4
|
+
@oddin-gg/havik-player incorporates third-party software. The pre-built browser
|
|
5
|
+
bundle (dist/havik-player.global.js) statically embeds hls.js; the npm package
|
|
6
|
+
declares it as a runtime dependency. The applicable licenses and required
|
|
7
|
+
attributions are reproduced below.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
--------------------------------------------------------------------------------
|
|
11
|
+
hls.js
|
|
12
|
+
--------------------------------------------------------------------------------
|
|
13
|
+
Project: hls.js
|
|
14
|
+
Homepage: https://github.com/video-dev/hls.js
|
|
15
|
+
License: Apache License, Version 2.0
|
|
16
|
+
Full text: http://www.apache.org/licenses/LICENSE-2.0
|
|
17
|
+
|
|
18
|
+
Copyright (c) 2017 Dailymotion (http://www.dailymotion.com)
|
|
19
|
+
|
|
20
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
21
|
+
you may not use this file except in compliance with the License.
|
|
22
|
+
You may obtain a copy of the License at
|
|
23
|
+
|
|
24
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
25
|
+
|
|
26
|
+
Unless required by applicable law or agreed to in writing, software
|
|
27
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
28
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
29
|
+
See the License for the specific language governing permissions and
|
|
30
|
+
limitations under the License.
|
|
31
|
+
|
|
32
|
+
src/remux/mp4-generator.js and src/demux/exp-golomb.ts implementation in this project
|
|
33
|
+
are derived from the HLS library for video.js (https://github.com/videojs/videojs-contrib-hls)
|
|
34
|
+
|
|
35
|
+
That work is also covered by the Apache 2 License, following copyright:
|
|
36
|
+
Copyright (c) 2013-2015 Brightcove
|
|
37
|
+
|
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
39
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
40
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
41
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
42
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
43
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
44
|
+
THE SOFTWARE.
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
--------------------------------------------------------------------------------
|
|
48
|
+
DRM / EME — trademark & licensing notice
|
|
49
|
+
--------------------------------------------------------------------------------
|
|
50
|
+
This SDK uses the browser's built-in Encrypted Media Extensions (EME) and the
|
|
51
|
+
Content Decryption Module (CDM) provided by the user's browser/operating system.
|
|
52
|
+
No DRM client or CDM is distributed with this package.
|
|
53
|
+
|
|
54
|
+
- Widevine™ is a trademark of Google LLC.
|
|
55
|
+
- FairPlay® and AirPlay® are trademarks of Apple Inc.
|
|
56
|
+
- PlayReady is a trademark of Microsoft Corporation.
|
|
57
|
+
|
|
58
|
+
These names are used for identification only. The corresponding CDMs are licensed
|
|
59
|
+
separately by their respective owners and are not provided by Oddin.gg.
|