├── .all-contributorsrc ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .prettierrc ├── .releaserc.json ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js ├── site ├── .gitignore ├── .prettierignore ├── .prettierrc ├── gatsby-config.js ├── gatsby-node.js ├── package.json ├── src │ ├── components │ │ ├── button.js │ │ ├── console-feed.js │ │ ├── demo.js │ │ └── layout.js │ ├── constants.js │ ├── gatsby-plugin-theme-ui │ │ └── index.js │ ├── images │ │ ├── icon.png │ │ ├── logo.svg │ │ └── opentok.png │ └── pages │ │ ├── get-started.mdx │ │ └── index.mdx └── static │ └── favicon.ico └── src ├── .eslintrc ├── __mocks__ ├── @opentok │ └── client.js ├── mockData.js └── mockEventEmitter.js ├── index.js ├── index.test.js └── libs ├── use-opentok-reducer.js ├── use-opentok-reducer.test.js ├── use-session-event-handler.js └── use-session-event-handler.test.js /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "andyyou", 10 | "name": "andyyou", 11 | "avatar_url": "https://avatars0.githubusercontent.com/u/665690?v=4", 12 | "profile": "http://andyyou.github.io/", 13 | "contributions": [ 14 | "code", 15 | "design", 16 | "example", 17 | "maintenance", 18 | "ideas", 19 | "review" 20 | ] 21 | }, 22 | { 23 | "login": "pjchender", 24 | "name": "PJCHENder", 25 | "avatar_url": "https://avatars1.githubusercontent.com/u/13399740?v=4", 26 | "profile": "http://pjchender.blogspot.com", 27 | "contributions": [ 28 | "code", 29 | "doc", 30 | "test", 31 | "example", 32 | "maintenance", 33 | "review" 34 | ] 35 | }, 36 | { 37 | "login": "Mwjrink", 38 | "name": "Maximillian Rink", 39 | "avatar_url": "https://avatars2.githubusercontent.com/u/29183162?v=4", 40 | "profile": "https://github.com/Mwjrink", 41 | "contributions": [ 42 | "code" 43 | ] 44 | } 45 | ], 46 | "contributorsPerLine": 7, 47 | "projectName": "react-use-opentok", 48 | "projectOwner": "pjchender", 49 | "repoType": "github", 50 | "repoHost": "https://github.com", 51 | "skipCi": true 52 | } 53 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false 7 | } 8 | ], 9 | "@babel/preset-react" 10 | ], 11 | "plugins": ["@babel/plugin-transform-runtime"], 12 | "exclude": [ 13 | "node_modules/**" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | site 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "react-app", 5 | "plugin:jsx-a11y/recommended", 6 | "plugin:jest-dom/recommended" 7 | ], 8 | "plugins": [ 9 | "jsx-a11y", 10 | "jest-dom" 11 | ], 12 | "env": { 13 | "es6": true 14 | }, 15 | "parserOptions": { 16 | "sourceType": "module" 17 | }, 18 | "rules": { 19 | // don't force es6 functions to include space before paren 20 | "space-before-function-paren": 0, 21 | // allow specifying true explicitly for boolean props 22 | "react/jsx-boolean-value": 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # See https://help.github.com/ignore-files/ for more about ignoring files. 3 | *.log* 4 | 5 | # dependencies 6 | node_modules 7 | 8 | # builds 9 | build 10 | dist 11 | public 12 | 13 | # misc 14 | .DS_Store 15 | .env 16 | .vscode 17 | 18 | # cache 19 | .cache 20 | .eslintcache 21 | 22 | # these cause more harm than good 23 | # when working with contributors 24 | package-lock.json 25 | yarn.lock 26 | 27 | # test 28 | coverage 29 | 30 | # runtime 31 | pids 32 | *.pid 33 | *.seed 34 | *.pid.lock 35 | npm-debug.log* 36 | yarn-debug.log* 37 | yarn-error.log* 38 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | site/ 2 | src/ 3 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "es5", 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false 10 | } 11 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@semantic-release/commit-analyzer", 4 | "@semantic-release/release-notes-generator", 5 | "@semantic-release/changelog", 6 | [ 7 | "@semantic-release/npm", 8 | { 9 | "npmPublish": true 10 | } 11 | ], 12 | [ 13 | "@semantic-release/git", 14 | { 15 | "assets": ["CHANGELOG.md", "package.json"] 16 | } 17 | ] 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 12 4 | jobs: 5 | include: 6 | - stage: Produce Coverage 7 | node_js: 12 8 | script: npm run coveralls 9 | - stage: release 10 | node_js: 12 11 | script: npm run build 12 | deploy: 13 | provider: script 14 | script: npx -p @semantic-release/changelog -p @semantic-release/git -p semantic-release semantic-release 15 | skip_cleanup: true 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [2.3.1](https://github.com/pjchender/react-use-opentok/compare/v2.3.0...v2.3.1) (2021-02-19) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * [#25](https://github.com/pjchender/react-use-opentok/issues/25) change warn to throw for sendSignal ([#26](https://github.com/pjchender/react-use-opentok/issues/26)) ([222e6e6](https://github.com/pjchender/react-use-opentok/commit/222e6e61ebb85708577524182870781eb23ccd54)) 7 | * Travis YAML to specify node version ([0091758](https://github.com/pjchender/react-use-opentok/commit/009175802e06ee98add0ed1776f3d2fb28b4fd01)) 8 | 9 | # [2.3.0](https://github.com/pjchender/react-use-opentok/compare/v2.2.4...v2.3.0) (2020-10-12) 10 | 11 | 12 | ### Features 13 | 14 | * support initPublisher, removePublisher, publishPublisher ([#25](https://github.com/pjchender/react-use-opentok/issues/25)) ([0f7299a](https://github.com/pjchender/react-use-opentok/commit/0f7299a2c5f9b1684576b96a496ddc7c52ed952f)) 15 | 16 | ## [2.2.4](https://github.com/pjchender/react-use-opentok/compare/v2.2.3...v2.2.4) (2020-05-29) 17 | 18 | 19 | ### Bug Fixes 20 | 21 | * subscribe stream cannot be null ([#20](https://github.com/pjchender/react-use-opentok/issues/20)) ([8130593](https://github.com/pjchender/react-use-opentok/commit/81305933024d5985b63d1f7488b3af5cc68eaaed)) 22 | 23 | ## [2.2.3](https://github.com/pjchender/react-use-opentok/compare/v2.2.2...v2.2.3) (2020-03-31) 24 | 25 | 26 | ### Bug Fixes 27 | 28 | * recevie 'to' when sendSignal ([7b8a801](https://github.com/pjchender/react-use-opentok/commit/7b8a80162924f77d23cf5712d1ad176f0d7ded09)) 29 | 30 | ## [2.2.2](https://github.com/pjchender/react-use-opentok/compare/v2.2.1...v2.2.2) (2020-03-26) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * clarify the error message ([ffdd27c](https://github.com/pjchender/react-use-opentok/commit/ffdd27c1e9fd18aa3cd0f2e4489b829a31c6c517)) 36 | 37 | ## [2.2.1](https://github.com/pjchender/react-use-opentok/compare/v2.2.0...v2.2.1) (2020-03-14) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * Return subscriber of subscribe method ([#17](https://github.com/pjchender/react-use-opentok/issues/17)) ([8439ca3](https://github.com/pjchender/react-use-opentok/commit/8439ca3f416d84d401ceccb03c68a1737ffa3c5d)) 43 | 44 | # [2.2.0](https://github.com/pjchender/react-use-opentok/compare/v2.1.1...v2.2.0) (2020-02-27) 45 | 46 | 47 | ### Features 48 | 49 | * Support promise sharp for publish method ([#14](https://github.com/pjchender/react-use-opentok/issues/14)) ([660b356](https://github.com/pjchender/react-use-opentok/commit/660b3562a103df78036d3c9a7a06722cdd891334)) 50 | 51 | ## [2.1.1](https://github.com/pjchender/react-use-opentok/compare/v2.1.0...v2.1.1) (2020-02-26) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * throw error issue ([#13](https://github.com/pjchender/react-use-opentok/issues/13)) ([459e1b6](https://github.com/pjchender/react-use-opentok/commit/459e1b6c738f6a878acde687f45cbaca6c3cfd70)) 57 | 58 | # [2.1.0](https://github.com/pjchender/react-use-opentok/compare/v2.0.1...v2.1.0) (2020-02-14) 59 | 60 | 61 | ### Features 62 | 63 | * add isSessionInitialized properties ([#11](https://github.com/pjchender/react-use-opentok/issues/11)) ([6636959](https://github.com/pjchender/react-use-opentok/commit/663695972a84c175784a3cee47df2518c2c6dbd7)) 64 | 65 | ## [2.0.1](https://github.com/pjchender/react-use-opentok/compare/v2.0.0...v2.0.1) (2020-02-07) 66 | 67 | 68 | ### Bug Fixes 69 | 70 | * unexpectedly invoke initSessionAndConnect twice when use it in useEffect ([#10](https://github.com/pjchender/react-use-opentok/issues/10)) ([d300f89](https://github.com/pjchender/react-use-opentok/commit/d300f896e3a8339810650db2fa7cd4797a488aa3)) 71 | 72 | # [2.0.0](https://github.com/pjchender/react-use-opentok/compare/v1.0.5...v2.0.0) (2020-02-05) 73 | 74 | 75 | * refactor!: add initSessionAndConnect and remove setCredentials in openTokMethods (#9) ([845735c](https://github.com/pjchender/react-use-opentok/commit/845735ca245fb660fac7bc596d8797c8785c3188)), closes [#9](https://github.com/pjchender/react-use-opentok/issues/9) [#9](https://github.com/pjchender/react-use-opentok/issues/9) 76 | 77 | 78 | ### BREAKING CHANGES 79 | 80 | * add initSessionAndConnect and remove setCredentials in API 81 | 82 | ## [1.0.5](https://github.com/pjchender/react-use-opentok/compare/v1.0.4...v1.0.5) (2020-02-03) 83 | 84 | 85 | ### Bug Fixes 86 | 87 | * add rollup-plugin-terser for minifying bundle files ([#8](https://github.com/pjchender/react-use-opentok/issues/8)) ([4bdaa9e](https://github.com/pjchender/react-use-opentok/commit/4bdaa9e110fbb9425ff7ef639d290ffd89f903bd)) 88 | 89 | ## [1.0.4](https://github.com/pjchender/react-use-opentok/compare/v1.0.3...v1.0.4) (2020-01-31) 90 | 91 | 92 | ### Bug Fixes 93 | 94 | * integrate with coveralls and add coveralls badge ([#7](https://github.com/pjchender/react-use-opentok/issues/7)) ([e504f1b](https://github.com/pjchender/react-use-opentok/commit/e504f1bd29e25f6201514fcdaf0843b308b4fdd8)) 95 | 96 | ## [1.0.3](https://github.com/pjchender/react-use-opentok/compare/v1.0.2...v1.0.3) (2020-01-31) 97 | 98 | 99 | ### Bug Fixes 100 | 101 | * add test for react-use-opentok ([fda06fa](https://github.com/pjchender/react-use-opentok/commit/fda06fa9c6f5d688f00d9e561185d94592737749)) 102 | * update packages ([8c7d21d](https://github.com/pjchender/react-use-opentok/commit/8c7d21d07bc314cefe8e54562ccb4da904595252)) 103 | 104 | ## [1.0.2](https://github.com/pjchender/react-use-opentok/compare/v1.0.1...v1.0.2) (2020-01-21) 105 | 106 | 107 | ### Bug Fixes 108 | 109 | * **ci:** update travis ci config for skip_cleanup ([f00c1e6](https://github.com/pjchender/react-use-opentok/commit/f00c1e677c99c9007ed7f5f316e913c6f314cb7d)) 110 | 111 | ## [1.0.1](https://github.com/pjchender/react-use-opentok/compare/v1.0.0...v1.0.1) (2020-01-21) 112 | 113 | 114 | ### Bug Fixes 115 | 116 | * **ci:** update travis ci ([0d4b668](https://github.com/pjchender/react-use-opentok/commit/0d4b668ed314ce5e574dcbcf2663585d228c18cf)) 117 | 118 | # 1.0.0 (2020-01-21) 119 | 120 | 121 | ### Bug Fixes 122 | 123 | * Update Travis CI file and install semantic-release ([da42b5c](https://github.com/pjchender/react-use-opentok/commit/da42b5c09c6ed6680b2dd93696b3f853477396f8)) 124 | * **typo:** Fix typo and format documents ([edeaf4b](https://github.com/pjchender/react-use-opentok/commit/edeaf4b0538ef6eb9a2f59e81ba339c3f2132091)) 125 | 126 | 127 | ### Features 128 | 129 | * Add ConsoleFeed component ([b85dc1b](https://github.com/pjchender/react-use-opentok/commit/b85dc1b54446e057e36ebc916d0b98017d6bd968)) 130 | * Add sendSignal function in react-use-opentok ([3cc902f](https://github.com/pjchender/react-use-opentok/commit/3cc902f75792a2c10d389bfdbd98a9414fdfbf81)) 131 | * Create demo site of useOpenTok by Gatsby ([35fe889](https://github.com/pjchender/react-use-opentok/commit/35fe889929057b32afaa61bd9390e0f1caeae9c9)) 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 PJCHENder 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-use-opentok 2 | 3 | [![Build status](https://badgen.net/travis/pjchender/react-use-opentok)](https://travis-ci.com/pjchender/react-use-opentok) 4 | [![version](https://img.shields.io/npm/v/react-use-opentok.svg)](https://www.npmjs.com/package/react-use-opentok) 5 | [![Coverage Status](https://coveralls.io/repos/github/pjchender/react-use-opentok/badge.svg?branch=master)](https://coveralls.io/github/pjchender/react-use-opentok?branch=master) 6 | [![license](https://img.shields.io/github/license/pjchender/react-use-opentok.svg)](https://github.com/pjchender/react-use-opentok/blob/master/LICENSE) 7 | [![All Contributors](https://img.shields.io/badge/all_contributors-2-orange.svg)](#contributors) 8 | 9 | React Hook for conveniently use @opentok/client SDK. 10 | 11 | ## Pre-requirement 12 | 13 | * Register [Opentok](https://id.tokbox.com/login) to get authentication. 14 | 15 | ## Demo 16 | 17 | See our demo site: [react-use-opentok](https://pjchender.github.io/react-use-opentok/) 18 | 19 | ![react-use-opentok](https://i.imgur.com/mpmlkrI.gif) 20 | 21 | ## Installation 22 | 23 | Install it with npm: 24 | 25 | ``` 26 | npm i @opentok/client@2.x react-use-opentok 27 | ``` 28 | 29 | Or with yarn: 30 | 31 | ``` 32 | yarn add @opentok/client@2.x react-use-opentok 33 | ``` 34 | 35 | > NOTE: remember to install the peer dependency of [@opentok/client](https://www.npmjs.com/package/@opentok/client) 36 | 37 | ## Getting Started 38 | 39 | 1. Get utilities from `useOpenTok` hook 40 | 2. Fetch `apiKey`, `sessionId`, and `token` from server 41 | 3. Connect to session with `token` 42 | 43 | ```js 44 | import React, { useEffect } from 'react'; 45 | import useOpenTok from 'react-use-opentok'; 46 | 47 | const Component = () => { 48 | // STEP 1: get utilities from useOpenTok; 49 | const [opentokProps, opentokMethods] = useOpenTok(); 50 | 51 | const { 52 | // connection info 53 | isSessionInitialized, 54 | connectionId, 55 | isSessionConnected, 56 | 57 | // connected data 58 | session, 59 | connections, 60 | streams, 61 | subscribers, 62 | publisher, 63 | } = opentokProps; 64 | 65 | const { 66 | initSessionAndConnect, 67 | disconnectSession, 68 | publish, 69 | unpublish, 70 | subscribe, 71 | unsubscribe, 72 | sendSignal, 73 | } = opentokMethods; 74 | 75 | // STEP 2: Mockup fetching apiKey, sessionId, and token from server 76 | useEffect(() => { 77 | fetch('').then( 78 | ({ apiKey, sessionId, token }) => { 79 | initSessionAndConnect({ 80 | apiKey, 81 | sessionId, 82 | token, 83 | }); 84 | } 85 | ); 86 | }, [initSessionAndConnect]); 87 | 88 | return
...
; 89 | }; 90 | 91 | export default Component; 92 | ``` 93 | 94 | ## Guide 95 | 96 | ### Get all utilities from useOpenTok Hook 97 | 98 | You can get all utilities from `useOpenTok` hook. 99 | 100 | ```js 101 | const [opentokProps, opentokMethods] = useOpenTok(); 102 | 103 | const { 104 | // connection info 105 | isSessionInitialized, 106 | connectionId, 107 | isSessionConnected, 108 | 109 | // connected data 110 | session, 111 | connections, 112 | streams, 113 | subscribers, 114 | publisher, 115 | } = opentokProps; 116 | 117 | const { 118 | initSessionAndConnect, 119 | disconnectSession, 120 | publish, 121 | unpublish, 122 | subscribe, 123 | unsubscribe, 124 | sendSignal, 125 | } = opentokMethods; 126 | ``` 127 | 128 | ### Connect and disconnect to session 129 | 130 | Before starting use openTok session object, remember to initialize session with `apiKey` and `sessionId` by `initSessionAndConnect` method: 131 | 132 | ```js 133 | const [opentokProps, opentokMethods] = useOpenTok(); 134 | const { initSessionAndConnect } = opentokMethods; 135 | 136 | // apiKey, sessionId, and token could get from your server or tokbox dashboard 137 | initSessionAndConnect({ 138 | apiKey, 139 | sessionId, 140 | token, 141 | }); 142 | ``` 143 | This methods will first initialize the session object, and continue connected to the session. 144 | 145 | After session initialized, the value of `isSessionInitialized` will be `true. 146 | 147 | After connect to session, you can get the `session`, `connectionId` , `isSessionConnected`, and `connections` properties from `opentokProps`: 148 | 149 | - `session`: a session object from [`OT.initSession()`](https://tokbox.com/developer/sdks/js/reference/OT.html#initSession) 150 | - `connectionId`: your own connectionId 151 | - `isSessionConnected`: whether you are connected to the session 152 | - `connections`: all connections in the session 153 | 154 | ```js 155 | const [opentokProps, opentokMethods] = useOpenTok(); 156 | const { session, connectionId, isSessionConnected, connections } = opentokProps; 157 | ``` 158 | 159 | By `disconnectSession`, you can disconnect from the session: 160 | 161 | ```js 162 | const [opentokProps, opentokMethods] = useOpenTok(); 163 | const { disconnectSession } = opentokMethods; 164 | 165 | disconnectSession(); 166 | ``` 167 | 168 | > If you want to control the process of session initialization and connect to session on your own, check the method `initSession({ apiKey, sessionId, sessionOptions })` and `connectSession({token, sessionToConnect })`. 169 | 170 | ### Publish and unpublished stream to the session 171 | 172 | You can publish stream from camera or screen to session through the `publish` method. 173 | 174 | - `name`: should be unique every time you invoke publish method which is for `unpublish` stream later. 175 | - `element`: should be a DOM element or the `id` attribute of the existing DOM element. 176 | - `options`: (optional) other optional properties which will pass into [OT.initPublisher](https://tokbox.com/developer/sdks/js/reference/OT.html#initPublisher). 177 | 178 | ```js 179 | const [opentokProps, opentokMethods] = useOpenTok(); 180 | const { publish } = opentokMethods; 181 | 182 | // publish stream from the camera 183 | publish({ 184 | name: 'camera', 185 | element: 'camera', 186 | }); 187 | 188 | // publish stream from screen sharing 189 | publish({ 190 | name: 'screen', 191 | element: 'screen', 192 | options: { 193 | insertMode: 'append', 194 | width: '100%', 195 | height: '100%', 196 | videoSource: 'screen', 197 | }, 198 | }); 199 | 200 | // publish support Promise way to catch errors 201 | publish({ 202 | name: 'camera', 203 | element: 'camera', 204 | }).catch((ex) => { 205 | console.log(ex); 206 | }); 207 | ``` 208 | 209 | According to the `name` you publish, you could use the same name to unpublish it: 210 | 211 | ```js 212 | const [opentokProps, opentokMethods] = useOpenTok(); 213 | const { unpublish } = opentokMethods; 214 | 215 | // unpublish stream from the name 'camera' 216 | unpublish({ name: 'camera' } 217 | ``` 218 | 219 | ### Subscribe and Unsubscribe 220 | 221 | You can get all streams in the session through `streams` property in `opentokProps`. After finding the stream for subscribing, use the `subscribe` method to subscribe to the stream: 222 | 223 | - `stream`: the Stream Object wanted to subscribe 224 | - `element`: should be a DOM element or the `id` attribute of the existing DOM element. 225 | 226 | ```js 227 | const [opentokProps, opentokMethods] = useOpenTok(); 228 | const { streams } = opentokProps; 229 | const { subscribe } = opentokMethods; 230 | 231 | const streamToSubscribe = streams[0]; 232 | subscribe({ stream: streamToSubscribe, element: 'subscriber' }); 233 | ``` 234 | 235 | For each stream be subscribed, a [subscriber object](https://tokbox.com/developer/sdks/js/reference/Session.html#subscribe) will be created and save as `subscribers` in `opentokProps`: 236 | 237 | ```js 238 | const [opentokProps, opentokMethods] = useOpenTok(); 239 | const { streams, subscribers } = opentokProps; 240 | ``` 241 | 242 | You can stop subscribing the stream with `unsubscribe` method: 243 | 244 | ```js 245 | const [opentokProps, opentokMethods] = useOpenTok(); 246 | const { unsubscribe } = opentokMethods; 247 | 248 | const streamToUnsubscribe = streams[0]; 249 | unsubscribe({ stream: streamToUnsubscribe }); 250 | ``` 251 | 252 | ### Send signal 253 | 254 | You can send signal in session with `sendSignal` method: 255 | 256 | ```js 257 | const [opentokProps, opentokMethods] = useOpenTok(); 258 | const { sendSignal } = opentokMethods; 259 | 260 | sendSignal({ 261 | type: 'foo', 262 | data: 'bar', 263 | }); 264 | ``` 265 | 266 | ### Register session events 267 | 268 | You could register all valid [session events](https://tokbox.com/developer/sdks/js/reference/Session.html#events) on `session` object. Take registering signal event, as an example, use the `session` object in `opentokProps`, register the session event with `on`, and unregister the event with `off`: 269 | 270 | ```js 271 | const [opentokProps, opentokMethods] = useOpenTok(); 272 | const { session } = opentokProps; 273 | 274 | const handleSignal = useCallback(e => { 275 | console.log('handleSignal', e); 276 | }, []); 277 | 278 | useEffect(() => { 279 | if (!isSessionConnected) { 280 | return; 281 | } 282 | 283 | session.on('signal', handleSignal); 284 | return () => { 285 | session.off('signal', handleSignal); 286 | }; 287 | }, [handleSignal, isSessionConnected, session]); 288 | ``` 289 | 290 | > NOTICE: for `sessionDisconnected` event, you can you `session.once('sessionDisconnected', )` 291 | 292 | ### (Optional) Preview Solution 293 | 294 | You may want to split `OT.initPublisher` and `session.publish` and invoke it in different stage. To solve the requirement you can use `initPublisher` and `publishPublisher` instead. If you need to cancel preview you can use `removePublisher` as well. 295 | 296 | NOTE: 297 | 298 | * `initPublisher` - Same with `OT.initPublisher` but support state which means you can access `publisher`. 299 | * `removePublisher` - The method can only remove `publisher` without publish. Once you publish the `publisher` you should use `unpublish` instead. 300 | * `publishPublisher` - Publish for `initPublisher`. 301 | 302 | `initPublisher` + `publishPublisher` = `publish` 303 | 304 | For example: 305 | 306 | ```js 307 | const Component = () => { 308 | const [opentokProps, opentokMethods] = useOpenTok(); 309 | 310 | const { 311 | initPublisher, 312 | publishPublisher, 313 | removePublisher, 314 | } = opentokMethods; 315 | 316 | // ... 317 | 318 | const onInitPublisher = () => { 319 | initPublisher({ 320 | name: 'guest', 321 | element: 'guest', 322 | options: { 323 | insertMode: 'append', 324 | width: '480px', 325 | height: '360px', 326 | }, 327 | }); 328 | }; 329 | const onPublishPublisher = () => { 330 | publishPublisher({ 331 | name: 'guest', 332 | }); 333 | }; 334 | const onRemovePublisher = () => { 335 | removePublisher({ 336 | name: 'guest', 337 | }); 338 | }; 339 | 340 | return ( 341 |
342 |
343 |
344 | 345 | 346 | 347 |
348 |
349 | ); 350 | } 351 | ``` 352 | 353 | ## Development 354 | 355 | ### for react-use-opentok package 356 | 357 | ```sh 358 | $ npm install 359 | $ npm start # rollup will watch the files change 360 | $ npm build # rollup will build the package 361 | $ npm test 362 | ``` 363 | 364 | ### for example site 365 | 366 | ```sh 367 | $ cd site 368 | $ npm install 369 | $ npm start # start gatsby develop server 370 | ``` 371 | 372 | ## Contributors 373 | 374 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 |

