├── .gitignore
├── demo
└── index.html
├── .github
└── workflows
│ └── publish.yml
├── webpack.config.js
├── package.json
├── README.md
└── src
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WHEP Video Component Demo
7 |
12 |
13 |
14 |
18 |
19 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 |
11 | steps:
12 | - uses: actions/checkout@v1
13 | - uses: actions/setup-node@v1
14 | with:
15 | node-version: 16
16 | registry-url: https://registry.npmjs.org/
17 | - run: |
18 | npm ci
19 | npm run build
20 | npm publish --access public
21 | env:
22 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
23 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const package = require('./package.json');
4 | const webpack = require('webpack');
5 |
6 | module.exports = {
7 | mode: 'production',
8 | entry: './src/index.js',
9 | output: {
10 | library: 'whepvideo.component',
11 | libraryExport: 'default',
12 | libraryTarget: 'umd',
13 | filename: 'whep-video.component.js',
14 | path: path.resolve(__dirname, 'dist'),
15 | },
16 | plugins: [
17 | new HtmlWebpackPlugin({
18 | title: package.version,
19 | template: './demo/index.html',
20 | inject: 'body',
21 | scriptLoading: 'blocking'
22 | }),
23 | // disable dynamic imports, it doesn't work with the umd output
24 | new webpack.optimize.LimitChunkCountPlugin({
25 | maxChunks: 1,
26 | }),
27 | ],
28 | devtool: 'source-map',
29 | devServer: {
30 | static: path.resolve(__dirname, 'dist'),
31 | compress: true,
32 | port: 1337,
33 | host: '0.0.0.0',
34 | },
35 | stats: {
36 | warningsFilter: [/Failed to parse source map/],
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@eyevinn/whep-video-component",
3 | "version": "0.1.0",
4 | "description": "WHEP video web-component",
5 | "main": "dist/whep-video.component.js",
6 | "scripts": {
7 | "build": "rm -rf dist/ && webpack --config webpack.config.js",
8 | "dev": "webpack-dev-server --hot",
9 | "postversion": "git push && git push --tags",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "files": [
13 | "dist"
14 | ],
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/Eyevinn/whep-video-component.git"
18 | },
19 | "keywords": [
20 | "WHEP"
21 | ],
22 | "author": "Eyevinn Technology AB ",
23 | "license": "MIT",
24 | "bugs": {
25 | "url": "https://github.com/Eyevinn/whep-video-component/issues"
26 | },
27 | "homepage": "https://github.com/Eyevinn/whep-video-component#readme",
28 | "dependencies": {
29 | "@eyevinn/webrtc-player": "^0.12.0"
30 | },
31 | "devDependencies": {
32 | "html-webpack-plugin": "^5.5.0",
33 | "webpack": "^5.74.0",
34 | "webpack-cli": "^4.10.0",
35 | "webpack-dev-server": "^4.11.1"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ``
2 |
3 | [](https://opensource.org/licenses/MIT) [](http://slack.streamingtech.se)
4 |
5 | A web component for [WHEP](https://eyevinntechnology.medium.com/standardized-webrtc-based-broadcast-streaming-is-being-recognized-by-the-industry-fbc24df54cf4) WebRTC video playback.
6 |
7 | ## Example
8 |
9 | ```html
10 |
11 |
12 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ```
24 |
25 | # Support
26 |
27 | Join our [community on Slack](http://slack.streamingtech.se) where you can post any questions regarding any of our open source projects. Eyevinn's consulting business can also offer you:
28 |
29 | - Further development of this component
30 | - Customization and integration of this component into your platform
31 | - Support and maintenance agreement
32 |
33 | Contact [sales@eyevinn.se](mailto:sales@eyevinn.se) if you are interested.
34 |
35 | # About Eyevinn Technology
36 |
37 | Eyevinn Technology is an independent consultant firm specialized in video and streaming. Independent in a way that we are not commercially tied to any platform or technology vendor.
38 |
39 | At Eyevinn, every software developer consultant has a dedicated budget reserved for open source development and contribution to the open source community. This give us room for innovation, team building and personal competence development. And also gives us as a company a way to contribute back to the open source community.
40 |
41 | Want to know more about Eyevinn and how it is to work here. Contact us at work@eyevinn.se!
42 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { WebRTCPlayer } from "@eyevinn/webrtc-player";
2 |
3 | const ComponentAttribute = {
4 | DYNAMIC: {
5 | SOURCE: 'src',
6 | AUTOPLAY: 'autoplay',
7 | MUTED: 'muted',
8 | }
9 | }
10 |
11 | const isSet = (value) => value === "" || !!value;
12 |
13 | export default class WhepVideoComponent extends HTMLElement {
14 | static get observedAttributes() {
15 | return Object.values(ComponentAttribute.DYNAMIC)
16 | }
17 |
18 | constructor() {
19 | super();
20 | const wrapper = this.setupDOM();
21 | this.setupPlayer(wrapper);
22 | }
23 |
24 | setupDOM() {
25 | this.attachShadow({ mode: 'open' });
26 | const { shadowRoot } = this;
27 |
28 | let styleTag = document.createElement('style');
29 | styleTag.innerHTML = "video { width: inherit; } div { width: inherit }";
30 | shadowRoot.appendChild(styleTag);
31 |
32 | const wrapper = document.createElement('div');
33 | shadowRoot.appendChild(wrapper);
34 | this.video = document.createElement('video');
35 | wrapper.appendChild(this.video);
36 |
37 | return wrapper;
38 | }
39 |
40 | setupPlayer(wrapper) {
41 | this.player = new WebRTCPlayer({
42 | video: this.video,
43 | type: "whep"
44 | });
45 | }
46 |
47 | async attributeChangedCallback(name) {
48 | const src = this.getAttribute(ComponentAttribute.DYNAMIC.SOURCE);
49 | const autoplay = this.getAttribute(ComponentAttribute.DYNAMIC.AUTOPLAY);
50 | const muted = this.getAttribute(ComponentAttribute.DYNAMIC.MUTED);
51 |
52 | if (name === ComponentAttribute.DYNAMIC.SOURCE) {
53 | if (isSet(src)) {
54 | await this.player.load(new URL(src));
55 | if (isSet(autoplay)) {
56 | this.video.muted = isSet(muted);
57 | this.video.autoplay = true;
58 | }
59 | } else {
60 | console.error("Missing src attribute in element");
61 | }
62 | }
63 | if (name === ComponentAttribute.DYNAMIC.MUTED) {
64 | this.video.muted = isSet(muted);
65 | }
66 | }
67 |
68 | disconnectedCallback() {
69 | this.player.destroy();
70 | }
71 | }
72 |
73 | customElements.define('whep-video', WhepVideoComponent);
--------------------------------------------------------------------------------