openvibers/openvibe.examples Commits
go-live reads the slot's WHIP address with the SDK's live.whip.forSlot (OpenRestream-ingested slots too) (#34)
Changes
@@@ -42,7 +42,7 @@ OV_SOURCE=talk.mp4 OV_SECONDS=0 node --env-file=.env go-live.js # a file, un| File | What ||---|---|--| `go-live.js` | `loadConfig()`, `createLive()`, `ensureSlot()`, `whipUrl()`, `ffmpegArgs()`, `waitForSession()`, `goLive()`, CLI |++| `go-live.js` | `loadConfig()`, `createLive()`, `ensureSlot()`, `whipUrl()` (the SDK's `live.whip.forSlot`), `ffmpegArgs()`, `waitForSession()`, `goLive()`, CLI || `test/smoke.test.js` | the whole run against a stand-in for Live's routes and a fake FFmpeg |## Run the smoke test@@@ -62,14 +62,17 @@ async function ensureSlot({ live }, config) {return { slot, created: true };}--/** The slot's WHIP URL (docs: https://openvibe.live/docs/whip#getting-your-whip-url). */--async function whipUrl({ client }, slotId) {-- const profile = await client.json({ service: 'live', audience: 'openvibe.live', path: `/api/streams/managed/${Number(slotId)}/profile` });-- if (!profile.stream_key || !profile.whip_url_base) {-- // A slot OpenRestream ingests publishes there, not to Live's WHIP.-- throw new Error(`slot ${slotId} has no Live WHIP URL${profile.ingest_authority ? ` (its ingest is ${profile.ingest_authority})` : ''}`);++/**++ * The slot's WHIP URL (docs: https://openvibe.live/docs/whip#getting-your-whip-url), from the SDK's live.whip.forSlot:++ * Live's WHIP origin with the slot's key, or OpenRestream's own WHIP URL when OpenRestream ingests the slot.++ */++async function whipUrl({ live }, slotId) {++ try {++ return (await live.whip.forSlot(slotId)).url;++ } catch (err) {++ if (err instanceof TypeError) throw new Error(`slot ${slotId}: ${err.message.replace(/^live\.whip\.forSlot: /, '')}`);++ throw err;}-- return `${String(profile.whip_url_base).replace(/\/+$/, '')}/whip/${profile.stream_key}`;}/**@@@ -35,6 +35,9 @@ async function fakeFetch(url, init = {}) {if (method === 'GET' && u.pathname === '/api/streams/managed/41/profile') {return json(200, { managed_stream: { id: 41, title: 'Robot cam' }, stream_key: KEY, whip_url_base: 'https://whip.openvibe.live', rtmp_url: 'rtmp://openvibe.live:1935/live' });}++ if (method === 'GET' && u.pathname === '/api/streams/managed/43/profile') {++ return json(200, { managed_stream: { id: 43 }, stream_key: null, whip_url: 'https://ingest.openre.stream/whip/orw_example', ingest_authority: 'openre' });++ }if (method === 'GET' && u.pathname === '/api/streams/managed/42/profile') {return json(200, { managed_stream: { id: 42 }, stream_key: null, whip_url_base: null, ingest_authority: 'openre' });}@@@ -80,8 +83,9 @@ function fakeFfmpeg(record) {const sdk = createLive(config, { fetch: fakeFetch });-- // A slot from another ingest has no Live WHIP URL: said plainly.-- await assert.rejects(whipUrl(sdk, 42), /slot 42 has no Live WHIP URL \(its ingest is openre\)/);++ // A slot OpenRestream ingests publishes to OpenRestream's WHIP URL; one with no WHIP address at all says so plainly.++ assert.equal(await whipUrl(sdk, 43), 'https://ingest.openre.stream/whip/orw_example');++ await assert.rejects(whipUrl(sdk, 42), /^Error: slot 42: this slot has no WHIP address/);// The whole run: a new WHIP slot, its WHIP URL, FFmpeg, the session named, the stream ended.const runs = [];
@@ -42,7 +42,7 @@ OV_SOURCE=talk.mp4 OV_SECONDS=0 node --env-file=.env go-live.js # a file, un
@@ -42,7 +42,7 @@ OV_SOURCE=talk.mp4 OV_SECONDS=0 node --env-file=.env go-live.js # a file, un
| File | What |
| File | What |
|---|---|
|---|---|
-| `go-live.js` | `loadConfig()`, `createLive()`, `ensureSlot()`, `whipUrl()`, `ffmpegArgs()`, `waitForSession()`, `goLive()`, CLI |
+| `go-live.js` | `loadConfig()`, `createLive()`, `ensureSlot()`, `whipUrl()` (the SDK's `live.whip.forSlot`), `ffmpegArgs()`, `waitForSession()`, `goLive()`, CLI |
| `test/smoke.test.js` | the whole run against a stand-in for Live's routes and a fake FFmpeg |
| `test/smoke.test.js` | the whole run against a stand-in for Live's routes and a fake FFmpeg |
## Run the smoke test
## Run the smoke test
@@ -62,14 +62,17 @@ async function ensureSlot({ live }, config) {
@@ -62,14 +62,17 @@ async function ensureSlot({ live }, config) {
return { slot, created: true };
return { slot, created: true };
}
}
-/** The slot's WHIP URL (docs: https://openvibe.live/docs/whip#getting-your-whip-url). */
-async function whipUrl({ client }, slotId) {
- const profile = await client.json({ service: 'live', audience: 'openvibe.live', path: `/api/streams/managed/${Number(slotId)}/profile` });
- if (!profile.stream_key || !profile.whip_url_base) {
- // A slot OpenRestream ingests publishes there, not to Live's WHIP.
- throw new Error(`slot ${slotId} has no Live WHIP URL${profile.ingest_authority ? ` (its ingest is ${profile.ingest_authority})` : ''}`);
+/**
+ * The slot's WHIP URL (docs: https://openvibe.live/docs/whip#getting-your-whip-url), from the SDK's live.whip.forSlot:
+ * Live's WHIP origin with the slot's key, or OpenRestream's own WHIP URL when OpenRestream ingests the slot.
+ */
+async function whipUrl({ live }, slotId) {
+ try {
+ return (await live.whip.forSlot(slotId)).url;
+ } catch (err) {
+ if (err instanceof TypeError) throw new Error(`slot ${slotId}: ${err.message.replace(/^live\.whip\.forSlot: /, '')}`);
+ throw err;
}
}
- return `${String(profile.whip_url_base).replace(/\/+$/, '')}/whip/${profile.stream_key}`;
}
}
/**
/**
@@ -35,6 +35,9 @@ async function fakeFetch(url, init = {}) {
@@ -35,6 +35,9 @@ async function fakeFetch(url, init = {}) {
if (method === 'GET' && u.pathname === '/api/streams/managed/41/profile') {
if (method === 'GET' && u.pathname === '/api/streams/managed/41/profile') {
return json(200, { managed_stream: { id: 41, title: 'Robot cam' }, stream_key: KEY, whip_url_base: 'https://whip.openvibe.live', rtmp_url: 'rtmp://openvibe.live:1935/live' });
return json(200, { managed_stream: { id: 41, title: 'Robot cam' }, stream_key: KEY, whip_url_base: 'https://whip.openvibe.live', rtmp_url: 'rtmp://openvibe.live:1935/live' });
}
}
+ if (method === 'GET' && u.pathname === '/api/streams/managed/43/profile') {
+ return json(200, { managed_stream: { id: 43 }, stream_key: null, whip_url: 'https://ingest.openre.stream/whip/orw_example', ingest_authority: 'openre' });
+ }
if (method === 'GET' && u.pathname === '/api/streams/managed/42/profile') {
if (method === 'GET' && u.pathname === '/api/streams/managed/42/profile') {
return json(200, { managed_stream: { id: 42 }, stream_key: null, whip_url_base: null, ingest_authority: 'openre' });
return json(200, { managed_stream: { id: 42 }, stream_key: null, whip_url_base: null, ingest_authority: 'openre' });
}
}
@@ -80,8 +83,9 @@ function fakeFfmpeg(record) {
@@ -80,8 +83,9 @@ function fakeFfmpeg(record) {
const sdk = createLive(config, { fetch: fakeFetch });
const sdk = createLive(config, { fetch: fakeFetch });
- // A slot from another ingest has no Live WHIP URL: said plainly.
- await assert.rejects(whipUrl(sdk, 42), /slot 42 has no Live WHIP URL \(its ingest is openre\)/);
+ // A slot OpenRestream ingests publishes to OpenRestream's WHIP URL; one with no WHIP address at all says so plainly.
+ assert.equal(await whipUrl(sdk, 43), 'https://ingest.openre.stream/whip/orw_example');
+ await assert.rejects(whipUrl(sdk, 42), /^Error: slot 42: this slot has no WHIP address/);
// The whole run: a new WHIP slot, its WHIP URL, FFmpeg, the session named, the stream ended.
// The whole run: a new WHIP slot, its WHIP URL, FFmpeg, the session named, the stream ended.
const runs = [];
const runs = [];