andyyou

💻 🎨 💡 🚧 🤔 👀

PJCHENder

💻 📖 ⚠️ 💡 🚧 👀

Maximillian Rink

💻
385 | 386 | 387 | 388 | 389 | 390 | This project follows the [all-contributors](https://allcontributors.org/) specification. Contributions of any kind welcome! 391 | 392 | ## LICENSE 393 | 394 | [MIT](https://github.com/pjchender/react-use-opentok/blob/master/LICENSE) 395 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-use-opentok", 3 | "version": "2.3.1", 4 | "description": "React Hook for @opentok/client SDK", 5 | "contributors": [ 6 | "PJCHENder (https://pjchender.blogspot.com)", 7 | "Andyyou (http://andyyou.github.io/)" 8 | ], 9 | "license": "MIT", 10 | "main": "dist/react-use-opentok.cjs.min.js", 11 | "module": "dist/react-use-opentok.esm.min.js", 12 | "engines": { 13 | "node": ">=8", 14 | "npm": ">=5" 15 | }, 16 | "scripts": { 17 | "start": "rollup -c -w", 18 | "build": "npm run clean && rollup -c", 19 | "clean": "rm -rf dist", 20 | "test": "cross-env CI=1 react-scripts test --env=jsdom", 21 | "test:watch": "react-scripts test --env=jsdom", 22 | "coveralls": "npm test -- --coverage && cat ./coverage/lcov.info | coveralls", 23 | "build:site": "cd site && npm install && npm run build", 24 | "deploy": "gh-pages -d site/public", 25 | "semantic-release": "semantic-release", 26 | "semantic-release:dry": "npx semantic-release --dry-run --no-ci" 27 | }, 28 | "files": [ 29 | "dist" 30 | ], 31 | "keywords": [ 32 | "tokbox", 33 | "opentok", 34 | "sdk", 35 | "react", 36 | "hook" 37 | ], 38 | "repository": { 39 | "type": "git", 40 | "url": "https://github.com/pjchender/react-use-opentok.git" 41 | }, 42 | "homepage": "https://pjchender.github.io/react-use-opentok/", 43 | "bugs": { 44 | "url": "https://github.com/pjchender/react-use-opentok/issues" 45 | }, 46 | "peerDependencies": { 47 | "@opentok/client": "^2.16.3", 48 | "react": "^17.0.2" 49 | }, 50 | "devDependencies": { 51 | "@babel/core": "^7.8.3", 52 | "@babel/plugin-transform-runtime": "^7.12.17", 53 | "@babel/preset-env": "^7.8.3", 54 | "@babel/preset-react": "^7.12.13", 55 | "@babel/runtime": "^7.12.18", 56 | "@opentok/client": "^2.16.6", 57 | "@rollup/plugin-babel": "^5.3.0", 58 | "@rollup/plugin-commonjs": "^11.0.1", 59 | "@rollup/plugin-node-resolve": "^7.0.0", 60 | "@rollup/plugin-url": "^4.0.1", 61 | "@semantic-release/changelog": "^5.0.0", 62 | "@semantic-release/git": "^9.0.0", 63 | "@testing-library/jest-dom": "^5.0.2", 64 | "@testing-library/react": "^9.4.0", 65 | "@testing-library/react-hooks": "^3.2.1", 66 | "@typescript-eslint/eslint-plugin": "^2.18.0", 67 | "@typescript-eslint/parser": "^2.18.0", 68 | "babel-eslint": "^10.0.3", 69 | "coveralls": "^3.0.9", 70 | "cross-env": "^7.0.0", 71 | "eslint": "^6.8.0", 72 | "eslint-config-react-app": "^5.1.0", 73 | "eslint-plugin-flowtype": "^4.6.0", 74 | "eslint-plugin-import": "^2.20.0", 75 | "eslint-plugin-jest-dom": "^2.0.0", 76 | "eslint-plugin-jsx-a11y": "^6.2.3", 77 | "eslint-plugin-promise": "^4.0.0", 78 | "eslint-plugin-react": "^7.18.0", 79 | "eslint-plugin-react-hooks": "^2.3.0", 80 | "gh-pages": "^2.0.1", 81 | "react": "^17.0.2", 82 | "react-scripts": "^3.0.1", 83 | "react-test-renderer": "^16.9.0", 84 | "rollup": "^2.0.5", 85 | "rollup-plugin-babel": "^4.3.2", 86 | "rollup-plugin-commonjs": "^10.1.0", 87 | "rollup-plugin-node-resolve": "^5.2.0", 88 | "rollup-plugin-peer-deps-external": "^2.2.0", 89 | "rollup-plugin-terser": "^5.2.0", 90 | "rollup-plugin-url": "^3.0.1", 91 | "semantic-release": "^17.0.1", 92 | "typescript": "^3.7.5" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel'; 2 | import external from 'rollup-plugin-peer-deps-external'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import resolve from '@rollup/plugin-node-resolve'; 5 | import url from '@rollup/plugin-url'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | 8 | import pkg from './package.json'; 9 | 10 | export default { 11 | input: 'src/index.js', 12 | output: [ 13 | { 14 | file: pkg.main.replace('.min', ''), 15 | format: 'cjs', 16 | sourcemap: true, 17 | exports: 'auto', 18 | }, 19 | { 20 | file: pkg.main, 21 | format: 'cjs', 22 | sourcemap: true, 23 | exports: 'auto', 24 | }, 25 | { 26 | file: pkg.module, 27 | format: 'esm', 28 | sourcemap: true, 29 | exports: 'auto', 30 | }, 31 | ], 32 | external: [/@babel\/runtime/, '@opentok/client', 'react'], 33 | plugins: [ 34 | external(), 35 | url({ exclude: ['**/*.svg'] }), 36 | babel({ babelHelpers: 'runtime' }), 37 | resolve(), 38 | commonjs(), 39 | terser({ 40 | include: [/^.+\.min\.js$/], 41 | }), // minify bundle files 42 | ], 43 | }; 44 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /site/.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | package.json 3 | package-lock.json 4 | public 5 | -------------------------------------------------------------------------------- /site/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": true, 4 | "singleQuote": true, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /site/gatsby-config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Configure your Gatsby site with this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/gatsby-config/ 5 | */ 6 | 7 | module.exports = { 8 | pathPrefix: `/react-use-opentok`, 9 | plugins: [ 10 | `gatsby-plugin-theme-ui`, 11 | { 12 | resolve: `gatsby-plugin-mdx`, 13 | options: { 14 | defaultLayouts: { 15 | default: require.resolve('./src/components/layout.js'), 16 | }, 17 | }, 18 | }, 19 | { 20 | resolve: `gatsby-plugin-manifest`, 21 | options: { 22 | icon: require.resolve('./src/images/icon.png'), 23 | }, 24 | }, 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /site/gatsby-node.js: -------------------------------------------------------------------------------- 1 | exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => { 2 | if (stage === "build-html") { 3 | actions.setWebpackConfig({ 4 | module: { 5 | rules: [ 6 | { 7 | test: /@opentok\/client|console-feed/, 8 | use: loaders.null(), 9 | }, 10 | ], 11 | }, 12 | }) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-hello-world", 3 | "private": true, 4 | "description": "A simplified bare-bones starter for Gatsby", 5 | "version": "0.1.0", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "gatsby build --prefix-paths", 9 | "develop": "gatsby develop", 10 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 11 | "start": "npm run develop", 12 | "serve": "gatsby serve", 13 | "clean": "gatsby clean", 14 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" 15 | }, 16 | "dependencies": { 17 | "@emotion/core": "^10.0.27", 18 | "@emotion/styled": "^10.0.27", 19 | "@mdx-js/mdx": "^1.5.3", 20 | "@mdx-js/react": "^1.5.3", 21 | "@theme-ui/components": "^0.2.50", 22 | "console-feed": "^2.8.11", 23 | "formik": "^2.1.2", 24 | "gatsby": "^2.19.45", 25 | "gatsby-plugin-manifest": "^2.2.48", 26 | "gatsby-plugin-mdx": "^1.0.83", 27 | "gatsby-plugin-theme-ui": "^0.2.53", 28 | "react": "file:../node_modules/react", 29 | "react-dom": "^16.12.0", 30 | "react-use-localstorage": "^3.4.1", 31 | "react-use-opentok": "file:..", 32 | "theme-ui": "^0.2.52" 33 | }, 34 | "devDependencies": { 35 | "prettier": "^1.19.1" 36 | }, 37 | "eslintConfig": { 38 | "extends": "react-app" 39 | }, 40 | "repository": { 41 | "type": "git", 42 | "url": "https://github.com/gatsbyjs/gatsby-starter-hello-world" 43 | }, 44 | "bugs": { 45 | "url": "https://github.com/gatsbyjs/gatsby/issues" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /site/src/components/button.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import { jsx } from 'theme-ui'; 3 | 4 | export default ({ children, ...props }) => ( 5 | 22 | ); 23 | -------------------------------------------------------------------------------- /site/src/components/console-feed.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useRef } from 'react'; 2 | import { Hook, Console } from 'console-feed'; 3 | import { Box, Heading } from '@theme-ui/components'; 4 | 5 | const scrollToBottom = targetElement => { 6 | if (!targetElement) return; 7 | targetElement.scrollTo({ 8 | top: targetElement.scrollHeight, 9 | behavior: 'smooth', 10 | }); 11 | }; 12 | 13 | const ConsoleFeed = () => { 14 | const [logs, setLogs] = useState([]); 15 | const containerRef = useRef(null); 16 | 17 | useEffect(() => { 18 | Hook( 19 | window.console, 20 | log => { 21 | setLogs(prevLogs => [...prevLogs, log]); 22 | scrollToBottom(containerRef.current); 23 | }, 24 | false 25 | ); 26 | }, []); 27 | 28 | return ( 29 | <> 30 | 31 | Browser Console 32 | 33 | 42 | 43 | 44 | 45 | ); 46 | }; 47 | 48 | export default ConsoleFeed; 49 | -------------------------------------------------------------------------------- /site/src/components/demo.js: -------------------------------------------------------------------------------- 1 | /** @jsx jsx */ 2 | import React, { useEffect, useCallback } from 'react'; 3 | import { jsx } from 'theme-ui'; 4 | import { useFormik } from 'formik'; 5 | import useOpenTok from 'react-use-opentok'; 6 | import useLocalStorage from 'react-use-localstorage'; 7 | import { 8 | Box, 9 | Label, 10 | Input, 11 | Textarea, 12 | Button, 13 | Badge, 14 | } from '@theme-ui/components'; 15 | import ConsoleFeed from './console-feed'; 16 | 17 | import { API_KEY, SESSION_ID, TOKEN } from '../constants'; 18 | 19 | // The options is used for 20 | // `Session.subscribe` and `Session.initPublisher` 21 | const defaultOpenTokOptions = { 22 | insertMode: 'append', 23 | width: '100%', 24 | height: '100%', 25 | }; 26 | 27 | const initialCredentials = JSON.stringify({ 28 | apiKey: API_KEY, 29 | sessionId: SESSION_ID, 30 | token: TOKEN, 31 | }); 32 | 33 | const Demo = () => { 34 | const [opentokProps, opentokMethods] = useOpenTok(); 35 | const [credentials, setCredentials] = 36 | typeof window !== 'undefined' 37 | ? useLocalStorage('credentials', initialCredentials) 38 | : [initialCredentials]; 39 | 40 | const { 41 | connectionId, 42 | isSessionConnected, 43 | 44 | session, 45 | connections, 46 | streams, 47 | subscribers, 48 | publisher, 49 | } = opentokProps; 50 | 51 | const { 52 | initSessionAndConnect, 53 | disconnectSession, 54 | publish, 55 | unpublish, 56 | subscribe, 57 | unsubscribe, 58 | sendSignal, 59 | } = opentokMethods; 60 | 61 | const credentialsFormik = useFormik({ 62 | initialValues: { 63 | ...JSON.parse(credentials), 64 | }, 65 | onSubmit: async (values, { setSubmitting }) => { 66 | const { apiKey, sessionId, token } = values; 67 | setCredentials( 68 | JSON.stringify({ 69 | ...values, 70 | }) 71 | ); 72 | 73 | await initSessionAndConnect({ 74 | apiKey, 75 | sessionId, 76 | token, 77 | }); 78 | 79 | setSubmitting(false); 80 | }, 81 | }); 82 | 83 | const signalFormik = useFormik({ 84 | initialValues: { 85 | type: '', 86 | data: '', 87 | }, 88 | onSubmit: (values, { setSubmitting, resetForm }) => { 89 | if (values.data.length === 0) { 90 | console.warn('signal data is empty'); 91 | return; 92 | } 93 | 94 | sendSignal({ 95 | ...values, 96 | }); 97 | 98 | setTimeout(() => { 99 | resetForm(); 100 | setSubmitting(false); 101 | }, 400); 102 | }, 103 | }); 104 | 105 | // Listener of `signal` 106 | // References https://tokbox.com/developer/sdks/js/reference/SignalEvent.html 107 | const handleSignal = useCallback(e => { 108 | console.log('handleSignal', e); 109 | }, []); 110 | 111 | const handleSessionDisconnected = useCallback(e => { 112 | console.log('handle session disconnected', e); 113 | }, []); 114 | 115 | useEffect(() => { 116 | if (!isSessionConnected) { 117 | return; 118 | } 119 | session.on('signal', handleSignal); 120 | session.once('sessionDisconnected', handleSessionDisconnected); 121 | return () => { 122 | session.off('signal', handleSignal); 123 | }; 124 | }, [handleSignal, handleSessionDisconnected, isSessionConnected, session]); 125 | 126 | const streamGroups = 127 | streams && 128 | streams.reduce((groups, stream) => { 129 | const { connection } = stream; 130 | groups[connection.connectionId] = groups[connection.connectionId] || []; 131 | groups[connection.connectionId].push(stream); 132 | return groups; 133 | }, {}); 134 | 135 | if (typeof window === 'undefined') return null; 136 | 137 | return ( 138 | <> 139 |
145 | {/* Left Side */} 146 |
151 |
159 |
170 |
181 |
192 |
193 |
194 | {isSessionConnected ? ( 195 | <> 196 |
201 | 204 | 205 | {!publisher.camera ? ( 206 | 217 | ) : ( 218 | 224 | )} 225 | 226 | {!publisher.screen ? ( 227 | 242 | ) : ( 243 | 249 | )} 250 |
251 | 252 | 253 | 256 | 263 |