Closed FKholbutayev closed 3 years ago
Hey @FKholbutayev we haven't tried using the player with Nuxt.js before. Can you share sample code or a repository that replicates the issue you're seeing?
@tonyjin I am seeing the same issue as well. Im using the example code from the repro and am just trying to load this component in the next.js page.
import {
create,
isPlayerSupported,
MediaPlayer,
PlayerError,
PlayerEventType,
PlayerState,
Quality,
TextCue,
TextMetadataCue,
} from 'amazon-ivs-player';
/**
* These imports are loaded via the file-loader, and return the path to the asset.
* We use the TypeScript compiler (TSC) to check types; it doesn't know what this WASM module is, so let's ignore the error it throws (TS2307).
*/
// @ts-ignore
import * as wasmBinaryPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm';
import wasmWorkerPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
import React from 'react';
class PlayerDemo {
private player: MediaPlayer;
private videoElement: HTMLVideoElement = document.querySelector('#video-player');
constructor(player: MediaPlayer) {
this.player = player;
player.attachHTMLVideoElement(this.videoElement);
this.attachListeners();
const versionString: HTMLElement = document.querySelector('.version');
versionString.innerText = `Amazon IVS Player version ${player.getVersion()}`;
}
loadAndPlay(stream: string) {
const { player } = this;
/**
* With setAutoplay, we don't need to call play() here to try and start the stream. One of three things will happen:
* - Autoplay with sound
* - Autoplay muted
* - Playback blocked
* If autoplay is muted or blocked, the viewer will need to manually interact with the video player in order to unmute or start playback.
* See https://developers.google.com/web/updates/2017/09/autoplay-policy-changes for more info on autoplaying video and best practices.
* */
player.setAutoplay(true);
player.load(stream);
}
destroy() {
// Event listeners are automatically removed on player destruction
this.player.delete();
}
private attachListeners() {
const { player } = this;
for (let state of Object.values(PlayerState)) {
player.addEventListener(state, () => {
console.log(state);
});
}
player.addEventListener(PlayerEventType.INITIALIZED, () => {
console.log('INITIALIZED');
});
player.addEventListener(PlayerEventType.ERROR, (error: PlayerError) => {
console.error('ERROR', error);
});
player.addEventListener(PlayerEventType.QUALITY_CHANGED, (quality: Quality) => {
console.log('QUALITY_CHANGED', quality);
});
// This event fires when text cues are encountered, such as captions or subtitles
player.addEventListener(PlayerEventType.TEXT_CUE, (cue: TextCue) => {
console.log('TEXT_CUE', cue.startTime, cue.text);
});
// This event fires when embedded Timed Metadata is encountered
player.addEventListener(PlayerEventType.TEXT_METADATA_CUE, (cue: TextMetadataCue) => {
console.log('Timed metadata', cue.text);
});
}
}
// This is the "quiz" stream, which contains Timed Metadata. See the README for more sample streams.
const defaultStream = 'https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8';
const inputEl: HTMLInputElement = document.querySelector('.src-input');
let demo: PlayerDemo;
function setup() {
/**
* The IVS player can only be used in browsers which support WebAssembly.
* You should use `isPlayerSupported` before calling `create`.
* Otherwise, wrap `create` in a `try/catch` block, because an error will be thrown in browsers without WebAssembly support.
*/
if (isPlayerSupported) {
setupForm();
setupPlayer();
} else {
console.error('IVS Player is not supported in this browser');
}
}
function setupPlayer() {
const createAbsolutePath = (assetPath: string) => new URL(assetPath, document.URL).toString();
const player = create({
wasmWorker: createAbsolutePath(wasmWorkerPath),
wasmBinary: createAbsolutePath(wasmBinaryPath),
});
demo = new PlayerDemo(player);
loadFormStream();
/**
* Add the demo and player to the window so that you can play around with them in the console.
* This is not necessary for production.
* */
// @ts-ignore
window.demo = demo;
// @ts-ignore
window.player = demo.player;
}
function setupForm() {
// Set the stream to load using the `playbackUrl=` query param
const params = new URLSearchParams(window.location.search);
const streamParam = params.get('playbackUrl');
if (streamParam) {
inputEl.value = streamParam;
}
const formEl = document.querySelector('.src-container-direct');
formEl.addEventListener('submit', (event) => {
event.preventDefault();
loadFormStream();
})
}
function loadFormStream() {
demo.loadAndPlay(inputEl.value || defaultStream);
}
export class LivePlayer extends React.Component {
componentDidMount() {
setup();
}
render() {
return (
<div className="demo">
<div className="video-container">
<form className="src-container-direct">
<input className="src-input" placeholder="Enter IVS .m3u8" />
<button className="src-submit" type="submit">Load</button>
</form>
<video id="video-player" playsinline controls></video>
<div className='version'></div>
</div>
</div>
);
}
}
@dwhiz thanks for sharing the snippet, we'll take a look. To double check, you're seeing problems using Next.js right? The original poster mentioned they were using Nuxt.js.
@tonyjin Yes I meant next.js, but I am getting the exact same error when trying to import the wasm module.
@tonyjin I think it as something do with the way the wasm file is compiled. I tried nextjs example project and loaded the add.wasm with no issue. https://github.com/vercel/next.js/tree/canary/examples/with-webassembly
I am having the same issue and am also working in next.js.
I also tired the web assembly next.js example and tried adding the 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js' file in place of the example and it wouldn't load.
In the meantime I have made a workaround using the alternative implementation (Setup With Script Tag) mentioned in https://docs.aws.amazon.com/ivs/latest/userguide/SWPG.html. But as next.js is react based, loading the script tag isn't as direct as including it in your html.. So here is my component in case it helps anyone till this issue is closed. I am having trouble creating multiple streams using this method though so keep that in mind and let me know if you have any idea why.
import React,{Component} from 'react'
class Stream extends Component{
constructor(props){
super(props)
this.ref = React.createRef()
}
componentDidMount(){
let script = document.createElement('script');
script.onload = function(){
if (IVSPlayer.isPlayerSupported) {
const player = IVSPlayer.create();
player.attachHTMLVideoElement(document.getElementById('video-player'));
player.load("https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8");
player.play();
}
}
script.src = "https://player.live-video.net/1.0.0/amazon-ivs-player.min.js";
const node = this.ref.current
node.appendChild(script);
}
render(){
return (
<div ref={this.ref}>
Stream!
<div className="demo">
<div className="video-container">
<form className="src-container-direct">
<input className="src-input" placeholder="Enter IVS .m3u8"/>
<button className="src-submit" type="submit">Load</button>
</form>
<video id="video-player" playsInline controls></video>
<div className='version'></div>
</div>
</div>
</div>
)
}
}
export default Stream
Thanks for sharing the workaround! We've reproduced this issue internally and are working on a fix.
@tonyjin sorry for not replying earlier I was not working these days. I see other developers had similar issue. Nevertheless here the snippet of my code.
import Vue from 'vue'
import videojs from 'video.js';
import {
VideoJSQualityPlugin,
VideoJSIVSTech,
registerIVSQualityPlugin,
registerIVSTech,
VideoJSEvents,
} from 'amazon-ivs-player';
import wasmWorkerPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
// @ts-ignore
import wasmBinaryPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm';
export default Vue.extend({
methods: {
createAbsolutePath: function(assetPath:string) {
return new URL(assetPath, document.URL).toString();
}
},
created() {
registerIVSTech(videojs, {
wasmWorker: this.createAbsolutePath(wasmWorkerPath),
wasmBinary: this.createAbsolutePath(wasmBinaryPath)
});
registerIVSQualityPlugin(videojs);
const player = videojs('videojs-player', {
techOrder: ["AmazonIVS"],
autoplay: true
}, function() {
console.warn('Player is ready to use')
}) as videojs.Player & VideoJSIVSTech & VideoJSQualityPlugin;
player.enableIVSQualityPlugin();
const events: VideoJSEvents = player.getIVSEvents();
const ivsPlayer = player.getIVSPlayer();
ivsPlayer.addEventListener(events.PlayerState.PLAYING, () => { console.log('IVS Player is playing') });
const defaultStream = PLAYBACK_URL;
player.src(defaultStream);
}
})
Hi, I'm getting the same issue with React.js (SPA). I found out wasm files are not bundled at build. So, I did as follows:
yarn eject
to make the configuration file editablewebpack.config.js
, as sample{
/**
* Developers packaging the IVS player into an app are required to resolve and import the following assets via URL:
*
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
* 'amazon-ivs-player/dist/assets/amazon-ivs-worker.min.js';
*
* These assets must not be re-compiled during packaging.
* The webpack file-loader (https://webpack.js.org/loaders/file-loader/) accomplishes this.
* Rollup's plugin-url (https://github.com/rollup/plugins/tree/master/packages/url) also seems to do this, but has not been tested.
*/
test: /[\/\\]amazon-ivs-player[\/\\].*dist[\/\\]assets[\/\\]/,
loader: 'file-loader',
type: 'javascript/auto',
options: {
name: '[name].[ext]',
},
}
AmazonIVS
componentimport {
registerIVSQualityPlugin,
registerIVSTech,
VideoJSEvents,
VideoJSIVSTech,
VideoJSQualityPlugin,
} from 'amazon-ivs-player';
import React, { useEffect, useRef } from 'react';
import videojs from 'video.js';
// Styles
import 'video.js/dist/video-js.css';
/**
* These imports are loaded via the file-loader, and return the path to the asset.
* We use the TypeScript compiler (TSC) to check types; it doesn't know what this WASM module is, so let's ignore the error it throws (TS2307).
*/
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import wasmBinaryPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm';
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import wasmWorkerPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
export type AmazonIVSOptions = {
stream: string;
};
function AmazonIVS(options: AmazonIVSOptions) {
const createAbsolutePath = (assetPath: string) =>
new URL(assetPath, document.URL).toString();
const videoEl = useRef<HTMLVideoElement>(null);
useEffect(() => {
registerIVSTech(videojs, {
wasmWorker: createAbsolutePath(wasmWorkerPath),
wasmBinary: createAbsolutePath(wasmBinaryPath),
});
// register the quality plugin
registerIVSQualityPlugin(videojs);
// create the player with the appropriate types. We're using @types/video.js VideoJsPlayer, and intersecting our Player and Quality Plugin interface
const player = videojs(
'videojs-player',
{
techOrder: ['AmazonIVS'],
autoplay: true,
},
function () {
console.warn('Player is ready to use');
},
) as videojs.Player & VideoJSIVSTech & VideoJSQualityPlugin;
player.enableIVSQualityPlugin();
// listen to IVS specific events
const events: VideoJSEvents = player.getIVSEvents();
const ivsPlayer = player.getIVSPlayer();
ivsPlayer.addEventListener(events.PlayerState.PLAYING, () => {
console.log('IVS Player is playing');
});
player.src(
'https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8',
);
}, []);
return (
<video
id="videojs-player"
ref={videoEl}
playsInline
autoPlay
height={300}
controls
/>
);
}
export default AmazonIVS;
yarn start
n._emscripten_get_callstack_js is not a function
Error occueredhttps://github.com/cm-wada-yusuke/amazon-ivs-react-ts-sample
Thanks for the reports everyone. I just want to re-emphasize that our assets must not be transpiled by any build tool. We show how to to do that with Webpack's file loader in the sample webpack config.
As an example of what @johnBartos is calling out if you add this next.config.js
(or add the relevant pieces to your existing config) you'll get past these errors. However even with this configuration you'll need to be sure that components using the IVS web player are not loaded during server side rendering (it looks like one way to do that would be with dynamic imports).
next.config.js
module.exports = {
webpack(config) {
config.module.rules.push({
/**
* Developers packaging the IVS player into an app are required to resolve and import the following assets via URL:
*
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
* 'amazon-ivs-player/dist/assets/amazon-ivs-worker.min.js';
*
* These assets must not be re-compiled during packaging.
* The webpack file-loader (https://webpack.js.org/loaders/file-loader/) accomplishes this.
* Rollup's plugin-url (https://github.com/rollup/plugins/tree/master/packages/url) also seems to do this, but has not been tested.
*/
test: /[\/\\]amazon-ivs-player[\/\\].*dist[\/\\]assets[\/\\]/,
loader: 'file-loader',
type: 'javascript/auto',
options: {
name: '[name].[ext]',
outputPath: 'static/ivs-player',
publicPath: '/_next/static/ivs-player'
}
})
return config
},
}
I'll note internally that in future versions we should eliminate the hard dependency on browsers during import of the IVS player.
@FKholbutayev it looks like you should be able to use a similar setup just using nuxt.config.js
instead of next.config.js
. I believe you will also need to make the component that uses IVS load async to avoid Server Side Rendering similar to Next.js.
Can somone tell me how to make this work with rails / react and webpacker (not plain webpack)? Really frustrating to get it working, when I try to add the webpack rule it looks like it's not working, I only get:
ERROR in ./node_modules/amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm
WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
@h0jeZvgoxFepBQ2C Thanks for the report, sorry to hear it's frustrating. I'm not familiar with webpacker, but what you need to do is load the WASM files "untouched" by webpack. So the same as you would for static assets like images. In webpack you'd use the file loader. Have you tried copying our file-loader example into webpacker? https://github.com/rails/webpacker/blob/master/docs/webpack.md#loaders
Unfortunately it really doesn't work out. Right now I don't get any errors anymore, but the player doesn't show anything (no UI elements, no video) - but unfortunately I don't get any errors at all :(
I did following:
1) Added .wasm
in config/webpacker.yml
under extensions
extensions:
- .jsx
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
- .wasm
2) Added the loader in my config/webpack/environment.js
const { environment } = require('@rails/webpacker')
environment.loaders.append('amazon-ivs-player', {
// Developers packaging the IVS player into an app are required to resolve and import the following assets via URL:
//
// 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
// 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
// 'amazon-ivs-player/dist/assets/amazon-ivs-worker.min.js';
//
// These assets must not be re-compiled during packaging.
// The webpack file-loader (https://webpack.js.org/loaders/file-loader/) accomplishes this.
// Rollup's plugin-url (https://github.com/rollup/plugins/tree/master/packages/url) also seems to do this, but has not been tested.
test: /[\/\\]amazon-ivs-player[\/\\].*dist[\/\\]assets[\/\\]/,
loader: 'file-loader',
type: 'javascript/auto',
options: {
name: '[name].[ext]',
// tried also with following:
// outputPath: 'static/ivs-player',
// publicPath: '/_next/static/ivs-player'
},
})
module.exports = environment
3) Add code to my jsx files:
// THIS IS NOT WORKING, DONT COPY PASTE
import React, { useEffect, useRef, useState } from 'react';
import videojs from 'video.js';
import 'video.js/dist/video-js.css'
import {
VideoJSQualityPlugin,
VideoJSIVSTech,
registerIVSQualityPlugin,
registerIVSTech,
VideoJSEvents,
} from 'amazon-ivs-player';
import wasmWorkerPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js'
import wasmBinaryPath from 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
const createAbsolutePath = (assetPath) => new URL(assetPath, document.URL).toString();
registerIVSTech(videojs, {
wasmWorker: createAbsolutePath(wasmWorkerPath),
wasmBinary: createAbsolutePath(wasmBinaryPath),
});
// register the quality plugin
registerIVSQualityPlugin(videojs)
export default function AmazonIvsPlayer({videoUrl,...props }) {
let player = null;
useEffect(() => {
player = videojs('amazon-ivs-videojs', {
techOrder: ["AmazonIVS"],
options: {
wasmWorker: createAbsolutePath(wasmWorkerPath),
wasmBinary: createAbsolutePath(wasmBinaryPath),
},
src: videoUrl
}, () => {
// ready callback is never called also (so this line wont be reached)
player.enableIVSQualityPlugin();
});
// if you console.log(player) here, it says player is null?!?
} catch(e) {
console.error("handled exception", e)
}
}, []}
return (
<div className="video-container">
<video id="amazon-ivs-videojs" className="video-js vjs-4-3 vjs-big-play-centered" controls autoPlay playsInline></video>
</div>
)
}
I tried multiple things (also move the register*Plugin
and createAbsolutePath
methods into the function), but none of them worked, showed errors.. This configuration looks like the best one - but doesn't work :(
Thanks for sharing the workaround! We've reproduced this issue internally and are working on a fix.
Has there been headway made on this? I am seeing this when I don't include the web assembly files included in the distribution:
Couldn't make the player TypeError: Cannot read property 'asmWorker' of undefined
at Se (index.js:6)
at Video.js:87
at commitHookEffectListMount (react-dom.development.js:19732)
at commitPassiveHookEffects (react-dom.development.js:19770)
at HTMLUnknownElement.callCallback (react-dom.development.js:189)
at Object.invokeGuardedCallbackDev (react-dom.development.js:238)
at invokeGuardedCallback (react-dom.development.js:293)
at flushPassiveEffectsImpl (react-dom.development.js:22854)
at unstable_runWithPriority (scheduler.development.js:653)
at runWithPriority$1 (react-dom.development.js:11040)
at flushPassiveEffects (react-dom.development.js:22821)
at react-dom.development.js:22700
at workLoop (scheduler.development.js:597)
at flushWork (scheduler.development.js:552)
at MessagePort.performWorkUntilDeadline (scheduler.development.js:164)
I am using Gatsby. I tried @boushley 's solution but within my gatsby.config
file. Why does create
need the paths to amazon-ivs-wasmworker.min.js'
and amazon-ivs-wasmworker.min.wasm
? It's unclear from the docs that this is necessary although I see it in the web snippet, which, while helpful, became more esoteric as I tried to apply the same method used but in a React environment.
Yeah it would be much easier if these files come bundled :/
@rahul-nath
Can you post your code where you instantiate the player? From what I can tell, that error is thrown when you call create
with no arguments (which is incorrect)
Why does create need the paths to amazon-ivs-wasmworker.min.js' and amazon-ivs-wasmworker.min.wasm?
Because those files are the player. They are split into separate bundles because browsers require workers to be instantiated via URLs.
@h0jeZvgoxFepBQ2C
Yeah it would be much easier if these files come bundled :/
Unfortunately this is the reality of using WebAssembly. The WASM file needs to be in a separate file because it's instantiated via URL. We are exploring how we can make this easier, but we have no timeline right now.
Ok, I managed it now make the paths available with the file-loader... But it doesn't work, no errors, just the black video player screen (no UI) :(
@johnBartos This is what I have towards loading them with webpack.
exports.onCreateWebpackConfig = ({ actions, loaders, getConfig }) => q{
const config = getConfig()
config.module.rules = [
// Omit the default rule where test === '\.jsx?$'
...config.module.rules.filter(
rule => String(rule.test) !== String(/\.jsx?$/)
),{
/**
* Developers packaging the IVS player into an app are required to resolve and import the following assets via URL:
*
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
* 'amazon-ivs-player/dist/assets/amazon-ivs-worker.min.js';
*
* These assets must not be re-compiled during packaging.
* The webpack file-loader (https://webpack.js.org/loaders/file-loader/) accomplishes this.
* Rollup's plugin-url (https://github.com/rollup/plugins/tree/master/packages/url) also seems to do this, but has not been tested.
*/
test: /[\/\\]amazon-ivs-player[\/\\].*dist[\/\\]assets[\/\\]/,
loader: 'file-loader',
type: 'javascript/auto',
options: {
name: '[name].[ext]',
outputPath: 'static/ivs-player',
publicPath: '/_next/static/ivs-player'
}
}
]
// This will completely replace the webpack config with the modified object.
actions.replaceWebpackConfig(config)
}
It is in a file known as gatsby-node.js
, which can be read about here if it helps.
As for the player, I have a React component set up like so:
import React, { useState, useEffect } from "react"
import {
create,
isPlayerSupported,
MediaPlayer,
PlayerError,
PlayerEventType,
PlayerState,
Quality,
TextCue,
TextMetadataCue,
} from 'amazon-ivs-player'
// what is going on here
/**
const videoJsOptions = {
autoplay: true,
controls: true,
sources: [{
src: '/path/to/video.mp4',
type: 'video/mp4'
}]
}
return <VideoPlayer { ...videoJsOptions } />
*/
const defaultURL = "https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8"
const VideoPlayer = ({ src, wasmBinaryPath, wasmWorkerPath }) => {
const [player, setPlayer] = useState()
const [url, setURL] = useState()
const attachListenersAndPlay = () => {
if(!player) return
for (let state of Object.values(PlayerState)) {
player.addEventListener(state, () => {
console.log(state);
});
}
player.addEventListener(PlayerEventType.INITIALIZED, () => {
console.log('INITIALIZED');
});
player.addEventListener(PlayerEventType.ERROR, (error) => {
console.error('ERROR', error);
});
player.addEventListener(PlayerEventType.QUALITY_CHANGED, (quality) => {
console.log('QUALITY_CHANGED', quality);
});
// This event fires when text cues are encountered, such as captions or subtitles
player.addEventListener(PlayerEventType.TEXT_CUE, (cue) => {
console.log('TEXT_CUE', cue.startTime, cue.text);
});
// This event fires when embedded Timed Metadata is encountered
player.addEventListener(PlayerEventType.TEXT_METADATA_CUE, (cue) => {
console.log('Timed metadata', cue.text);
});
console.log("this is the url")
player.setAutoplay(true)
player.load(url)
}
useEffect(attachListenersAndPlay, [player])
useEffect(() => {
/**
* The IVS player can only be used in browsers which support WebAssembly.
* You should use `isPlayerSupported` before calling `create`.
* Otherwise, wrap `create` in a `try/catch` block, because an error will be thrown in browsers without WebAssembly support.
*/
src ? setURL(src) : setURL(defaultURL)
let ivsPlayer
if (isPlayerSupported) {
try {
ivsPlayer = create();
setPlayer(ivsPlayer)
} catch (e) {
console.log("Couldn't make the player", e)
}
// const createAbsolutePath = (assetPath) => new URL(assetPath, document.URL).toString();
// {
// wasmWorker: createAbsolutePath('amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js'),
// wasmBinary: createAbsolutePath('amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'),
// }
} else {
console.error('IVS Player is not supported in this browser');
}
return ivsPlayer && ivsPlayer.delete()
}, [src])
return (
<video id="video-player" playsInline controls></video>
)
}
export default VideoPlayer
Thanks for the reports everyone. I just want to re-emphasize that our assets must not be transpiled by any build tool. We show how to to do that with Webpack's file loader in the sample webpack config.
I'm fairly new to the details of Webpack. It seems the only way to load the wasm is transpiling it because Gatsby and other SSGs and other SSR-like What to do then?
The errors I see are as so:
ERROR #98124 WEBPACK
Generating development JavaScript bundle failed
Can't resolve 'a' in '/Users/me/written_things/work/InHouseLive/inhouselive/node_modules/amazon-ivs-player/dist/assets'
Perhaps you need to install the package 'a'?
File: node_modules/amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm
ERROR #98123 WEBPACK
Generating development JavaScript bundle failed
WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async splitpoint (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
* multi ./node_modules/event-source-polyfill/src/eventsource.js (webpack)-hot-middleware/client.js?path=/__webpack_hmr&reload=true&overlay=false ./.cache/app --> ./.cache/app.js --> ./.cache/sync-requires.js --> ./src/pages/app.js --> ./src/templates/Livestream.js --> ./node_modules/amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm
File: node_modules/amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm
failed Building development bundle - 26.002s
Ok, I managed it now make the paths available with the file-loader... But it doesn't work, no errors, just the black video player screen (no UI) :(
Exactly where I'm at now. The player is stuck on "pause" when player.isPaused()
is called.
@johnBartos is there any debug flag which we can activate to output something helpfull?
@h0jeZvgoxFepBQ2C @rahul-nath Is there anything logged in the console? Let me check that the test streams are working.
The test stream https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.DmumNckWFTqz.m3u8
works on my end.
It seems the only way to load the wasm is transpiling it because Gatsby and other SSGs and other SSR-like What to do then?
SSR libraries needs to be told to ignore the wasm files. For now you also need to ignore the JS files. We are currently working on a fix so that you shouldn't need to exclude JS files in the future.
@johnBartos Unfortunately there is not a single log entry... I can access the passed wasm + js path in my browser, so the passed URLs should be correct. Also they are not transpiled on my setup and included with the webpack-file-loader, so it should be fine 🤔
I couldn't get it running, only with following workaround it works: https://github.com/cm-wada-yusuke/amazon-ivs-react-js-sample/blob/master/src/AmazonIVSWorkaround.js
@h0jeZvgoxFepBQ2C That's our script tag build, which automatically sets up the WASM worker. It can do that because we host the wasm files ourselves. When building from NPM, you need to virtually "host" the wasm files via the file-loader.
Can you post a full page screenshot of your page which includes the console? I am not sure what our next steps are given that there are no logs or errors to dig into.
@h0jeZvgoxFepBQ2C Also, please call player.setLogLevel('debug')
to enable debug logging. Call this after instantiation, but before load.
I am having similar issues. Basically I have trouble getting a combination of IVS with VideoJS implementation to work with React.
My app crashes at this line:
import { registerIVSTech } from 'amazon-ivs-player';
I get (truncated error string):
webpack:///./node_modules/amazon-ivs-player/dist/index.js?:6
module.exports=function(e){var t={};function i(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=25)}([function(e,t){e.exports=__w
ReferenceError: navigator is not defined
at Object.eval (webpack:///./node_modules/amazon-ivs-player/dist/index.js?:6:2473)
I followed the documentation in AWS here but can't even seem to be able to import the library...? What am I missing?
Man this player is really a pain to implement.. We solved the wasm not found error by configuring webpacker correctly and setting mime types in nginx.. And then it works, but only in browsers != chrome || OS != windows.
If you open the developer console, it works fine. But with closed developer tools the browser just does nothing, but eats up more and more ram, until it freezes completely. This has been reliably reproduced with 4 colleagues. I really don't know what to do anymore, the logs don't show anything related. It also works when connecting over lan to a local machine, but after deployed to a server it only shows the mentioned behaviour. I've never spent so much time to implement a player, wth.. :(
Hey folks, thanks for the feedback. We'll work on creating a basic example with React & video.js.
@h0jeZvgoxFepBQ2C and @veromarchand do you mind opening separate issues with sample code (ideally a GitHub repository we can clone) so we can try to reproduce on our end?
Edit - the player should work on Chrome and Windows, but I understand it can be tricky to load the assets properly.
The file-loader
way can be tricky for those who are not webpack pro, or with an already complicated webpack configuration.
I ended up hosting these assets as static file. Maybe one can also load them from CDN.
Our player assets are also hosted on Cloudfront, you can see where to find them here: https://docs.aws.amazon.com/ivs/latest/userguide/IVSPRN.html#jul1520.
https://codepen.io/amazon-ivs/pen/c3b13a2df34b60ada7756f3a2af8d2f0 Here's our codepen showing how to load the player from our CDN.
use next.js encounter the same problem
Attempted import error: 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm' does not contain a default export (imported as 'wasmBinaryPath').
Hey @yeukfei02 do you mind filing a new issue with details about your setup? This issue is becoming a bit overloaded and I'm going to close it out.
For others in this issue, we plan to look into a way to include the player via NPM, but have it use static assets hosted by IVS. We expect that will provide an easier way to integrate the player via NPM while keeping the current method for advanced use cases.
I found an easy and straight forward way to use Amazon IVS with video.js tech script for react projects in this repository:- https://github.com/anoop4bhat/UGCAppRepo/tree/main/web-ui
I am using create-react-app for my project setup and found it easier to append the base IVS and IVS-videojs-tech scripts using javascript rather than trying to use complicated WASM file module loader implementations. The base URLs for both the scripts can be found in index.html file added in the above repo:- https://github.com/anoop4bhat/UGCAppRepo/blob/main/web-ui/public/index.html
This might not be good approach for everyone but hope it helps some of you.
I am trying to integrate amazon-ivs-player into nuxt project. Followed along sample code into nuxt project however getting this issue.
- a in ./node_modules/amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm friendly-errors 16:57:06
issue with detail
Were you ever able to resolve this? I'm currently getting the same issue with a nuxt.js app...
[nitro] [dev] [unhandledRejection] { 18:43:43
message: 'WebAssembly support is required for AmazonIVS tech',
code: 2
}
I know this is an old thread but combining some answers above led me to a solution for a NextJS Application.
First create a script tag in RootLayout with src="https://player.live-video.net/1.22.0/amazon-ivs-player.min.js"
import Script from "next/script";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<Script src="https://player.live-video.net/1.22.0/amazon-ivs-player.min.js" />
<body className={inter.className}>
{{Other code....}}
</body>
</html>
)
My next.config.js file:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
nextScriptWorkers: true,
},
webpack(config) {
config.experiments = {
asyncWebAssembly: true,
layers: true,
};
config.module.rules.push({
/**
* Developers packaging the IVS player into an app are required to resolve and import the following assets via URL:
*
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm'
* 'amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js';
* 'amazon-ivs-player/dist/assets/amazon-ivs-worker.min.js';
*
* These assets must not be re-compiled during packaging.
* The webpack file-loader (https://webpack.js.org/loaders/file-loader/) accomplishes this.
* Rollup's plugin-url (https://github.com/rollup/plugins/tree/master/packages/url) also seems to do this, but has not been tested.
*/
test: /[\/\\]amazon-ivs-player[\/\\].*dist[\/\\]assets[\/\\]/,
loader: "file-loader",
type: "javascript/auto",
options: {
name: "[name].[ext]",
outputPath: "static/ivs-player",
publicPath: "/_next/static/ivs-player",
},
});
return config;
},
};
module.exports = nextConfig;
My VideoFrame code that then takes in the playback url and now I'm able to see the stream that is live if created:
import React, { useRef, useEffect } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";
import {
VideoJSQualityPlugin,
VideoJSIVSTech,
registerIVSQualityPlugin,
registerIVSTech,
VideoJSEvents,
} from "amazon-ivs-player";
import "video.js/dist/video-js.css";
/**
* These imports are loaded via the file-loader, and return the path to the asset.
* We use the TypeScript compiler (TSC) to check types; it doesn't know what this WASM module is, so let's ignore the error it throws (TS2307).
*/
// @ts-ignore
import wasmBinaryPath from "amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.wasm";
// @ts-ignore
import wasmWorkerPath from "amazon-ivs-player/dist/assets/amazon-ivs-wasmworker.min.js";
export type AmazonIVSOptions = {
stream: string;
};
const VideoFrame: React.FC<any> = () => {
var playbackURL =
"{YOUR_PLAYBACK_URL}";
const createAbsolutePath = (assetPath: string) =>
new URL(assetPath, document.URL).toString();
useEffect(() => {
registerIVSTech(videojs, {
wasmWorker: createAbsolutePath(wasmWorkerPath),
wasmBinary: createAbsolutePath(wasmBinaryPath),
});
// register the quality plugin
registerIVSQualityPlugin(videojs);
const player = videojs(
"video-js-amazon-IVS",
{
techOrder: ["AmazonIVS"],
autoplay: true,
},
() => {
console.log("player is ready");
player.src(playbackURL);
player.play();
}
);
return () => {
player.dispose();
};
}, [playbackURL]);
return (
<div data-vjs-player>
<video id="video-js-amazon-IVS" className="video-js" />
</div>
);
};
export default VideoFrame;
Dev Dependencies:
"devDependencies": {
"@builder.io/partytown": "^0.8.1",
"@types/qs": "^6.9.8",
"file-loader": "^6.2.0",
"video.js": "^8.6.1"
}
and obviously "amazon-ivs-player": "^1.22.0" within a dependency.
Let me know if this works for any one in the future!
@brendanfurtado Thanks for providing this!
@brendanfurtado I'm trying out the implementation you are provided. It gets the player working, However, I'm facing an issue that the IVS player opened threads are not closed when disposing the player. So whenever the player is rendered a new worker thread for the IVS player is opened. Accumulating web worker threads causing a memory leak. Are you facing the same issue ?
I am trying to integrate amazon-ivs-player into nuxt project. Followed along sample code into nuxt project however getting this issue.