{"id":13691597,"url":"https://github.com/lazorfuzz/liowebrtc","last_synced_at":"2025-04-10T01:08:08.538Z","repository":{"id":38916044,"uuid":"135642445","full_name":"lazorfuzz/liowebrtc","owner":"lazorfuzz","description":"An event-based WebRTC library that makes it easy to embed real-time peer to peer communication into UI components.","archived":false,"fork":false,"pushed_at":"2022-12-08T23:11:56.000Z","size":1012,"stargazers_count":165,"open_issues_count":20,"forks_count":10,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-10T01:08:03.157Z","etag":null,"topics":["electronjs","javascript","javascript-library","liowebrtc","p2p-chat","p2p-cloud","p2p-everything","p2p-network","p2p-transfer","peer-communication","react","reactjs","webrtc"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lazorfuzz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-31T22:48:06.000Z","updated_at":"2025-04-03T14:40:34.000Z","dependencies_parsed_at":"2023-01-25T12:16:07.400Z","dependency_job_id":null,"html_url":"https://github.com/lazorfuzz/liowebrtc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lazorfuzz%2Fliowebrtc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lazorfuzz%2Fliowebrtc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lazorfuzz%2Fliowebrtc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lazorfuzz%2Fliowebrtc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lazorfuzz","download_url":"https://codeload.github.com/lazorfuzz/liowebrtc/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137888,"owners_count":21053775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electronjs","javascript","javascript-library","liowebrtc","p2p-chat","p2p-cloud","p2p-everything","p2p-network","p2p-transfer","peer-communication","react","reactjs","webrtc"],"created_at":"2024-08-02T17:00:47.096Z","updated_at":"2025-04-10T01:08:08.519Z","avatar_url":"https://github.com/lazorfuzz.png","language":"JavaScript","readme":"# LioWebRTC\n\n[![NPM Downloads](https://img.shields.io/npm/dm/liowebrtc.svg)](https://www.npmjs.com/package/liowebrtc)\n\nA WebRTC library that makes it easy to embed scalable peer to peer communication into UI components.\n\nLioWebRTC works standalone, but it is also compatible with React, Vue, Electron, etc. It can be configured for scalability using partial mesh networks, making it possible to emit data to thousands of peers in a room, while only needing to be connected to at least one other peer in the room.\n\n[Click here](https://chatdemo.razorfart.com/) to see a chatroom demo built with LioWebRTC.\n\n[Click here](https://vchatdemo.razorfart.com/) to see a video conferencing demo app built with LioWebRTC.\n\n## Using LioWebRTC with React\nReact developers may want to take a look at [react-liowebrtc](https://github.com/lazorfuzz/react-liowebrtc).\n\n## Usage\n\n### Installation\n\n```js\nyarn add liowebrtc\n// Or\nnpm i liowebrtc\n```\n\n### Import LioWebRTC\n```js\nimport LioWebRTC from 'liowebrtc';\n```\n\n### Create LioWebRTC instance\nBy default, this enables video, audio, and data channels.\n```js\nconst webrtc = new LioWebRTC({\n    localVideoEl: localVideoIdOrRef, // The local video element\n    autoRequestMedia: true, // Immediately request camera and mic access upon initialization\n    debug: true, // Displays events emitted by liowebrtc in the console\n    url: 'https://your-signaling-server.com:443/' // The url for your signaling server. If no url is passed, liowebrtc uses the default demo signaling server. (The default server is for demo purposes only, and is not reliable. Plus, I'm the only one paying for it 🙁. Please use your own in production!)\n});\n```\n\n### Data channels only\nDisable video/audio streaming, and only allow data channels.\n```js\nconst webrtc = new LioWebRTC({\n    dataOnly: true\n});\n```\n\n### Audio and data channels only\nGreat for voice calls.\n```js\nconst webrtc = new LioWebRTC({\n    autoRequestMedia: true,\n    media: {\n        video: false,\n        audio: true\n    }\n});\n```\n\n### Partial mesh network\nPeers only form direct connections with a maximum of maxPeers and a minimum of minPeers. shout()ing still works because peers wil re-propagate messages to other peers. Note: partial mesh networks only work if you're only using `dataOnly`.\n```js\nconst webrtc = new LioWebRTC({\n  dataOnly: true,\n  network: {\n    maxPeers: 8,\n    minPeers: 4\n  }\n})\n```\n\n### Join a room once it's ready\n\n```js\nwebrtc.on('ready', () =\u003e {\n    // Joins a room if it exists, creates it if it doesn't\n    webrtc.joinRoom('your room name');\n});\n```\n\n### Emitting to the hive\nSometimes a peer wants to let every other peer in the room to know about something. This can be accomplished with\n```shout(messageType, payload)```\n```js\nwebrtc.shout('event-label', { success: true, payload: '137' });\n```\nNow for the recipients, handle the peer event with a listener:\n```js\nwebrtc.on('receivedPeerData', (type, data, peer) =\u003e {\n    if (type === 'event-label' \u0026\u0026 data.success) {\n        console.log(`Peer ${peer.id} emitted ${data.payload}`);\n    }\n});\n```\n\n### Communicating with a single peer\nSometimes a peer only wants to send data directly to another peer. This can be accomplished with\n```whisper(peer, messageType, payload)```\n```js\nwebrtc.whisper(peer, 'directMessage', { msg: 'Hello world!' });\n```\nReceiving the message is the same as handling a peer event:\n```js\nwebrtc.on('receivedPeerData', (type, data, peer) =\u003e {\n    if (type === 'directMessage') console.log(`Peer ${peer.id} says: ${data.msg}`);\n});\n```\n\n### Live-syncing state\n```js\ncomponentDidUpdate(prevProps, prevState) {\n    if (this.state.position !== prevState.position) {\n        this.webrtc.shout('stateUpdate', this.state);\n    }\n}\n});\n```\n\nAll communications via shout/whisper are sent over the default data channel and emitted by the LioWebRTC instance as events. You can create your own custom listeners suited for whatever purpose you'd like.\n\n### Attaching a peer's media stream to a video element\n```js\nwebrtc.on('peerStreamAdded', (stream, peer) =\u003e {\n    webrtc.attachStream(stream, yourVideoElementOrRef);\n});\n```\n\n###\n\n## Example\n\n### P2P Video Chat Component\n```jsx\nimport React, { Component } from 'react';\nimport LioWebRTC from 'liowebrtc';\n\nclass Party extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      nick: this.props.nick,\n      roomID: `party-${this.props.roomName}`,\n      muted: false,\n      camPaused: false,\n      peers: []\n    };\n    this.remoteVideos = {};\n  }\n\n  componentDidMount() {\n    this.webrtc = new LioWebRTC({\n      // The url for your signaling server. Use your own in production!\n      url: 'https://sm1.lio.app:443/',\n      // The local video ref set within your render function\n      localVideoEl: this.localVid,\n      // Immediately request camera access\n      autoRequestMedia: true,\n      // Optional: nickname\n      nick: this.state.nick,\n      debug: true\n    });\n\n    this.webrtc.on('peerStreamAdded', this.addVideo);\n    this.webrtc.on('removedPeer', this.removeVideo);\n    this.webrtc.on('ready', this.readyToJoin);\n    this.webrtc.on('iceFailed', this.handleConnectionError);\n    this.webrtc.on('connectivityError', this.handleConnectionError);\n  }\n\n  addVideo = (stream, peer) =\u003e {\n    this.setState({ peers: [...this.state.peers, peer] }, () =\u003e {\n      this.webrtc.attachStream(stream, this.remoteVideos[peer.id]);\n    });\n  }\n\n  removeVideo = (peer) =\u003e {\n    this.setState({\n      peers: this.state.peers.filter(p =\u003e !p.closed)\n    });\n  }\n\n  handleConnectionError = (peer) =\u003e {\n    const pc = peer.pc;\n    console.log('had local relay candidate', pc.hadLocalRelayCandidate);\n    console.log('had remote relay candidate', pc.hadRemoteRelayCandidate);\n  }\n\n  readyToJoin = () =\u003e {\n    // Starts the process of joining a room.\n    this.webrtc.joinRoom(this.state.roomID, (err, desc) =\u003e {\n    });\n  }\n\n  // Show fellow peers in the room\n  generateRemotes = () =\u003e this.state.peers.map((p) =\u003e (\n    \u003cdiv key={p.id}\u003e\n      \u003cdiv id={/* The video container needs a special id */ `${this.webrtc.getContainerId(p)}`}\u003e\n        \u003cvideo\n          // Important: The video element needs both an id and ref\n          id={this.webrtc.getDomId(p)}\n          ref={(v) =\u003e this.remoteVideos[p.id] = v}\n          /\u003e\n      \u003c/div\u003e\n        \u003cp\u003e{p.nick}\u003c/p\u003e\n    \u003c/div\u003e\n    ));\n\n  disconnect = () =\u003e {\n    this.webrtc.quit();\n  }\n\n  componentWillUnmount() {\n    this.disconnect();\n  }\n\n  render() {\n    return (\n      \u003cdiv\u003e\n        \u003cdiv\u003e\n            \u003cvideo\n              // Important: The local video element needs to have a ref\n              ref={(vid) =\u003e { this.localVid = vid; }}\n            /\u003e\n            \u003cp\u003e{this.state.nick}\u003c/p\u003e\n        \u003c/div\u003e\n        {this.generateRemotes()}\n      \u003c/div\u003e\n    );\n  }\n}\n\nexport default Party;\n\n```\n\n## API\n\n### Constructor Options\n\n`new LioWebRTC(options)`\n\n- `object options`\n  - `string url` - url for your socket.io signaling server\n  - `bool debug` - *optional* logs all webrtc events\n  - `string nick` - *optional* sets your nickname. Peers' nicknames can be accessed with `peer.nick`\n  - `[string|DomElement|Ref] localVideoEl` - Can be a ref, DOM element, or ID of the local video\n  - `bool autoRequestMedia` - *optional(=false)* automatically request\n  user media. Use `true` to request automatically, or `false` to request media\n  later with `startLocalVideo`\n  - `bool dataOnly` *optional(=false)* option to ensure that video and audio stream channels\n  are turned off\n  - `bool autoRemoveVideos` - *optional(=true)* option to automatically remove\n  video elements when streams are stopped.\n  - `bool adjustPeerVolume` - *optional(=true)* option to reduce peer volume\n  when the local participant is speaking\n  - `number peerVolumeWhenSpeaking` - *optional(=.0.25)* value used in\n  conjunction with `adjustPeerVolume`. Uses values between 0 and 1\n  - `object media` - media options to be passed to `getUserMedia`. Defaults to\n  `{ video: true, audio: true }`. Valid configurations described\n  [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia)\n  with official spec\n  [at w3c](http://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia).\n  - `object receiveMedia` - *optional* RTCPeerConnection options. Defaults to\n  `{ offerToReceiveAudio: 1, offerToReceiveVideo: 1 }`.\n  - `object localVideo` - *optional* options for attaching the local video\n  stream to the page. Defaults to\n  ```javascript\n  {\n      autoplay: true, // automatically play the video stream on the page\n      mirror: true, // flip the local video to mirror mode (for UX)\n      muted: true // mute local video stream to prevent echo\n  }\n  ```\n  - `object constraints` - *optional* options for setting minimum and maximum peers to connect to.\n  Defaults to\n  ```javascript\n  {\n    minPeers: 2, // connect to at least 2 peers\n    maxPeers: 0 // when 0, maxPeers is infinite\n  }\n  ```\n  - `bool selfOptimize` - *optional(=true)* whether or not peers in a partial mesh network should self-optimize their connections. LioWebRTC uses a more object-oriented version of an adjacency list to represent the p2p graph, with the weights of the edges representing roundtrip latency between two nodes. With `selfOptimize` set to true, peers automatically disconnect from neighbors with latencies \u003e=1 std. deviation from the mean, and reconnect to a new random peer.\n\n### Fields\n\n`connection` - the socket signaling connection\n\n`webrtc` - the underlying WebRTC session manager\n\n### Events\n\nTo set up event listeners, use the LioWebRTC instance created with the\nconstructor. Example:\n\n```js\n// Emitted when a peer's media stream becomes available\nthis.webrtc.on('peerStreamAdded', (stream, peer) =\u003e {\n    // Attach the MediaStream to a video element\n    // this.webrtc.attachStream(stream, this.remoteVideos[peer.id]);\n});\n// Emitted when we receive data from a peer via the data channel\nthis.webrtc.on('receivedPeerData', (type, payload, peer) =\u003e {\n    // Find something to do with the data\n});\n```\n`'channelOpen', RTCDataChannel, peer` - emitted when a new channel is established with a peer.\n\n`'connectionReady', sessionId` - emitted when the signaling connection emits the\n`connect` event, with the unique id for the session.\n\n`'createdPeer', peer` - this will be emitted when:\n- joining a room with existing peers, once for each peer\n- a new peer joins your room\n\n`'joinedRoom', roomName` - emitted after successfully joining a room.\n\n`'leftRoom', roomName` - emitted after successfully leaving the current room,\nending all peers, and stopping local stream\n\n`'mute', data` - emitted when a peer mutes their video or audioOn\n- `data` an object that contains an `id` property that returns the id of the peer, and a `name` property that indicates which stream was muted, `video` or `audio`\n\n`'removedPeer', peer` - emitted when a peer loses connection or exits the room\n- `peer` - the peer associated with the stream that was removed\n\n`'ready', sessionId` - emitted when liowebrtc is ready to join a room\n- `sessionId` - the socket.io connection session ID\n\n`'receivedPeerData', type, payload, peer` - emitted when data is received from a peer that sent the data with `shout` or `whisper`\n- `type` a label, usually a string, that describes the payload\n- `payload` any kind of data sent by the peer, usually an object\n- `peer` the object representing the peer and its peer connection\n\n`'receivedSignalData', type, payload, peer` - emitted when data is received from a peer that sent the data via the socket.io signaling server with `broadcast` or `transmit`\n- `type` a label, usually a string, that describes the payload\n- `payload` any kind of data sent by the peer, usually an object\n- `peer` the object representing the peer and its peer connection\n\n`'stunservers', [...args]` - emitted when the signaling server emits a list of stun servers.\n\n`'turnservers', [...args]` - emitted when the signaling server emits a list of turn servers.\n\n`'unmute', data` - emitted when a peer mutes their video or audioOn\n- `data` an object that contains an `id` property for the id of the peer that sent the event, and a `name` property that indicates which stream was muted, `video` or `audio`\n\n`'peerStreamAdded', stream, peer` - emitted when a peer's MediaStream becomes available\n- `stream` - the MediaStream associated with the peer\n- `peer` - the peer associated with the stream that was added\n\n`'peerStreamRemoved', peer` - emitted when a peer stream is removed\n- `peer` - the peer associated with the stream that was removed\n\n### Methods\n\n`attachStream(stream, el, opts)` - attaches a media stream to a video or audio element\n- `MediaStream stream` - an object representing a local or peer media stream\n- `HTMLElement el` - the element (or ref if you're using React) to attach the media stream to, usually a video or audio element\n- `object opts` - *optional* optional configuration for attachStream\n    - `bool autoplay` - autoplay the video once attached. Defaults to `true`\n    - `bool muted` - mute the video once attached. Defaults to `false`\n    - `bool mirror` - mirror the video once attached. Defaults to `true`\n    - `bool audio` - attach to `\u003caudio\u003e` element instead of `\u003cvideo\u003e` element. Defaults to `false`\n\n`broadcast(messageType, payload)` - broadcasts a message to all peers in the\nroom via the signaling server (similar to `shout`, but not p2p). Listen for peers' broadcasts on the `receivedSignalData` event.\n- `string messageType` an arbitrary label, usually a string, that describes the payload\n- `object payload` - an arbitrary value or object to send to peers\n\n`createRoom(name, callback)` - emits the `create` event and optionally invokes `callback` on response\n\n`disconnect()` - calls `disconnect` on the signaling connection and deletes it. Peers will still be available\n\n`emit(eventLabel, ...args)` - emit arbitrary event (Emits locally. To emit stuff other peers, use `shout`)\n\n`getClients((err, clients))` - asks the socket.io signaling server for a list of peers currently in the room.\n- `object clients` - An object whose keys are the client IDs and values are client types.\n\n`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\n- `Peer peer` - the object representing the peer and its peer connection\n\n`getMyId()` - get your own peer ID\n\n`getDomId(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.\n- `Peer peer` - the object representing the peer and its peer connection\n\n`getPeerById(id)` - returns a peer with a given `id`\n- `string id`  - the id of the peer\n\n`getPeerByNick(nick)` - returns a peer with a given `nick`\n- `string nick` - the peer's nickname\n\n`getPeers(sessionId)` - returns all peers by `sessionId`\n- `string sessionId` - the sid of the current room. Will return all peers if no sessionId is provided.\n\n`joinRoom(name, callback)` - joins the room `name`. Callback is\ninvoked with `callback(err, roomDescription)` where `roomDescription` is yielded\nby the connection on the `join` event. See [SignalBuddy](https://github.com/lazorfuzz/signalbuddy) for more info.\n\n`leaveRoom()` - leaves the currently joined room and stops local streams\n\n`mute()` - mutes the local audio stream to your peers (stops sending audio in the WebRTC audio channel)\n\n`on(ev, fn)` - creates an event listener for event `ev` handled by `fn`\n\n`pause()` - pauses both video and audio streams to your peers\n\n`pauseVideo()` - pauses the video stream to your peers (stops sending video in the WebRTC video channel)\n\n`quit()` - stops the local video, leaves the currently joined room, and disconnects from the signaling server\n\n`resume()` - resumes sending video and audio to your peers\n\n`resumeVideo()` - resumes the video stream to your peers (resumes sending video in the WebRTC video channel)\n\n`sendDirectlyToAll(messageType, payload, channel)` - sends a message\nto 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, e.g. a dedicated file-sharing channel, etc.)\n- `string channel` - (optional) the name of the data channel. If it doesn't exist, it will be created.\n\n`setVolumeForAll(volume)` - set the volume level for all peers\n\n`shout(messageType, payload)` - sends a message\nto all peers in the room via the default p2p data channel. Listen for peers' shouts on the `receivedPeerData` event.\n- `string messageType` - an arbitrary label, usually a string, that describes the payload\n- `object payload` - an arbitrary value or object to send to peers\n\n`startLocalVideo()` - starts the local video or audio streams with the `media` options provided\nin the config. Use this if `autoRequestMedia` is set to false\n\n`stopLocalVideo()` - stops all local media streams\n\n`transmit(peer, messageType, payload)` - sends a message to a single peer in the\nroom via the signaling server (similar to `whisper`, but not p2p). Listen for peers' transmissions on the `receivedSignalData` event.\n- `Peer peer` - the object representing the peer and its peer connection\n- `string messageType` - an arbitrary label, usually a string, that describes the payload\n- `object payload` - any kind of data sent by the peer, usually an object\n\n`unmute()` - unmutes the audio stream to your peers (resumes sending audio in the WebRTC audio channel)\n- `float volume` - the volume level, between 0 and 1\n\n`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.\n- `Peer peer` - the object representing the peer and its peer connection\n- `string messageType` - an arbitrary label, usually a string, that describes the payload\n- `object payload` - any kind of data sent by the peer, usually an object\n\n\n## Signaling\n\nWebRTC 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.\n\n[SignalBuddy](https://github.com/lazorfuzz/signalbuddy) is a scalable [socket.io](http://socket.io/) signaling server, 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.\n\nFor 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.\n\n### Connection\n\nLioWebRTC wraps socketio-client and returns a connection object. This the connection to the signaling server. The connection object comes with the following methods:\n\n- `on(ev, fn)` - a method to set a listener for event `ev`\n- `emit()` - send/emit arbitrary events on the connection\n- `getSessionId()` - returns the session ID of the connection\n- `disconnect()` - disconnect from the signaling server (closes the web socket)\n\n### Signaling Server Url\n\nLioWebRTC uses SignalBuddy to facilitate signaling. LioWebRTC works out of the box with a demo SignalBuddy server that was intended for testing purposes. However, for production purposes, IT IS NOT RELIABLE. In production, you will need to set up your own [SignalBuddy](https://github.com/lazorfuzz/signalbuddy) server (or any other socket.io solution that implements matchmaking).\n","funding_links":[],"categories":["Libraries"],"sub_categories":["JavaScript"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flazorfuzz%2Fliowebrtc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flazorfuzz%2Fliowebrtc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flazorfuzz%2Fliowebrtc/lists"}