From 030969de969720ecda2f1bc7b54374c37cf50f93 Mon Sep 17 00:00:00 2001 From: lazorfuzz <leontosy@gmail.com> Date: Sun, 3 Jun 2018 07:23:31 -0700 Subject: [PATCH] Add getPeerByNick, transmit methods * Organize readme --- README.md | 163 ++++++++++++++++++++++++++--------------------- src/liowebrtc.js | 2 +- src/webrtc.js | 8 +++ 3 files changed, 99 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index 55c5378..076135a 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,6 @@ class Party extends Component { super(props); this.state = { nick: this.props.nick, - peers: [], roomID: `party-${this.props.roomName}`, muted: false, camPaused: false @@ -140,11 +139,11 @@ class Party extends Component { this.webrtc = new LioWebRTC({ // The url for your signaling server url: 'https://sandbox.simplewebrtc.com:443/', - // The local video reference set within your render function + // The local video ref set within your render function localVideoEl: this.localVid, // Immediately request camera access autoRequestMedia: true, - // Optional: The nickname of the peer in the room + // Optional: nickname nick: this.state.nick, }); @@ -156,17 +155,11 @@ class Party extends Component { } addVideo = (stream, peer) => { - this.setState({ - peers: [...this.state.peers, peer] - }, () => { - this.webrtc.attachStream(stream, this.remoteVideos[peer.id]); - }); + this.webrtc.attachStream(stream, this.remoteVideos[peer.id]); } - removeVideo = (video, peer) => { - this.setState({ - peers: this.state.peers.filter(p => p.id) - }); + removeVideo = (peer) => { + // Clean up video } handleConnectionError = (peer) => { @@ -237,11 +230,11 @@ export default Party; `new LioWebRTC(options)` - `object options` - - `string url` - *optional* url for your socket.io signaling server + - `string url` - url for your socket.io signaling server - `bool debug` - *optional* logs all webrtc events - `string nick` - *optional* sets your nickname. Peers' nicknames can be accessed with `peer.nick` - `[string|DomElement|Ref] localVideoEl` - Can be a ref, DOM element, or ID of the local video - - `bool autoRequestMedia` - *optional(=true)* automatically request + - `bool autoRequestMedia` - *optional(=false)* automatically request user media. Use `true` to request automatically, or `false` to request media later with `startLocalVideo` - `bool dataOnly` *optional(=false)* option to ensure that video and audio stream channels @@ -283,42 +276,46 @@ To set up event listeners, use the LioWebRTC instance created with the constructor. Example: ```js +// Emitted when a peer's media stream becomes available +this.webrtc.on('videoAdded', (stream, peer) => { + // Attach the MediaStream to a video element + // this.webrtc.attachStream(stream, this.remoteVideos[peer.id]); +}); +// Emitted when we receive data from a peer via the data channel this.webrtc.on('receivedPeerData', (type, payload, peer) => { - // ... -}) + // Find something to do with the data +}); ``` `'connectionReady', sessionId` - emitted when the signaling connection emits the `connect` event, with the unique id for the session. +`'createdPeer', peer` - this will be emitted when: +- joining a room with existing peers, once for each peer +- a new peer joins your room +- sharing screen, once for each peer + +`'leftRoom', roomName` - emitted after successfully leaving the current room, +ending all peers, and stopping the local screen stream + +`'localScreenAdded', el` - emitted after triggering the start of screen sharing +- `el` the element that contains the local screen stream + `'receivedPeerData', type, payload, peer` - emitted when a peer sends data via `shout` or `whisper` - `type` a label, usually a string, that describes the payload - `payload` any kind of data sent by the peer, usually an object - `peer` the object representing the peer and its peer connection -`'receivedSignalData', type, payload, peer` - emitted when a peer sends data via `broadcast` +`'receivedSignalData', type, payload, peer` - emitted when a peer sends data via `broadcast` or `transmit` - `type` a label, usually a string, that describes the payload - `payload` any kind of data sent by the peer, usually an object - `peer` the object representing the peer and its peer connection -`'createdPeer', peer` - this will be emitted when: -- joining a room with existing peers, once for each peer -- a new peer joins your room -- sharing screen, once for each peer - -- `peer` - the object representing the peer and its peer connection - -`'stunservers', [...args]` - emitted when the signaling server emits this event. +`'stunservers', [...args]` - emitted when the signaling server emits a list of stun servers. -`'turnservers', [...args]` - emitted when the signaling server emits this event. +`'turnservers', [...args]` - emitted when the signaling server emits a list of turn servers. -`'localScreenAdded', el` - emitted after triggering the start of screen sharing -- `el` the element that contains the local screen stream - -`'leftRoom', roomName` - emitted after successfully leaving the current room, -ending all peers, and stopping the local screen stream - -`'videoAdded', stream, peer` - emitted when a peer stream is added +`'videoAdded', stream, peer` - emitted when a peer's MediaStream becomes available - `stream` - the MediaStream associated with the peer - `peer` - the peer associated with the stream that was added @@ -327,86 +324,106 @@ ending all peers, and stopping the local screen stream ### Methods +`attachStream(stream, el)` - attaches a media stream to a video or audio element +- `MediaStream stream` - an object representing a media stream +- `HTMLElement el` - the element (or ref if you're using React) to attach the media stream to, usually a video or audio element + +`broadcast(messageType, payload)` - broadcasts a message to all peers in the +room via the signaling server (similar to `shout`, but not p2p). Listen for peers' broadcasts on the `receivedSignalData` event. + `createRoom(name, callback)` - emits the `create` event and optionally invokes `callback` on response +`disconnect()` - calls `disconnect` on the signaling connection and deletes it. Peers will still be available + +`emit(eventLabel, ...args)` - emit arbitrary event (Emits locally. To emit stuff to the room, use `broadcast`) + +`getContainerId(peer)` - get the DOM id associated with a peer's media element. In JSX, you will need to set the id of the container element to this value + +`getId(peer)` - get the DOM id associated with a peer's media stream. In JSX, you will need to set the id of the peer's media element to this value. + +`getLocalScreen()` - returns the local screen stream + +`getPeerByNick(nick)` - returns a peer with a given `nick` + +`getPeers(sessionId, type)` - returns all peers by `sessionId` and/or `type` + `joinRoom(name, callback)` - joins the room `name`. Callback is invoked with `callback(err, roomDescription)` where `roomDescription` is yielded by the connection on the `join` event. See [signalmaster](https://github.com/andyet/signalmaster) for details about rooms. -`startLocalVideo()` - starts the local video or audio streams with the `media` options provided -in the config +`leaveRoom()` - leaves the currently joined room and stops local screen share `mute()` - mutes the local audio stream to your peers (stops sending audio in the WebRTC audio channel) -`unmute()` - unmutes the audio stream to your peers (resumes sending audio in the WebRTC audio channel) - -`pauseVideo()` - pauses the video stream to your peers (stops sending video in the WebRTC video channel) - -`resumeVideo()` - resumes the video stream to your peers (resumes sending video in the WebRTC video channel) +`on(ev, fn)` - creates an event listener for event `ev` `pause()` - pauses both video and audio streams to your peers -`resume()` - resumes sending video and audio to your peers - -`shout(messageType, payload)` - sends a message -to all peers in the room via the default data channel -- `string messageType` - An arbitrary value that represents the classification of the payload -- `object payload` - an arbitrary value or object to send to peers +`pauseVideo()` - pauses the video stream to your peers (stops sending video in the WebRTC video channel) -`whisper(peer, messageType, payload)` - sends a message to a single peer in the room via the default data channel -- `string messageType` - An arbitrary value that represents the classification of the payload -- `object payload` - an arbitrary value or object to send to peers +`resume()` - resumes sending video and audio to your peers -`broadcast(messageType, payload)` - broadcasts a message to all peers in the -room via the signaling server (similar to `shout`, but not p2p) +`resumeVideo()` - resumes the video stream to your peers (resumes sending video in the WebRTC video channel) `sendDirectlyToAll(messageType, payload, channel)` - sends a message -to all peers in the room via a data channel (same as `shout`, except you can specify your own data channel. Use this if you need to set up a new data channel) -- `string channel` - (optional) the name of the data channel +to all peers in the room via a data channel (same as `shout`, except you can specify your own data channel. Use this if you need to set up a new data channel, like a dedicated file-sharing channel, etc.) +- `string channel` - (optional) the name of the data channel. If it doesn't exist, it will be created. -`getPeers(sessionId, type)` - returns all peers by `sessionId` and/or `type` - -`attachStream(stream, el)` - attaches a media stream to a video or audio element. -- `MediaStream stream` - an object representing a media stream -- `HTMLElement el` - the element (or ref if you're using React) to attach the media stream to +`setVolumeForAll(volume)` - set the volume level for all peers `shareScreen(callback)` - initiates screen capture request to browser, then streams the video to peers in the room -`getLocalScreen()` - returns the local screen stream +`shout(messageType, payload)` - sends a message +to all peers in the room via the default p2p data channel. Listen for peers' shouts on the `receivedPeerData` event. +- `string messageType` - An arbitrary value that represents the classification of the payload +- `object payload` - an arbitrary value or object to send to peers -`stopScreenShare()` - stops the screen share stream and removes it from the room +`startLocalVideo()` - starts the local video or audio streams with the `media` options provided +in the config `stopLocalVideo()` - stops all local media streams -`setVolumeForAll(volume)` - used to set the volume level for all peers +`stopScreenShare()` - stops the screen share stream and removes it from the room + +`transmit(peer, messageType, payload)` - sends a message to a single peer in the +room via the signaling server (similar to `whisper`, but not p2p). Listen for peers' transmissions on the `receivedSignalData` event. +`unmute()` - unmutes the audio stream to your peers (resumes sending audio in the WebRTC audio channel) - `volume` - the volume level, between 0 and 1 -`leaveRoom()` - leaves the currently joined room and stops local screen share +`whisper(peer, messageType, payload)` - sends a message to a single peer in the room via the default p2p data channel. Listen for peers' whispers on the `receivedPeerData` event. +- `string messageType` - An arbitrary value that represents the classification of the payload +- `object payload` - an arbitrary value or object to send to peers -`disconnect()` - calls `disconnect` on the signaling connection and deletes it -`getId(peer)` - get the DOM id associated with a peer's media stream. In JSX, you will need to set the id of the peer's media element to this value. +## Signaling -`getContainerId(peer)` - get the DOM id associated with a peer's media element. In JSX, you will need to set the id of the container element to this value. +WebRTC needs to be facilitated with signaling; a service that acts as a matchmaker for peers before they establish direct video/audio/data channels. Signaling can be done in any way, e.g. via good old fashioned carrier pigeons. Signaling services only need to fulfill the absolute minimal role of matchmaking peers. +[Signalmaster](https://github.com/andyet/signalmaster) is a [socket.io](http://socket.io/) server signaling solution, and is very easy to set up. socket.io enables real-time, bidirectional communication between a client and server via web sockets. It also allows us to easily segment peers into "rooms." -## Signaling +For emitting data to peers, LioWebRTC provides a unified, event-based API that enables peers to seamlessly switch between `shout`ing (p2p data channels) or `broadcast`ing (socket.io) to all the peers in a room. It's up to you to decide which protocol to use, but socket.io should ideally only be used for transmitting things like metadata, one-off events, etc. Both protocols are real-time, bidirectional, and event-based. + +When joining a room, the device becomes a node in a full mesh network consisting of every other peer in the room, opening a unique data channel to each peer. For video conferencing, that means a unique video, audio, and data channel is opened for each peer. + +The socket.io connection remains a single bi-directional pipeline between the client and the signaling server. It will always be a single connection no matter how many peers there are in the room. ### Connection -For signaling, LioWebRTC uses [socket.io](http://socket.io/) to -communicate with the signaling server, and returns a connection object. The connection object comes with the following methods: +LioWebRTC wraps socketio-client and returns a connection object. This the connection to the signaling server. The connection object comes with the following methods: -- `on(ev, fn)` - a method to set a listener +- `on(ev, fn)` - a method to set a listener for event `ev` - `emit()` - send/emit arbitrary events on the connection - `getSessionId()` - returns the session ID of the connection -- `disconnect()` - disconnect from the signaling server (closes the websocket) +- `disconnect()` - disconnect from the signaling server (closes the web socket) + +### Signaling Server Url -### Signaling Server +LioWebRTC uses the signalmaster server provided for testing purposes by SimpleWebRTC. +In production, you will need to set up your own [signalmaster](https://github.com/andyet/signalmaster) server (or any other socket.io solution that implements matchmaking). -LioWebRTC uses the signaling server provided for testing purposes by SimpleWebRTC. -In production, you will need to set up your own [signalmaster](https://github.com/andyet/signalmaster) server, and pass in your server's url when creating an instance of LioWebRTC. To start your signalmaster server in production mode using PM2, do the following: +To start your signalmaster server in production mode using PM2, do the following: ``` NODE_ENV=production pm2 start signalmaster ``` +Then pass your server's url into the LioWebRTC instantiation config. diff --git a/src/liowebrtc.js b/src/liowebrtc.js index 618bcc5..10c53e9 100644 --- a/src/liowebrtc.js +++ b/src/liowebrtc.js @@ -126,7 +126,7 @@ class LioWebRTC extends WildEmitter { this.webrtc = new WebRTC(opts); // attach a few methods from underlying lib to liowebrtc. - ['mute', 'unmute', 'pauseVideo', 'resumeVideo', 'pause', 'resume', 'sendToAll', 'sendDirectlyToAll', 'getPeers', 'shout', 'whisper', 'broadcast'].forEach((method) => { + ['mute', 'unmute', 'pauseVideo', 'resumeVideo', 'pause', 'resume', 'sendToAll', 'sendDirectlyToAll', 'getPeers', 'getPeerByNick', 'shout', 'whisper', 'broadcast'].forEach((method) => { self[method] = self.webrtc[method].bind(self.webrtc); }); diff --git a/src/webrtc.js b/src/webrtc.js index 8df366d..a4add9a 100644 --- a/src/webrtc.js +++ b/src/webrtc.js @@ -125,6 +125,10 @@ class WebRTC extends LocalMedia { return this.peers.filter(peer => (!sessionId || peer.id === sessionId) && (!type || peer.type === type)); } + getPeerByNick(nick) { + return this.peers.filter(p => p.nick === nick)[0]; + } + // sends message to all sendToAll(message, payload) { this.peers.forEach((peer) => { @@ -153,6 +157,10 @@ class WebRTC extends LocalMedia { broadcast(messageType, payload) { this.sendToAll('signalData', { type: messageType, payload }); } + + transmit(peer, messageType, payload) { + peer.send('signalData', { type: messageType, payload }); + } } export default WebRTC; -- GitLab