Code Monkey home page Code Monkey logo

node-sdks's Introduction

The LiveKit icon, the name of the repository and some sample code in the background.

LiveKit Node SDKs

Use this SDK to add real-time video, audio and data features to your Node app. By connecting to a self- or cloud-hosted LiveKit server, you can quickly build applications like interactive live streaming or video calls with just a few lines of code.

Monorepo Navigation



Development Setup

If you are interested in contributing to the project or running the examples that are part of this mono-repository, then you must first set up your development environment.

Setup Monorepo

This repo consists of multiple packages that partly build on top of each other. It relies on pnpm workspaces and Turborepo (which gets installed automatically).

Clone the repo and run pnpm install the root level:

pnpm install

In order to link up initial dependencies and check whether everything has installed correctly run

pnpm build

This will build all the packages in /packages and the examples in /examples once.

After that you can use a more granular command to only rebuild the packages you are working on.


LiveKit Ecosystem
Real-time SDKsReact Components · Browser · iOS/macOS · Android · Flutter · React Native · Rust · Node.js · Python · Unity (web) · Unity (beta)
Server APIsNode.js · Golang · Ruby · Java/Kotlin · Python · Rust · PHP (community)
Agents FrameworksPython · Playground
ServicesLivekit server · Egress · Ingress · SIP
ResourcesDocs · Example apps · Cloud · Self-hosting · CLI

node-sdks's People

Contributors

davidzhao avatar lukasio avatar frostbyte73 avatar nbsp avatar renovate[bot] avatar theomonnom avatar github-actions[bot] avatar biglittlebigben avatar ocupe avatar dependabot[bot] avatar istorry avatar cacheonly avatar dennwc avatar dsa avatar skaldebane avatar lourd avatar neilkinnish avatar noahlt avatar shahriar-shojib avatar ws avatar m3t avatar moonrailgun avatar

Stargazers

Z avatar Eries Trisnadi avatar Madhu Bagroy avatar yufeng avatar tom zhou avatar Vladislav Severin avatar Hsiang avatar Kasemsan Chompuwised avatar Rubén avatar WhatIfDev avatar Travis Fischer avatar gabimoncha avatar  avatar KirPot05 avatar Bezalel Lim avatar  avatar DT avatar Melvin F avatar weishour avatar  avatar Alberto Cerasini avatar Mizutani avatar 飞天御剑流co avatar  avatar Lino Thomas avatar Daanish Rumani avatar Austin Cho avatar  avatar Jeffrey avatar Guille avatar Stephen M avatar Daniel Liu avatar wonjae.h avatar NERDDISCO avatar 湫曗 avatar  avatar Raja Subramanian avatar Onur Usluca avatar beeman avatar Ahmet ALTUN avatar Yuzuki Aida avatar KotikVacia avatar Michael Bawiec avatar Niranjan Anandkumar avatar  avatar Nymul Islam avatar April Mintac Pineda avatar Ibrahim Katari avatar  avatar leplay avatar  avatar Akinori Nakajima avatar  avatar footearth avatar  avatar esinanturan avatar Nay Lin Aung avatar Dane Medussa avatar Vojtěch Šimko avatar Sujith S Manjavana avatar Danilo Verde avatar Bishal Bhattarai avatar  avatar Julian avatar Dipesh Dulal avatar Rodan Ramdam avatar Romain GAGNAIRE avatar Adnan Ahmed avatar Petr Bela avatar Daniel Isaksen avatar Nick Mousavi avatar Govind Maheshwari avatar Mark avatar Jhony Alceu Pereira avatar yingshaoxo avatar Dan Sikes avatar leeing avatar soappanda avatar Kevin Shen avatar maiki avatar icxldd avatar Kim Hyunse avatar Juan Camilo Guarin Peñaranda avatar Lee avatar JSON avatar  avatar HeroSony avatar ebigram avatar Juk - a search builder avatar  avatar Felipe Menegazzi avatar  avatar daniel sieradski avatar  avatar Justin Sisley avatar Teerapat Prommarak avatar Marcus S. Abildskov avatar shalom.js avatar Lalit Kapoor avatar  avatar

Watchers

Paul Wells avatar  avatar  avatar  avatar shishirng avatar James Cloos avatar  avatar  avatar Neil Dwyer avatar  avatar  avatar Lukas Herman avatar  avatar

node-sdks's Issues

StartRecording throws an uncatchable axios error

I'm running livekit-server-sdk 0.5.9 and livekit-server v0.15.5 in service mode with redis

when I try to startRecording using the server-sdk-js and no recorders are available, I get a huge error being thrown by axios, that cannot be catched.

here's a snip of the code I use

'use strict';
const lksdk = require('livekit-server-sdk');
const RecordingServiceClient = require("livekit-server-sdk/dist/RecordingServiceClient").default
const RecordingTemplate = require('livekit-server-sdk/dist/proto/livekit_recording').RecordingTemplate;
const recService = new RecordingServiceClient("http://livekit:7880", process.env.LIVEKIT_API_KEY, process.env.LIVEKIT_API_SECRET);

async function startRecording(roomName) {
  const filename = roomName + ".mp4";
  const tpl = RecordingTemplate.fromJSON({
    layout: "grid-dark",
    roomName: roomName,
  });

  try {
    await recService.startRecording(tpl, filename);
  } catch (e) {
    console.log("error recording:", e);
  }
}

the error being thrown by axios is not catched at all, even though I startRecording() in a try/catch block

here's the complete error I get (it's huge)
 /app/node_modules/axios/lib/core/createError.js:16
   var error = new Error(message);
               ^

 Error: Request failed with status code 500
     at createError (/app/node_modules/axios/lib/core/createError.js:16:15)
     at settle (/app/node_modules/axios/lib/core/settle.js:17:12)
     at IncomingMessage.handleStreamEnd (/app/node_modules/axios/lib/adapters/http.js:269:11)
     at IncomingMessage.emit (node:events:402:35)
     at endReadableNT (node:internal/streams/readable:1343:12)
     at processTicksAndRejections (node:internal/process/task_queues:83:21) {
   config: {
     url: '/twirp/livekit.RecordingService/StartRecording',
     method: 'post',
     data: '{"template":{"layout":"grid-dark","roomName":"NT0C5SD2HCWS5KO8SHJEO","baseUrl":""},"filepath":"NT0C5SD2HCWS5KO8SHJEO.mp4"}',
     headers: {
       Accept: 'application/json, text/plain, */*',
       'Content-Type': 'application/json',
       Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0',
       'User-Agent': 'axios/0.21.4',
       'Content-Length': 122
     },
     baseURL: 'http://livekit:7880',
     transformRequest: [ [Function: transformRequest] ],
     transformResponse: [ [Function: transformResponse] ],
     timeout: 0,
     adapter: [Function: httpAdapter],
     xsrfCookieName: 'XSRF-TOKEN',
     xsrfHeaderName: 'X-XSRF-TOKEN',
     maxContentLength: -1,
     maxBodyLength: -1,
     validateStatus: [Function: validateStatus],
     transitional: {
       silentJSONParsing: true,
       forcedJSONParsing: true,
       clarifyTimeoutError: false
     }
   },
   request: <ref *1> ClientRequest {
     _events: [Object: null prototype] {
       abort: [Function (anonymous)],
       aborted: [Function (anonymous)],
       connect: [Function (anonymous)],
       error: [Function (anonymous)],
       socket: [Function (anonymous)],
       timeout: [Function (anonymous)],
       prefinish: [Function: requestOnPrefinish]
     },
     _eventsCount: 7,
     _maxListeners: undefined,
     outputData: [],
     outputSize: 0,
     writable: true,
     destroyed: false,
     _last: true,
     chunkedEncoding: false,
     shouldKeepAlive: false,
     maxRequestsOnConnectionReached: false,
     _defaultKeepAlive: true,
     useChunkedEncodingByDefault: true,
     sendDate: false,
     _removedConnection: false,
     _removedContLen: false,
     _removedTE: false,
     _contentLength: null,
     _hasBody: true,
     _trailer: '',
     finished: true,
     _headerSent: true,
     _closed: false,
     socket: <ref *2> Socket {
       connecting: false,
       _hadError: false,
       _parent: null,
       _host: 'livekit',
       _readableState: ReadableState {
         objectMode: false,
         highWaterMark: 16384,
         buffer: BufferList { head: null, tail: null, length: 0 },
         length: 0,
         pipes: [],
         flowing: true,
         ended: false,
         endEmitted: false,
         reading: true,
         constructed: true,
         sync: false,
         needReadable: true,
         emittedReadable: false,
         readableListening: false,
         resumeScheduled: false,
         errorEmitted: false,
         emitClose: false,
         autoDestroy: true,
         destroyed: false,
         errored: null,
         closed: false,
         closeEmitted: false,
         defaultEncoding: 'utf8',
         awaitDrainWriters: null,
         multiAwaitDrain: false,
         readingMore: false,
         dataEmitted: true,
         decoder: null,
         encoding: null,
         [Symbol(kPaused)]: false
       },
       _events: [Object: null prototype] {
         end: [Function: onReadableStreamEnd],
         free: [Function: onFree],
         close: [ [Function: onClose], [Function: socketCloseListener] ],
         timeout: [Function: onTimeout],
         agentRemove: [Function: onRemove],
         error: [Function: socketErrorListener],
         finish: [Function: bound onceWrapper] { listener: [Function: destroy] }
       },
       _eventsCount: 7,
       _maxListeners: undefined,
       _writableState: WritableState {
         objectMode: false,
         highWaterMark: 16384,
         finalCalled: true,
         needDrain: false,
         ending: true,
         ended: true,
         finished: false,
         destroyed: false,
         decodeStrings: false,
         defaultEncoding: 'utf8',
         length: 0,
         writing: false,
         corked: 0,
         sync: false,
         bufferProcessing: false,
         onwrite: [Function: bound onwrite],
         writecb: null,
         writelen: 0,
         afterWriteTickInfo: null,
         buffered: [],
         bufferedIndex: 0,
         allBuffers: true,
         allNoop: true,
         pendingcb: 1,
         constructed: true,
         prefinished: false,
         errorEmitted: false,
         emitClose: false,
         autoDestroy: true,
         errored: null,
         closed: false,
         closeEmitted: false,
         [Symbol(kOnFinished)]: []
       },
       allowHalfOpen: false,
       _sockname: null,
       _pendingData: null,
       _pendingEncoding: '',
       server: null,
       _server: null,
       parser: null,
       _httpMessage: [Circular *1],
       [Symbol(async_id_symbol)]: 282,
       [Symbol(kHandle)]: TCP {
         reading: true,
         onconnection: null,
         [Symbol(owner_symbol)]: [Circular *2]
       },
       [Symbol(kSetNoDelay)]: false,
       [Symbol(lastWriteQueueSize)]: 0,
       [Symbol(timeout)]: null,
       [Symbol(kBuffer)]: null,
       [Symbol(kBufferCb)]: null,
       [Symbol(kBufferGen)]: null,
       [Symbol(kCapture)]: false,
       [Symbol(kBytesRead)]: 0,
       [Symbol(kBytesWritten)]: 0,
       [Symbol(RequestTimeout)]: undefined
     },
     _header: 'POST /twirp/livekit.RecordingService/StartRecording HTTP/1.1\r\n' +
       'Accept: application/json, text/plain, */*\r\n' +
       'Content-Type: application/json\r\n' +
       'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0\r\n' +
       'User-Agent: axios/0.21.4\r\n' +
       'Content-Length: 122\r\n' +
       'Host: livekit:7880\r\n' +
       'Connection: close\r\n' +
       '\r\n',
     _keepAliveTimeout: 0,
     _onPendingData: [Function: nop],
     agent: Agent {
       _events: [Object: null prototype] {
         free: [Function (anonymous)],
         newListener: [Function: maybeEnableKeylog]
       },
       _eventsCount: 2,
       _maxListeners: undefined,
       defaultPort: 80,
       protocol: 'http:',
       options: [Object: null prototype] { path: null },
       requests: [Object: null prototype] {},
       sockets: [Object: null prototype] {
         'livekit:7880:': [
           <ref *2> Socket {
             connecting: false,
             _hadError: false,
             _parent: null,
             _host: 'livekit',
             _readableState: [ReadableState],
             _events: [Object: null prototype],
             _eventsCount: 7,
             _maxListeners: undefined,
             _writableState: [WritableState],
             allowHalfOpen: false,
             _sockname: null,
             _pendingData: null,
             _pendingEncoding: '',
             server: null,
             _server: null,
             parser: null,
             _httpMessage: [Circular *1],
             [Symbol(async_id_symbol)]: 282,
             [Symbol(kHandle)]: [TCP],
             [Symbol(kSetNoDelay)]: false,
             [Symbol(lastWriteQueueSize)]: 0,
             [Symbol(timeout)]: null,
             [Symbol(kBuffer)]: null,
             [Symbol(kBufferCb)]: null,
             [Symbol(kBufferGen)]: null,
             [Symbol(kCapture)]: false,
             [Symbol(kBytesRead)]: 0,
             [Symbol(kBytesWritten)]: 0,
             [Symbol(RequestTimeout)]: undefined
           }
         ]
       },
       freeSockets: [Object: null prototype] {},
       keepAliveMsecs: 1000,
       keepAlive: false,
       maxSockets: Infinity,
       maxFreeSockets: 256,
       scheduling: 'lifo',
       maxTotalSockets: Infinity,
       totalSocketCount: 1,
       [Symbol(kCapture)]: false
     },
     socketPath: undefined,
     method: 'POST',
     maxHeaderSize: undefined,
     insecureHTTPParser: undefined,
     path: '/twirp/livekit.RecordingService/StartRecording',
     _ended: true,
     res: IncomingMessage {
       _readableState: ReadableState {
         objectMode: false,
         highWaterMark: 16384,
         buffer: BufferList { head: null, tail: null, length: 0 },
         length: 0,
         pipes: [],
         flowing: true,
         ended: true,
         endEmitted: true,
         reading: false,
         constructed: true,
         sync: true,
         needReadable: false,
         emittedReadable: false,
         readableListening: false,
         resumeScheduled: false,
         errorEmitted: false,
         emitClose: true,
         autoDestroy: true,
         destroyed: true,
         errored: null,
         closed: true,
         closeEmitted: true,
         defaultEncoding: 'utf8',
         awaitDrainWriters: null,
         multiAwaitDrain: false,
         readingMore: true,
         dataEmitted: true,
         decoder: null,
         encoding: null,
         [Symbol(kPaused)]: false
       },
       _events: [Object: null prototype] {
         end: [ [Function: responseOnEnd], [Function: handleStreamEnd] ],
         data: [Function: handleStreamData],
         error: [Function: handleStreamError]
       },
       _eventsCount: 3,
       _maxListeners: undefined,
       socket: <ref *2> Socket {
         connecting: false,
         _hadError: false,
         _parent: null,
         _host: 'livekit',
         _readableState: ReadableState {
           objectMode: false,
           highWaterMark: 16384,
           buffer: BufferList { head: null, tail: null, length: 0 },
           length: 0,
           pipes: [],
           flowing: true,
           ended: false,
           endEmitted: false,
           reading: true,
           constructed: true,
           sync: false,
           needReadable: true,
           emittedReadable: false,
           readableListening: false,
           resumeScheduled: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           destroyed: false,
           errored: null,
           closed: false,
           closeEmitted: false,
           defaultEncoding: 'utf8',
           awaitDrainWriters: null,
           multiAwaitDrain: false,
           readingMore: false,
           dataEmitted: true,
           decoder: null,
           encoding: null,
           [Symbol(kPaused)]: false
         },
         _events: [Object: null prototype] {
           end: [Function: onReadableStreamEnd],
           free: [Function: onFree],
           close: [ [Function: onClose], [Function: socketCloseListener] ],
           timeout: [Function: onTimeout],
           agentRemove: [Function: onRemove],
           error: [Function: socketErrorListener],
           finish: [Function: bound onceWrapper] {
             listener: [Function: destroy]
           }
         },
         _eventsCount: 7,
         _maxListeners: undefined,
         _writableState: WritableState {
           objectMode: false,
           highWaterMark: 16384,
           finalCalled: true,
           needDrain: false,
           ending: true,
           ended: true,
           finished: false,
           destroyed: false,
           decodeStrings: false,
           defaultEncoding: 'utf8',
           length: 0,
           writing: false,
           corked: 0,
           sync: false,
           bufferProcessing: false,
           onwrite: [Function: bound onwrite],
           writecb: null,
           writelen: 0,
           afterWriteTickInfo: null,
           buffered: [],
           bufferedIndex: 0,
           allBuffers: true,
           allNoop: true,
           pendingcb: 1,
           constructed: true,
           prefinished: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           errored: null,
           closed: false,
           closeEmitted: false,
           [Symbol(kOnFinished)]: []
         },
         allowHalfOpen: false,
         _sockname: null,
         _pendingData: null,
         _pendingEncoding: '',
         server: null,
         _server: null,
         parser: null,
         _httpMessage: [Circular *1],
         [Symbol(async_id_symbol)]: 282,
         [Symbol(kHandle)]: TCP {
           reading: true,
           onconnection: null,
           [Symbol(owner_symbol)]: [Circular *2]
         },
         [Symbol(kSetNoDelay)]: false,
         [Symbol(lastWriteQueueSize)]: 0,
         [Symbol(timeout)]: null,
         [Symbol(kBuffer)]: null,
         [Symbol(kBufferCb)]: null,
         [Symbol(kBufferGen)]: null,
         [Symbol(kCapture)]: false,
         [Symbol(kBytesRead)]: 0,
         [Symbol(kBytesWritten)]: 0,
         [Symbol(RequestTimeout)]: undefined
       },
       httpVersionMajor: 1,
       httpVersionMinor: 1,
       httpVersion: '1.1',
       complete: true,
       rawHeaders: [
         'Content-Length',
         '89',
         'Content-Type',
         'application/json',
         'Vary',
         'Origin',
         'Date',
         'Thu, 03 Mar 2022 07:27:41 GMT',
         'Connection',
         'close'
       ],
       rawTrailers: [],
       aborted: false,
       upgrade: false,
       url: '',
       method: null,
       statusCode: 500,
       statusMessage: 'Internal Server Error',
       client: <ref *2> Socket {
         connecting: false,
         _hadError: false,
         _parent: null,
         _host: 'livekit',
         _readableState: ReadableState {
           objectMode: false,
           highWaterMark: 16384,
           buffer: BufferList { head: null, tail: null, length: 0 },
           length: 0,
           pipes: [],
           flowing: true,
           ended: false,
           endEmitted: false,
           reading: true,
           constructed: true,
           sync: false,
           needReadable: true,
           emittedReadable: false,
           readableListening: false,
           resumeScheduled: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           destroyed: false,
           errored: null,
           closed: false,
           closeEmitted: false,
           defaultEncoding: 'utf8',
           awaitDrainWriters: null,
           multiAwaitDrain: false,
           readingMore: false,
           dataEmitted: true,
           decoder: null,
           encoding: null,
           [Symbol(kPaused)]: false
         },
         _events: [Object: null prototype] {
           end: [Function: onReadableStreamEnd],
           free: [Function: onFree],
           close: [ [Function: onClose], [Function: socketCloseListener] ],
           timeout: [Function: onTimeout],
           agentRemove: [Function: onRemove],
           error: [Function: socketErrorListener],
           finish: [Function: bound onceWrapper] {
             listener: [Function: destroy]
           }
         },
         _eventsCount: 7,
         _maxListeners: undefined,
         _writableState: WritableState {
           objectMode: false,
           highWaterMark: 16384,
           finalCalled: true,
           needDrain: false,
           ending: true,
           ended: true,
           finished: false,
           destroyed: false,
           decodeStrings: false,
           defaultEncoding: 'utf8',
           length: 0,
           writing: false,
           corked: 0,
           sync: false,
           bufferProcessing: false,
           onwrite: [Function: bound onwrite],
           writecb: null,
           writelen: 0,
           afterWriteTickInfo: null,
           buffered: [],
           bufferedIndex: 0,
           allBuffers: true,
           allNoop: true,
           pendingcb: 1,
           constructed: true,
           prefinished: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           errored: null,
           closed: false,
           closeEmitted: false,
           [Symbol(kOnFinished)]: []
         },
         allowHalfOpen: false,
         _sockname: null,
         _pendingData: null,
         _pendingEncoding: '',
         server: null,
         _server: null,
         parser: null,
         _httpMessage: [Circular *1],
         [Symbol(async_id_symbol)]: 282,
         [Symbol(kHandle)]: TCP {
           reading: true,
           onconnection: null,
           [Symbol(owner_symbol)]: [Circular *2]
         },
         [Symbol(kSetNoDelay)]: false,
         [Symbol(lastWriteQueueSize)]: 0,
         [Symbol(timeout)]: null,
         [Symbol(kBuffer)]: null,
         [Symbol(kBufferCb)]: null,
         [Symbol(kBufferGen)]: null,
         [Symbol(kCapture)]: false,
         [Symbol(kBytesRead)]: 0,
         [Symbol(kBytesWritten)]: 0,
         [Symbol(RequestTimeout)]: undefined
       },
       _consuming: false,
       _dumped: false,
       req: [Circular *1],
       responseUrl: 'http://livekit:7880/twirp/livekit.RecordingService/StartRecording',
       redirects: [],
       [Symbol(kCapture)]: false,
       [Symbol(kHeaders)]: {
         'content-length': '89',
         'content-type': 'application/json',
         vary: 'Origin',
         date: 'Thu, 03 Mar 2022 07:27:41 GMT',
         connection: 'close'
       },
       [Symbol(kHeadersCount)]: 10,
       [Symbol(kTrailers)]: null,
       [Symbol(kTrailersCount)]: 0,
       [Symbol(RequestTimeout)]: undefined
     },
     aborted: false,
     timeoutCb: null,
     upgradeOrConnect: false,
     parser: null,
     maxHeadersCount: null,
     reusedSocket: false,
     host: 'livekit',
     protocol: 'http:',
     _redirectable: Writable {
       _writableState: WritableState {
         objectMode: false,
         highWaterMark: 16384,
         finalCalled: false,
         needDrain: false,
         ending: false,
         ended: false,
         finished: false,
         destroyed: false,
         decodeStrings: true,
         defaultEncoding: 'utf8',
         length: 0,
         writing: false,
         corked: 0,
         sync: true,
         bufferProcessing: false,
         onwrite: [Function: bound onwrite],
         writecb: null,
         writelen: 0,
         afterWriteTickInfo: null,
         buffered: [],
         bufferedIndex: 0,
         allBuffers: true,
         allNoop: true,
         pendingcb: 0,
         constructed: true,
         prefinished: false,
         errorEmitted: false,
         emitClose: true,
         autoDestroy: true,
         errored: null,
         closed: false,
         closeEmitted: false,
         [Symbol(kOnFinished)]: []
       },
       _events: [Object: null prototype] {
         response: [Function: handleResponse],
         error: [Function: handleRequestError]
       },
       _eventsCount: 2,
       _maxListeners: undefined,
       _options: {
         maxRedirects: 21,
         maxBodyLength: 10485760,
         protocol: 'http:',
         path: '/twirp/livekit.RecordingService/StartRecording',
         method: 'POST',
         headers: {
           Accept: 'application/json, text/plain, */*',
           'Content-Type': 'application/json',
           Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0',
           'User-Agent': 'axios/0.21.4',
           'Content-Length': 122
         },
         agent: undefined,
         agents: { http: undefined, https: undefined },
         auth: undefined,
         hostname: 'livekit',
         port: '7880',
         nativeProtocols: {
           'http:': {
             _connectionListener: [Function: connectionListener],
             METHODS: [Array],
             STATUS_CODES: [Object],
             Agent: [Function],
             ClientRequest: [Function: ClientRequest],
             IncomingMessage: [Function: IncomingMessage],
             OutgoingMessage: [Function: OutgoingMessage],
             Server: [Function: Server],
             ServerResponse: [Function: ServerResponse],
             createServer: [Function: createServer],
             validateHeaderName: [Function: __node_internal_],
             validateHeaderValue: [Function: __node_internal_],
             get: [Function: get],
             request: [Function: request],
             maxHeaderSize: [Getter],
             globalAgent: [Getter/Setter]
           },
           'https:': {
             Agent: [Function: Agent],
             globalAgent: [Agent],
             Server: [Function: Server],
             createServer: [Function: createServer],
             get: [Function: get],
             request: [Function: request]
           }
         },
         pathname: '/twirp/livekit.RecordingService/StartRecording'
       },
       _ended: true,
       _ending: true,
       _redirectCount: 0,
       _redirects: [],
       _requestBodyLength: 122,
       _requestBodyBuffers: [],
       _onNativeResponse: [Function (anonymous)],
       _currentRequest: [Circular *1],
       _currentUrl: 'http://livekit:7880/twirp/livekit.RecordingService/StartRecording',
       [Symbol(kCapture)]: false
     },
     [Symbol(kCapture)]: false,
     [Symbol(kNeedDrain)]: false,
     [Symbol(corked)]: 0,
     [Symbol(kOutHeaders)]: [Object: null prototype] {
       accept: [ 'Accept', 'application/json, text/plain, */*' ],
       'content-type': [ 'Content-Type', 'application/json' ],
       authorization: [
         'Authorization',
         'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0'
       ],
       'user-agent': [ 'User-Agent', 'axios/0.21.4' ],
       'content-length': [ 'Content-Length', 122 ],
       host: [ 'Host', 'livekit:7880' ]
     }
   },
   response: {
     status: 500,
     statusText: 'Internal Server Error',
     headers: {
       'content-length': '89',
       'content-type': 'application/json',
       vary: 'Origin',
       date: 'Thu, 03 Mar 2022 07:27:41 GMT',
       connection: 'close'
     },
     config: {
       url: '/twirp/livekit.RecordingService/StartRecording',
       method: 'post',
       data: '{"template":{"layout":"grid-dark","roomName":"NT0C5SD2HCWS5KO8SHJEO","baseUrl":""},"filepath":"NT0C5SD2HCWS5KO8SHJEO.mp4"}',
       headers: {
         Accept: 'application/json, text/plain, */*',
         'Content-Type': 'application/json',
         Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0',
         'User-Agent': 'axios/0.21.4',
         'Content-Length': 122
       },
       baseURL: 'http://livekit:7880',
       transformRequest: [ [Function: transformRequest] ],
       transformResponse: [ [Function: transformResponse] ],
       timeout: 0,
       adapter: [Function: httpAdapter],
       xsrfCookieName: 'XSRF-TOKEN',
       xsrfHeaderName: 'X-XSRF-TOKEN',
       maxContentLength: -1,
       maxBodyLength: -1,
       validateStatus: [Function: validateStatus],
       transitional: {
         silentJSONParsing: true,
         forcedJSONParsing: true,
         clarifyTimeoutError: false
       }
     },
     request: <ref *1> ClientRequest {
       _events: [Object: null prototype] {
         abort: [Function (anonymous)],
         aborted: [Function (anonymous)],
         connect: [Function (anonymous)],
         error: [Function (anonymous)],
         socket: [Function (anonymous)],
         timeout: [Function (anonymous)],
         prefinish: [Function: requestOnPrefinish]
       },
       _eventsCount: 7,
       _maxListeners: undefined,
       outputData: [],
       outputSize: 0,
       writable: true,
       destroyed: false,
       _last: true,
       chunkedEncoding: false,
       shouldKeepAlive: false,
       maxRequestsOnConnectionReached: false,
       _defaultKeepAlive: true,
       useChunkedEncodingByDefault: true,
       sendDate: false,
       _removedConnection: false,
       _removedContLen: false,
       _removedTE: false,
       _contentLength: null,
       _hasBody: true,
       _trailer: '',
       finished: true,
       _headerSent: true,
       _closed: false,
       socket: <ref *2> Socket {
         connecting: false,
         _hadError: false,
         _parent: null,
         _host: 'livekit',
         _readableState: ReadableState {
           objectMode: false,
           highWaterMark: 16384,
           buffer: BufferList { head: null, tail: null, length: 0 },
           length: 0,
           pipes: [],
           flowing: true,
           ended: false,
           endEmitted: false,
           reading: true,
           constructed: true,
           sync: false,
           needReadable: true,
           emittedReadable: false,
           readableListening: false,
           resumeScheduled: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           destroyed: false,
           errored: null,
           closed: false,
           closeEmitted: false,
           defaultEncoding: 'utf8',
           awaitDrainWriters: null,
           multiAwaitDrain: false,
           readingMore: false,
           dataEmitted: true,
           decoder: null,
           encoding: null,
           [Symbol(kPaused)]: false
         },
         _events: [Object: null prototype] {
           end: [Function: onReadableStreamEnd],
           free: [Function: onFree],
           close: [ [Function: onClose], [Function: socketCloseListener] ],
           timeout: [Function: onTimeout],
           agentRemove: [Function: onRemove],
           error: [Function: socketErrorListener],
           finish: [Function: bound onceWrapper] {
             listener: [Function: destroy]
           }
         },
         _eventsCount: 7,
         _maxListeners: undefined,
         _writableState: WritableState {
           objectMode: false,
           highWaterMark: 16384,
           finalCalled: true,
           needDrain: false,
           ending: true,
           ended: true,
           finished: false,
           destroyed: false,
           decodeStrings: false,
           defaultEncoding: 'utf8',
           length: 0,
           writing: false,
           corked: 0,
           sync: false,
           bufferProcessing: false,
           onwrite: [Function: bound onwrite],
           writecb: null,
           writelen: 0,
           afterWriteTickInfo: null,
           buffered: [],
           bufferedIndex: 0,
           allBuffers: true,
           allNoop: true,
           pendingcb: 1,
           constructed: true,
           prefinished: false,
           errorEmitted: false,
           emitClose: false,
           autoDestroy: true,
           errored: null,
           closed: false,
           closeEmitted: false,
           [Symbol(kOnFinished)]: []
         },
         allowHalfOpen: false,
         _sockname: null,
         _pendingData: null,
         _pendingEncoding: '',
         server: null,
         _server: null,
         parser: null,
         _httpMessage: [Circular *1],
         [Symbol(async_id_symbol)]: 282,
         [Symbol(kHandle)]: TCP {
           reading: true,
           onconnection: null,
           [Symbol(owner_symbol)]: [Circular *2]
         },
         [Symbol(kSetNoDelay)]: false,
         [Symbol(lastWriteQueueSize)]: 0,
         [Symbol(timeout)]: null,
         [Symbol(kBuffer)]: null,
         [Symbol(kBufferCb)]: null,
         [Symbol(kBufferGen)]: null,
         [Symbol(kCapture)]: false,
         [Symbol(kBytesRead)]: 0,
         [Symbol(kBytesWritten)]: 0,
         [Symbol(RequestTimeout)]: undefined
       },
       _header: 'POST /twirp/livekit.RecordingService/StartRecording HTTP/1.1\r\n' +
         'Accept: application/json, text/plain, */*\r\n' +
         'Content-Type: application/json\r\n' +
         'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0\r\n' +
         'User-Agent: axios/0.21.4\r\n' +
         'Content-Length: 122\r\n' +
         'Host: livekit:7880\r\n' +
         'Connection: close\r\n' +
         '\r\n',
       _keepAliveTimeout: 0,
       _onPendingData: [Function: nop],
       agent: Agent {
         _events: [Object: null prototype] {
           free: [Function (anonymous)],
           newListener: [Function: maybeEnableKeylog]
         },
         _eventsCount: 2,
         _maxListeners: undefined,
         defaultPort: 80,
         protocol: 'http:',
         options: [Object: null prototype] { path: null },
         requests: [Object: null prototype] {},
         sockets: [Object: null prototype] { 'livekit:7880:': [ [Socket] ] },
         freeSockets: [Object: null prototype] {},
         keepAliveMsecs: 1000,
         keepAlive: false,
         maxSockets: Infinity,
         maxFreeSockets: 256,
         scheduling: 'lifo',
         maxTotalSockets: Infinity,
         totalSocketCount: 1,
         [Symbol(kCapture)]: false
       },
       socketPath: undefined,
       method: 'POST',
       maxHeaderSize: undefined,
       insecureHTTPParser: undefined,
       path: '/twirp/livekit.RecordingService/StartRecording',
       _ended: true,
       res: IncomingMessage {
         _readableState: ReadableState {
           objectMode: false,
           highWaterMark: 16384,
           buffer: BufferList { head: null, tail: null, length: 0 },
           length: 0,
           pipes: [],
           flowing: true,
           ended: true,
           endEmitted: true,
           reading: false,
           constructed: true,
           sync: true,
           needReadable: false,
           emittedReadable: false,
           readableListening: false,
           resumeScheduled: false,
           errorEmitted: false,
           emitClose: true,
           autoDestroy: true,
           destroyed: true,
           errored: null,
           closed: true,
           closeEmitted: true,
           defaultEncoding: 'utf8',
           awaitDrainWriters: null,
           multiAwaitDrain: false,
           readingMore: true,
           dataEmitted: true,
           decoder: null,
           encoding: null,
           [Symbol(kPaused)]: false
         },
         _events: [Object: null prototype] {
           end: [ [Function: responseOnEnd], [Function: handleStreamEnd] ],
           data: [Function: handleStreamData],
           error: [Function: handleStreamError]
         },
         _eventsCount: 3,
         _maxListeners: undefined,
         socket: <ref *2> Socket {
           connecting: false,
           _hadError: false,
           _parent: null,
           _host: 'livekit',
           _readableState: ReadableState {
             objectMode: false,
             highWaterMark: 16384,
             buffer: [BufferList],
             length: 0,
             pipes: [],
             flowing: true,
             ended: false,
             endEmitted: false,
             reading: true,
             constructed: true,
             sync: false,
             needReadable: true,
             emittedReadable: false,
             readableListening: false,
             resumeScheduled: false,
             errorEmitted: false,
             emitClose: false,
             autoDestroy: true,
             destroyed: false,
             errored: null,
             closed: false,
             closeEmitted: false,
             defaultEncoding: 'utf8',
             awaitDrainWriters: null,
             multiAwaitDrain: false,
             readingMore: false,
             dataEmitted: true,
             decoder: null,
             encoding: null,
             [Symbol(kPaused)]: false
           },
           _events: [Object: null prototype] {
             end: [Function: onReadableStreamEnd],
             free: [Function: onFree],
             close: [Array],
             timeout: [Function: onTimeout],
             agentRemove: [Function: onRemove],
             error: [Function: socketErrorListener],
             finish: [Function]
           },
           _eventsCount: 7,
           _maxListeners: undefined,
           _writableState: WritableState {
             objectMode: false,
             highWaterMark: 16384,
             finalCalled: true,
             needDrain: false,
             ending: true,
             ended: true,
             finished: false,
             destroyed: false,
             decodeStrings: false,
             defaultEncoding: 'utf8',
             length: 0,
             writing: false,
             corked: 0,
             sync: false,
             bufferProcessing: false,
             onwrite: [Function: bound onwrite],
             writecb: null,
             writelen: 0,
             afterWriteTickInfo: null,
             buffered: [],
             bufferedIndex: 0,
             allBuffers: true,
             allNoop: true,
             pendingcb: 1,
             constructed: true,
             prefinished: false,
             errorEmitted: false,
             emitClose: false,
             autoDestroy: true,
             errored: null,
             closed: false,
             closeEmitted: false,
             [Symbol(kOnFinished)]: []
           },
           allowHalfOpen: false,
           _sockname: null,
           _pendingData: null,
           _pendingEncoding: '',
           server: null,
           _server: null,
           parser: null,
           _httpMessage: [Circular *1],
           [Symbol(async_id_symbol)]: 282,
           [Symbol(kHandle)]: TCP {
             reading: true,
             onconnection: null,
             [Symbol(owner_symbol)]: [Circular *2]
           },
           [Symbol(kSetNoDelay)]: false,
           [Symbol(lastWriteQueueSize)]: 0,
           [Symbol(timeout)]: null,
           [Symbol(kBuffer)]: null,
           [Symbol(kBufferCb)]: null,
           [Symbol(kBufferGen)]: null,
           [Symbol(kCapture)]: false,
           [Symbol(kBytesRead)]: 0,
           [Symbol(kBytesWritten)]: 0,
           [Symbol(RequestTimeout)]: undefined
         },
         httpVersionMajor: 1,
         httpVersionMinor: 1,
         httpVersion: '1.1',
         complete: true,
         rawHeaders: [
           'Content-Length',
           '89',
           'Content-Type',
           'application/json',
           'Vary',
           'Origin',
           'Date',
           'Thu, 03 Mar 2022 07:27:41 GMT',
           'Connection',
           'close'
         ],
         rawTrailers: [],
         aborted: false,
         upgrade: false,
         url: '',
         method: null,
         statusCode: 500,
         statusMessage: 'Internal Server Error',
         client: <ref *2> Socket {
           connecting: false,
           _hadError: false,
           _parent: null,
           _host: 'livekit',
           _readableState: ReadableState {
             objectMode: false,
             highWaterMark: 16384,
             buffer: [BufferList],
             length: 0,
             pipes: [],
             flowing: true,
             ended: false,
             endEmitted: false,
             reading: true,
             constructed: true,
             sync: false,
             needReadable: true,
             emittedReadable: false,
             readableListening: false,
             resumeScheduled: false,
             errorEmitted: false,
             emitClose: false,
             autoDestroy: true,
             destroyed: false,
             errored: null,
             closed: false,
             closeEmitted: false,
             defaultEncoding: 'utf8',
             awaitDrainWriters: null,
             multiAwaitDrain: false,
             readingMore: false,
             dataEmitted: true,
             decoder: null,
             encoding: null,
             [Symbol(kPaused)]: false
           },
           _events: [Object: null prototype] {
             end: [Function: onReadableStreamEnd],
             free: [Function: onFree],
             close: [Array],
             timeout: [Function: onTimeout],
             agentRemove: [Function: onRemove],
             error: [Function: socketErrorListener],
             finish: [Function]
           },
           _eventsCount: 7,
           _maxListeners: undefined,
           _writableState: WritableState {
             objectMode: false,
             highWaterMark: 16384,
             finalCalled: true,
             needDrain: false,
             ending: true,
             ended: true,
             finished: false,
             destroyed: false,
             decodeStrings: false,
             defaultEncoding: 'utf8',
             length: 0,
             writing: false,
             corked: 0,
             sync: false,
             bufferProcessing: false,
             onwrite: [Function: bound onwrite],
             writecb: null,
             writelen: 0,
             afterWriteTickInfo: null,
             buffered: [],
             bufferedIndex: 0,
             allBuffers: true,
             allNoop: true,
             pendingcb: 1,
             constructed: true,
             prefinished: false,
             errorEmitted: false,
             emitClose: false,
             autoDestroy: true,
             errored: null,
             closed: false,
             closeEmitted: false,
             [Symbol(kOnFinished)]: []
           },
           allowHalfOpen: false,
           _sockname: null,
           _pendingData: null,
           _pendingEncoding: '',
           server: null,
           _server: null,
           parser: null,
           _httpMessage: [Circular *1],
           [Symbol(async_id_symbol)]: 282,
           [Symbol(kHandle)]: TCP {
             reading: true,
             onconnection: null,
             [Symbol(owner_symbol)]: [Circular *2]
           },
           [Symbol(kSetNoDelay)]: false,
           [Symbol(lastWriteQueueSize)]: 0,
           [Symbol(timeout)]: null,
           [Symbol(kBuffer)]: null,
           [Symbol(kBufferCb)]: null,
           [Symbol(kBufferGen)]: null,
           [Symbol(kCapture)]: false,
           [Symbol(kBytesRead)]: 0,
           [Symbol(kBytesWritten)]: 0,
           [Symbol(RequestTimeout)]: undefined
         },
         _consuming: false,
         _dumped: false,
         req: [Circular *1],
         responseUrl: 'http://livekit:7880/twirp/livekit.RecordingService/StartRecording',
         redirects: [],
         [Symbol(kCapture)]: false,
         [Symbol(kHeaders)]: {
           'content-length': '89',
           'content-type': 'application/json',
           vary: 'Origin',
           date: 'Thu, 03 Mar 2022 07:27:41 GMT',
           connection: 'close'
         },
         [Symbol(kHeadersCount)]: 10,
         [Symbol(kTrailers)]: null,
         [Symbol(kTrailersCount)]: 0,
         [Symbol(RequestTimeout)]: undefined
       },
       aborted: false,
       timeoutCb: null,
       upgradeOrConnect: false,
       parser: null,
       maxHeadersCount: null,
       reusedSocket: false,
       host: 'livekit',
       protocol: 'http:',
       _redirectable: Writable {
         _writableState: WritableState {
           objectMode: false,
           highWaterMark: 16384,
           finalCalled: false,
           needDrain: false,
           ending: false,
           ended: false,
           finished: false,
           destroyed: false,
           decodeStrings: true,
           defaultEncoding: 'utf8',
           length: 0,
           writing: false,
           corked: 0,
           sync: true,
           bufferProcessing: false,
           onwrite: [Function: bound onwrite],
           writecb: null,
           writelen: 0,
           afterWriteTickInfo: null,
           buffered: [],
           bufferedIndex: 0,
           allBuffers: true,
           allNoop: true,
           pendingcb: 0,
           constructed: true,
           prefinished: false,
           errorEmitted: false,
           emitClose: true,
           autoDestroy: true,
           errored: null,
           closed: false,
           closeEmitted: false,
           [Symbol(kOnFinished)]: []
         },
         _events: [Object: null prototype] {
           response: [Function: handleResponse],
           error: [Function: handleRequestError]
         },
         _eventsCount: 2,
         _maxListeners: undefined,
         _options: {
           maxRedirects: 21,
           maxBodyLength: 10485760,
           protocol: 'http:',
           path: '/twirp/livekit.RecordingService/StartRecording',
           method: 'POST',
           headers: {
             Accept: 'application/json, text/plain, */*',
             'Content-Type': 'application/json',
             Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0',
             'User-Agent': 'axios/0.21.4',
             'Content-Length': 122
           },
           agent: undefined,
           agents: { http: undefined, https: undefined },
           auth: undefined,
           hostname: 'livekit',
           port: '7880',
           nativeProtocols: { 'http:': [Object], 'https:': [Object] },
           pathname: '/twirp/livekit.RecordingService/StartRecording'
         },
         _ended: true,
         _ending: true,
         _redirectCount: 0,
         _redirects: [],
         _requestBodyLength: 122,
         _requestBodyBuffers: [],
         _onNativeResponse: [Function (anonymous)],
         _currentRequest: [Circular *1],
         _currentUrl: 'http://livekit:7880/twirp/livekit.RecordingService/StartRecording',
         [Symbol(kCapture)]: false
       },
       [Symbol(kCapture)]: false,
       [Symbol(kNeedDrain)]: false,
       [Symbol(corked)]: 0,
       [Symbol(kOutHeaders)]: [Object: null prototype] {
         accept: [ 'Accept', 'application/json, text/plain, */*' ],
         'content-type': [ 'Content-Type', 'application/json' ],
         authorization: [
           'Authorization',
           'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tUmVjb3JkIjp0cnVlfSwiaWF0IjoxNjQ2MjkyNDU4LCJuYmYiOjE2NDYyOTI0NTgsImV4cCI6MTY0NjI5MzA1OCwiaXNzIjoiQVBJRU5XRnRSYkxWY2NrIn0.eBFy0hg4Ss18kR8OWWcImdpAo1jeVeRXxa4DsGTH6I0'
         ],
         'user-agent': [ 'User-Agent', 'axios/0.21.4' ],
         'content-length': [ 'Content-Length', 122 ],
         host: [ 'Host', 'livekit:7880' ]
       }
     },
     data: {
       code: 'internal',
       msg: 'no recorders available',
       meta: { cause: '*errors.errorString' }
     }
   },
   isAxiosError: true,
   toJSON: [Function: toJSON]
 }

Text Chat via WebRTC Data Channel is unusable

The chat implementation in your application is not reliable because messages don't get sent if there are no participants. In reality, they should be stored in history so that a new participant can receive the messages. From the backend and webhook side, I don't see a way to control this. Can you provide any guidance?

Hidden participant Can Not subscribe to published data

Hello Livekit team!

In my use case I need to let a hidden participant to join the room with permission to subscribe ONLY for both Audio/Video tracks and Published data!
I added the following token

at.addGrant({
            roomJoin: true,
            room: "example",
            canPublish: false,           
            canPublishData: false,
            roomAdmin: false,
           
            canSubscribe: true,
            hidden: true,
          });

This participant can subscribe to published Audio/Video But not to published data

Update
After upgrading livekit-server-sdk to v1.0.2 and restarting the server, It works now

Please close this issue

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): update devdependencies (non-major) (@rushstack/heft, @types/node, @typescript-eslint/eslint-plugin, @typescript-eslint/parser, eslint-config-next, eslint-plugin-react, prettier, typedoc, vite, vitest)

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Ignored or Blocked

These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.

Detected dependencies

cargo
packages/livekit-rtc/Cargo.toml
  • napi 2.12.2
  • napi-derive 2.12.2
  • prost 0.12
  • prost-types 0.12
  • log 0.4.20
  • tokio 1.37.0
  • napi-build 2.0.1
github-actions
.github/workflows/rtc-node.yml
  • actions/checkout v4
  • pnpm/action-setup v4
  • actions/setup-node v4
  • fsfe/reuse-action v3
  • dorny/paths-filter v3
  • actions/checkout v4
  • pnpm/action-setup v4
  • actions/setup-node v4
  • actions/cache v4
  • actions/upload-artifact v4
  • actions/checkout v4
  • pnpm/action-setup v4
  • actions/setup-node v4
  • actions/download-artifact v4
  • changesets/action v1
npm
package.json
  • @changesets/cli ^2.27.1
  • @livekit/changesets-changelog-github ^0.0.4
  • @rushstack/heft ^0.66.0
  • @trivago/prettier-plugin-sort-imports ^4.3.0
  • @typescript-eslint/eslint-plugin ^7.13.1
  • @typescript-eslint/parser ^7.13.1
  • eslint ^8.56.0
  • eslint-config-next ^14.2.4
  • eslint-config-prettier ^9.0.0
  • eslint-config-standard ^17.1.0
  • eslint-config-turbo ^2.0.0
  • eslint-plugin-import ^2.29.1
  • eslint-plugin-n ^17.9.0
  • eslint-plugin-prettier ^5.1.3
  • eslint-plugin-promise ^6.1.1
  • eslint-plugin-react ^7.34.2
  • eslint-plugin-tsdoc ^0.3.0
  • prettier ^3.2.5
  • turbo ^2.0.0
  • typescript ^5.4.5
  • vitest ^2.0.0
  • pnpm 9.2.0
packages/livekit-rtc/npm/darwin-arm64/package.json
  • node >= 10
packages/livekit-rtc/npm/darwin-x64/package.json
  • node >= 10
packages/livekit-rtc/npm/linux-arm64-gnu/package.json
  • node >= 10
packages/livekit-rtc/npm/linux-x64-gnu/package.json
  • node >= 10
packages/livekit-rtc/npm/win32-x64-msvc/package.json
  • node >= 10
packages/livekit-rtc/package.json
  • @bufbuild/protobuf ^1.4.2
  • typed-emitter ^2.1.0
  • @napi-rs/cli ^2.18.0
  • @types/node ^20.9.2
  • typescript ^5.2.2
  • prettier ^3.0.3
  • node >= 18
packages/livekit-server-sdk/package.json
  • @livekit/protocol ^1.19.0
  • camelcase-keys ^9.0.0
  • jose ^5.1.2
  • @bufbuild/protobuf ^1.7.2
  • @changesets/cli ^2.27.1
  • @edge-runtime/vm ^3.1.7
  • @livekit/changesets-changelog-github ^0.0.4
  • @types/node ^20.10.1
  • happy-dom ^14.0.0
  • prettier ^3.0.0
  • typedoc ^0.26.0
  • typescript 5.5.x
  • vite ^5.2.9
  • vitest ^2.0.0
  • node >=19

  • Check this box to trigger a request for Renovate to run again on this repository

AccessToken.addGrant() should not replace previous grants

Consider this following use case:

const token = new AccessToken();

token.addGrant({
 canPublish: true,
 canSubscribe: true,
 roomJoin: true,
 room: data.meetingID,
 canPublishData: true,
});

if( user.isAdmin ){
 token.addGrant({  roomAdmin: true })
}

This code should keep the previous grants and add roomAdmin grant to the token, instead, it replaces previous grants and adds only roomAdmin grant to the token.

I am not sure if this is intentional, I was not able to join a room with just roomAdmin grant.

I can open a PR that fixes this issue.

https://github.com/livekit/server-sdk-js/blob/e9e24658479c72bbcd156d62f046a51c608d8731/src/AccessToken.ts#L83

After upgrading to v2, all functions like `createIngress()` are broken

After following the instructions I get the following error message for all functions:
Error: cannot decode message livekit.IngressInfo from JSON: key "participantMetadata" is unknown

I searched for participantMetadata in the source code but didn't find anything to fix this error.

Full error:

 ⨯ node_modules\@bufbuild\protobuf\dist\cjs\private\json-format-common.js (87:30) @ Object.readMessage
 ⨯ Error: cannot decode message livekit.IngressInfo from JSON: key "participantMetadata" is unknown
    at async resetIngresses (./src/actions/ingress.ts:26:23)
    at async createIngress (./src/actions/ingress.ts:43:5)

Functions which call the error:

// Error: "at async resetIngresses (./src/actions/ingress.ts:26:23)"
const ingresses = await ingressClient.listIngress({
  roomName: hostIdentity
});

// ...
const options: CreateIngressOptions = {
  name: self.name!,
  roomName: self.id,
  participantName: self.name!,
  participantIdentity: self.id
};

options.video = new IngressVideoOptions({
  source: TrackSource.CAMERA,
  encodingOptions: {
    value: IngressVideoEncodingPreset.H264_720P_30FPS_3_LAYERS,
    case: 'preset'
  }
});
options.audio = new IngressAudioOptions({
  source: TrackSource.MICROPHONE,
  encodingOptions: {
    value: IngressAudioEncodingPreset.OPUS_STEREO_96KBPS,
    case: 'preset'
  }
});

// Error: "at async createIngress (./src/actions/ingress.ts:43:5)"
const ingress = await ingressClient.createIngress(
  ingressType,
  options
);

Question about startEgress

Is it guaranteed that startTrackEgress and startTrackCompositeEgress will resolve only after an egress instance successfully started recording(status is started)?

My use case is the following:

  1. I call and await startTrackCompositeEgress()
  2. set {recording: true} on the room metadata
  3. on client side(react) detect this change in metadata and update the UI

livekit server example

I made a lot of searches and I did not find any example or tutorial for js server, please provide it

Dependency issue upgrading to 1.2.0

Got this error today:

...\node_modules\livekit-server-sdk\dist\TwirpRPC.js:8
const camelcase_keys_1 = __importDefault(require("camelcase-keys"));
                                         ^
Error [ERR_REQUIRE_ESM]: require() of ES Module ...\node_modules\camelcase-keys\index.js from ...\node_modules\livekit-server-sdk\dist\TwirpRPC.js not supported.
Instead change the require of index.js in ...\node_modules\livekit-server-sdk\dist\TwirpRPC.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (...\node_modules\livekit-server-sdk\dist\TwirpRPC.js:8:42)
    at Object.<anonymous> (...\node_modules\livekit-server-sdk\dist\EgressClient.js:18:20)
    at Object.<anonymous> (...\node_modules\livekit-server-sdk\dist\index.js:15:14)
    at Object.<anonymous> (...\dist\src\livekit\livekit.service.js:15:30)
    at Object.<anonymous> (...\dist\src\app.module.js:43:27)
    at Object.<anonymous> (...\dist\src\main.js:8:22)

Fixed by downgrading to 1.1.4

Documentation Update: `emptyTimeout` in `CreateOptions`

Current Documentation

/**
 * number of seconds the room should clean up after being empty
 */
emptyTimeout?: number;

Proposed Documentation

  /**
   * The `emptyTimeout` property represents the number of seconds a room should remain open after being empty.
   *
   * Behavior:
   * 1. When creating a room with an `emptyTimeout` of, for example, 10 minutes:
   *    - If no participant joins within 20 seconds of room creation, the room will automatically close.
   *
   * 2. If a participant joins and later disconnects:
   *    - The empty timeout countdown begins only after the last participant disconnects.
   *    - If the last participant disconnects and no new participant joins, the room will continue to exist for the
   *      specified `emptyTimeout` duration (e.g., 10 minutes) before automatically closing.
   *    - If a new participant joins before the empty timeout elapses, the countdown is reset, and the room remains open.
   */
  emptyTimeout?: number;

IO error: invalid peer certificate: UnknownIssuer

Problem

When attempting to connect to a room using the @livekit/rtc-node library, I encounter an error on the staging environment, while it works fine locally.

Code

import { Room } from '@livekit/rtc-node';

const room = new Room();
await room.connect(this.options.host, jwtToken, { autoSubscribe: true, dynacast:

Error

{
   "type": "ConnectError",
   "message": "engine: signal failure: ws failure: IO error: invalid peer certificate: UnknownIssuer",
   "stack": "Error: engine: signal failure: ws failure: IO error: invalid peer certificate: UnknownIssuer\n    at Room.connect (file:///usr/src/app/node_modules/@livekit/rtc-node/dist/room.js:202:19)\n "
},

Environment

  • Library version: @livekit/rtc-node ^0.5.0
  • Node.js version: v22.4.1
  • Livekit Server version: v1.7 (both locally and on staging)
  • Environment: Staging
  • Works locally without issues
  • Steps to Reproduce

Steps to Reproduce

  1. Use the provided code snippet to connect to a room.
  2. Deploy the code to the staging environment.
  3. Attempt to connect to the room.

Import error in nestjs typescript

I am integrating livekit-sdk-js in my nestjs project. It is throwing me import error

/home/app/dist/modules/live-stream/services/livekit.services.js:14
const livekit_server_sdk_1 = require("livekit-server-sdk");
                             ^
Error [ERR_REQUIRE_ESM]: require() of ES Module/home/app/node_modules/livekit-server-sdk/dist/index.js from /home/app/dist/modules/live-stream/services/livekit.services.js not supported.
Instead change the require of index.js in /home/app/dist/modules/live-stream/services/livekit.services.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/home/app/dist/modules/live-stream/services/livekit.services.js:14:30)

Livekit version from package-lock.json:

"node_modules/livekit-server-sdk": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/livekit-server-sdk/-/livekit-server-sdk-2.0.2.tgz",
      "integrity": "sha512-txRuM8HDXTpzKGdwUwL6uJI7AuOeB+a+ozJNO/OWJhf/xLnYmJn4Vwpzar5+DkW10878pfFpu/NsWiu6j3120g==",
      "dependencies": {
        "@bufbuild/protobuf": "^1.3.0",
        "camelcase-keys": "^7.0.0",
        "jose": "^5.1.2"
      },
      "engines": {
        "node": ">=18"
      }
    },

and tsconfig.json:

{
  "compilerOptions": {
    "module": "commonjs",
    "declaration": true,
    "removeComments": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "target": "ES2021",
    "sourceMap": true,
    "outDir": "./dist",
    "baseUrl": "./",
    "incremental": true,
    "skipLibCheck": true,
    "strictNullChecks": false,
    "noImplicitAny": false,
    "strictBindCallApply": false,
    "forceConsistentCasingInFileNames": false,
    "noFallthroughCasesInSwitch": false
  }
}

Setting metadata on all participants causes 500 response

Hi, below is an example to trigger the issue:

import { RoomServiceClient } from "livekit-server-sdk";


const roomName = "Students";

const roomServiceClient = new RoomServiceClient(
  `http://127.0.0.1:7880`,
  "devkey",
  "secret"
);

roomServiceClient.listParticipants(roomName).then((participants) =>
  participants.forEach((participant) => {
    roomServiceClient.updateParticipant(
      roomName,
      participant.identity,
      String.fromCharCode(0 | (Math.random() * 26 + 97))
    );
  })
);
console.log("done");

the server room has multiple participants simulated with livekit-cli load-test and when the above example is run it throws an exception because of 500 code from the twirp server:

Crash ➜ set-metadata node index.js done

/Users/rhx/repos/set-metadata/node_modules/.pnpm/[email protected]/node_modules/axios/dist/node/axios.cjs:1902
reject(new AxiosError(
^
AxiosError: Request failed with status code 500
at settle (/Users/rhx/repos/set-metadata/node_modules/.pnpm/[email protected]/node_modules/axios/dist/node/axios.cjs:1902:12)
at IncomingMessage.handleStreamEnd (/Users/rhx/repos/set-metadata/node_modules/.pnpm/[email protected]/node_modules/axios/dist/node/axios.cjs:2954:11)
at IncomingMessage.emit (node:events:524:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ERR_BAD_RESPONSE',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: {
FormData: [Function: FormData] {
LINE_BREAK: '\r\n',
DEFAULT_CONTENT_TYPE: 'application/octet-stream'
},
Blob: [class Blob]
},
validateStatus: [Function: validateStatus],
headers: AxiosHeaders {
Accept: 'application/json, text/plain, /',
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40',
'User-Agent': 'axios/1.3.6',
'Content-Length': '65',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
baseURL: 'http://127.0.0.1:7880',
method: 'post',
url: '/twirp/livekit.RoomService/UpdateParticipant',
data: '{"room":"Students","identity":"sdlhl_0","metadata":"c","name":""}'
},
request: <ref *6> ClientRequest {
_events: [Object: null prototype] {
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)],
finish: [Function: requestOnFinish]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
strictContentLength: false,
_contentLength: '65',
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: true,
socket: <ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: false,
endEmitted: false,
reading: true,
constructed: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [Function: onReadableStreamEnd],
free: [Function: onFree],
close: [Function: onClose],
timeout: [Function: onTimeout],
agentRemove: [Function: onRemove],
error: [Function: bound onceWrapper] {
listener: [Function: freeSocketErrorListener]
}
},
_eventsCount: 6,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: <ref *2> TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *1],
[Symbol(resource_symbol)]: ReusedHandle { type: 34, handle: [Circular *2] }
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: <ref *3> Timeout {
_idleTimeout: 5000,
_idlePrev: <ref *4> TimersList {
_idleNext: [Circular *3],
_idlePrev: Timeout {
_idleTimeout: 5000,
_idlePrev: [Circular *3],
_idleNext: [Circular *4],
_idleStart: 657,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 47,
[Symbol(triggerId)]: 45
},
expiry: 5127,
id: -9007199254740991,
msecs: 5000,
priorityQueuePosition: 1
},
_idleNext: <ref *5> Timeout {
_idleTimeout: 5000,
_idlePrev: [Circular *3],
_idleNext: <ref *4> TimersList {
_idleNext: [Circular *3],
_idlePrev: [Circular *5],
expiry: 5127,
id: -9007199254740991,
msecs: 5000,
priorityQueuePosition: 1
},
_idleStart: 657,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 47,
[Symbol(triggerId)]: 45
},
_idleStart: 2165,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 58,
[Symbol(triggerId)]: 56
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_header: 'POST /twirp/livekit.RoomService/UpdateParticipant HTTP/1.1\r\n' +
'Accept: application/json, text/plain, /\r\n' +
'Content-Type: application/json\r\n' +
'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40\r\n' +
'User-Agent: axios/1.3.6\r\n' +
'Content-Length: 65\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: 127.0.0.1:7880\r\n' +
'Connection: keep-alive\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: Agent {
_events: [Object: null prototype] {
free: [Function (anonymous)],
newListener: [Function: maybeEnableKeylog]
},
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object: null prototype] {
keepAlive: true,
scheduling: 'lifo',
timeout: 5000,
noDelay: true,
path: null
},
requests: [Object: null prototype] {},
sockets: [Object: null prototype] {},
freeSockets: [Object: null prototype] {
'127.0.0.1:7880:': [
Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 6,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: [Timeout],
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
<ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 6,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: [Timeout],
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
}
]
},
keepAliveMsecs: 1000,
keepAlive: true,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 2,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
joinDuplicateHeaders: undefined,
path: '/twirp/livekit.RoomService/UpdateParticipant',
_ended: true,
res: IncomingMessage {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: true,
endEmitted: true,
reading: false,
constructed: true,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
destroyed: true,
errored: null,
closed: true,
closeEmitted: true,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: true,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [ [Function: responseOnEnd], [Function: handleStreamEnd] ],
error: [Function: handleStreamError],
data: [Function: handleStreamData],
aborted: [Function: handlerStreamAborted]
},
_eventsCount: 4,
_maxListeners: undefined,
socket: null,
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
rawHeaders: [
'Content-Length',
'57',
'Content-Type',
'application/json',
'Vary',
'Origin',
'Date',
'Mon, 24 Apr 2023 11:03:58 GMT'
],
rawTrailers: [],
joinDuplicateHeaders: undefined,
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 500,
statusMessage: 'Internal Server Error',
client: <ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: false,
endEmitted: false,
reading: true,
constructed: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [Function: onReadableStreamEnd],
free: [Function: onFree],
close: [Function: onClose],
timeout: [Function: onTimeout],
agentRemove: [Function: onRemove],
error: [Function: bound onceWrapper] {
listener: [Function: freeSocketErrorListener]
}
},
_eventsCount: 6,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: <ref *2> TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *1],
[Symbol(resource_symbol)]: ReusedHandle { type: 34, handle: [Circular *2] }
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: <ref *3> Timeout {
_idleTimeout: 5000,
_idlePrev: <ref *4> TimersList {
_idleNext: [Circular *3],
_idlePrev: [Timeout],
expiry: 5127,
id: -9007199254740991,
msecs: 5000,
priorityQueuePosition: 1
},
_idleNext: <ref *5> Timeout {
_idleTimeout: 5000,
_idlePrev: [Circular *3],
_idleNext: [TimersList],
_idleStart: 657,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 47,
[Symbol(triggerId)]: 45
},
_idleStart: 2165,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 58,
[Symbol(triggerId)]: 56
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_consuming: false,
_dumped: false,
req: [Circular *6],
responseUrl: 'http://127.0.0.1:7880/twirp/livekit.RoomService/UpdateParticipant',
redirects: [],
[Symbol(kCapture)]: false,
[Symbol(kHeaders)]: {
'content-length': '57',
'content-type': 'application/json',
vary: 'Origin',
date: 'Mon, 24 Apr 2023 11:03:58 GMT'
},
[Symbol(kHeadersCount)]: 8,
[Symbol(kTrailers)]: null,
[Symbol(kTrailersCount)]: 0
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: true,
host: '127.0.0.1',
protocol: 'http:',
_redirectable: Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
_events: [Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError],
socket: [Function: handleRequestSocket]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: Infinity,
protocol: 'http:',
path: '/twirp/livekit.RoomService/UpdateParticipant',
method: 'POST',
headers: [Object: null prototype] {
Accept: 'application/json, text/plain, /',
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40',
'User-Agent': 'axios/1.3.6',
'Content-Length': '65',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
agents: { http: undefined, https: undefined },
auth: undefined,
beforeRedirect: [Function: dispatchBeforeRedirect],
beforeRedirects: { proxy: [Function: beforeRedirect] },
hostname: '127.0.0.1',
port: '7880',
agent: undefined,
nativeProtocols: {
'http:': {
_connectionListener: [Function: connectionListener],
METHODS: [Array],
STATUS_CODES: [Object],
Agent: [Function],
ClientRequest: [Function: ClientRequest],
IncomingMessage: [Function: IncomingMessage],
OutgoingMessage: [Function: OutgoingMessage],
Server: [Function: Server],
ServerResponse: [Function: ServerResponse],
createServer: [Function: createServer],
validateHeaderName: [Function: _node_internal],
validateHeaderValue: [Function: _node_internal],
get: [Function: get],
request: [Function: request],
setMaxIdleHTTPParsers: [Function: setMaxIdleHTTPParsers],
maxHeaderSize: [Getter],
globalAgent: [Getter/Setter]
},
'https:': {
Agent: [Function: Agent],
globalAgent: [Agent],
Server: [Function: Server],
createServer: [Function: createServer],
get: [Function: get],
request: [Function: request]
}
},
pathname: '/twirp/livekit.RoomService/UpdateParticipant'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 65,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [Circular *6],
_currentUrl: 'http://127.0.0.1:7880/twirp/livekit.RoomService/UpdateParticipant',
[Symbol(kCapture)]: false
},
[Symbol(kCapture)]: false,
[Symbol(kBytesWritten)]: 0,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [ 'Accept', 'application/json, text/plain, /' ],
'content-type': [ 'Content-Type', 'application/json' ],
authorization: [
'Authorization',
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40'
],
'user-agent': [ 'User-Agent', 'axios/1.3.6' ],
'content-length': [ 'Content-Length', '65' ],
'accept-encoding': [ 'Accept-Encoding', 'gzip, compress, deflate, br' ],
host: [ 'Host', '127.0.0.1:7880' ]
},
[Symbol(errored)]: null,
[Symbol(kUniqueHeaders)]: null
},
response: {
status: 500,
statusText: 'Internal Server Error',
headers: AxiosHeaders {
'content-length': '57',
'content-type': 'application/json',
vary: 'Origin',
date: 'Mon, 24 Apr 2023 11:03:58 GMT'
},
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [ 'xhr', 'http' ],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: {
FormData: [Function: FormData] {
LINE_BREAK: '\r\n',
DEFAULT_CONTENT_TYPE: 'application/octet-stream'
},
Blob: [class Blob]
},
validateStatus: [Function: validateStatus],
headers: AxiosHeaders {
Accept: 'application/json, text/plain, /',
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40',
'User-Agent': 'axios/1.3.6',
'Content-Length': '65',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
baseURL: 'http://127.0.0.1:7880',
method: 'post',
url: '/twirp/livekit.RoomService/UpdateParticipant',
data: '{"room":"Students","identity":"sdlhl_0","metadata":"c","name":""}'
},
request: <ref *6> ClientRequest {
_events: [Object: null prototype] {
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)],
finish: [Function: requestOnFinish]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: true,
_last: false,
chunkedEncoding: false,
shouldKeepAlive: true,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
strictContentLength: false,
_contentLength: '65',
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: true,
socket: <ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: false,
endEmitted: false,
reading: true,
constructed: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [Function: onReadableStreamEnd],
free: [Function: onFree],
close: [Function: onClose],
timeout: [Function: onTimeout],
agentRemove: [Function: onRemove],
error: [Function: bound onceWrapper] {
listener: [Function: freeSocketErrorListener]
}
},
_eventsCount: 6,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: <ref *2> TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *1],
[Symbol(resource_symbol)]: ReusedHandle { type: 34, handle: [Circular *2] }
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: <ref *3> Timeout {
_idleTimeout: 5000,
_idlePrev: <ref *4> TimersList {
_idleNext: [Circular *3],
_idlePrev: [Timeout],
expiry: 5127,
id: -9007199254740991,
msecs: 5000,
priorityQueuePosition: 1
},
_idleNext: <ref *5> Timeout {
_idleTimeout: 5000,
_idlePrev: [Circular *3],
_idleNext: [TimersList],
_idleStart: 657,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 47,
[Symbol(triggerId)]: 45
},
_idleStart: 2165,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 58,
[Symbol(triggerId)]: 56
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_header: 'POST /twirp/livekit.RoomService/UpdateParticipant HTTP/1.1\r\n' +
'Accept: application/json, text/plain, /\r\n' +
'Content-Type: application/json\r\n' +
'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40\r\n' +
'User-Agent: axios/1.3.6\r\n' +
'Content-Length: 65\r\n' +
'Accept-Encoding: gzip, compress, deflate, br\r\n' +
'Host: 127.0.0.1:7880\r\n' +
'Connection: keep-alive\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: Agent {
_events: [Object: null prototype] {
free: [Function (anonymous)],
newListener: [Function: maybeEnableKeylog]
},
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object: null prototype] {
keepAlive: true,
scheduling: 'lifo',
timeout: 5000,
noDelay: true,
path: null
},
requests: [Object: null prototype] {},
sockets: [Object: null prototype] {},
freeSockets: [Object: null prototype] {
'127.0.0.1:7880:': [ [Socket], [Socket] ]
},
keepAliveMsecs: 1000,
keepAlive: true,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 2,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
joinDuplicateHeaders: undefined,
path: '/twirp/livekit.RoomService/UpdateParticipant',
_ended: true,
res: IncomingMessage {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: [],
flowing: true,
ended: true,
endEmitted: true,
reading: false,
constructed: true,
sync: true,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
destroyed: true,
errored: null,
closed: true,
closeEmitted: true,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: true,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [ [Function: responseOnEnd], [Function: handleStreamEnd] ],
error: [Function: handleStreamError],
data: [Function: handleStreamData],
aborted: [Function: handlerStreamAborted]
},
_eventsCount: 4,
_maxListeners: undefined,
socket: null,
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
rawHeaders: [
'Content-Length',
'57',
'Content-Type',
'application/json',
'Vary',
'Origin',
'Date',
'Mon, 24 Apr 2023 11:03:58 GMT'
],
rawTrailers: [],
joinDuplicateHeaders: undefined,
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 500,
statusMessage: 'Internal Server Error',
client: <ref *1> Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: null,
_closeAfterHandlingError: false,
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: [BufferList],
length: 0,
pipes: [],
flowing: true,
ended: false,
endEmitted: false,
reading: true,
constructed: true,
sync: false,
needReadable: true,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
destroyed: false,
errored: null,
closed: false,
closeEmitted: false,
defaultEncoding: 'utf8',
awaitDrainWriters: null,
multiAwaitDrain: false,
readingMore: false,
dataEmitted: true,
decoder: null,
encoding: null,
[Symbol(kPaused)]: false
},
_events: [Object: null prototype] {
end: [Function: onReadableStreamEnd],
free: [Function: onFree],
close: [Function: onClose],
timeout: [Function: onTimeout],
agentRemove: [Function: onRemove],
error: [Function]
},
_eventsCount: 6,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: false,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: false,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
timeout: 5000,
parser: null,
_httpMessage: null,
[Symbol(async_id_symbol)]: -1,
[Symbol(kHandle)]: <ref *2> TCP {
reading: true,
onconnection: null,
[Symbol(owner_symbol)]: [Circular *1],
[Symbol(resource_symbol)]: [ReusedHandle]
},
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: <ref *3> Timeout {
_idleTimeout: 5000,
_idlePrev: [TimersList],
_idleNext: [Timeout],
_idleStart: 2165,
_onTimeout: [Function: bound ],
_timerArgs: undefined,
_repeat: null,
_destroyed: false,
[Symbol(refed)]: false,
[Symbol(kHasPrimitive)]: false,
[Symbol(asyncId)]: 58,
[Symbol(triggerId)]: 56
},
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: true,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 1,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_consuming: false,
_dumped: false,
req: [Circular *6],
responseUrl: 'http://127.0.0.1:7880/twirp/livekit.RoomService/UpdateParticipant',
redirects: [],
[Symbol(kCapture)]: false,
[Symbol(kHeaders)]: {
'content-length': '57',
'content-type': 'application/json',
vary: 'Origin',
date: 'Mon, 24 Apr 2023 11:03:58 GMT'
},
[Symbol(kHeadersCount)]: 8,
[Symbol(kTrailers)]: null,
[Symbol(kTrailersCount)]: 0
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: true,
host: '127.0.0.1',
protocol: 'http:',
_redirectable: Writable {
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: false,
ended: false,
finished: false,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: true,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
afterWriteTickInfo: null,
buffered: [],
bufferedIndex: 0,
allBuffers: true,
allNoop: true,
pendingcb: 0,
constructed: true,
prefinished: false,
errorEmitted: false,
emitClose: true,
autoDestroy: true,
errored: null,
closed: false,
closeEmitted: false,
[Symbol(kOnFinished)]: []
},
_events: [Object: null prototype] {
response: [Function: handleResponse],
error: [Function: handleRequestError],
socket: [Function: handleRequestSocket]
},
_eventsCount: 3,
_maxListeners: undefined,
_options: {
maxRedirects: 21,
maxBodyLength: Infinity,
protocol: 'http:',
path: '/twirp/livekit.RoomService/UpdateParticipant',
method: 'POST',
headers: [Object: null prototype] {
Accept: 'application/json, text/plain, /',
'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40',
'User-Agent': 'axios/1.3.6',
'Content-Length': '65',
'Accept-Encoding': 'gzip, compress, deflate, br'
},
agents: { http: undefined, https: undefined },
auth: undefined,
beforeRedirect: [Function: dispatchBeforeRedirect],
beforeRedirects: { proxy: [Function: beforeRedirect] },
hostname: '127.0.0.1',
port: '7880',
agent: undefined,
nativeProtocols: { 'http:': [Object], 'https:': [Object] },
pathname: '/twirp/livekit.RoomService/UpdateParticipant'
},
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 65,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [Circular *6],
_currentUrl: 'http://127.0.0.1:7880/twirp/livekit.RoomService/UpdateParticipant',
[Symbol(kCapture)]: false
},
[Symbol(kCapture)]: false,
[Symbol(kBytesWritten)]: 0,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [ 'Accept', 'application/json, text/plain, /' ],
'content-type': [ 'Content-Type', 'application/json' ],
authorization: [
'Authorization',
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiJTdHVkZW50cyJ9LCJpYXQiOjE2ODIzMzQyMzYsIm5iZiI6MTY4MjMzNDIzNiwiZXhwIjoxNjgyMzM0ODM2LCJpc3MiOiJkZXZrZXkifQ.1zsSyWhDALpxctMzutT5xd_ph7GWk9WgMcoDUVcUj40'
],
'user-agent': [ 'User-Agent', 'axios/1.3.6' ],
'content-length': [ 'Content-Length', '65' ],
'accept-encoding': [ 'Accept-Encoding', 'gzip, compress, deflate, br' ],
host: [ 'Host', '127.0.0.1:7880' ]
},
[Symbol(errored)]: null,
[Symbol(kUniqueHeaders)]: null
},
data: { code: 'internal', msg: 'operation cannot be completed' }
}
}

Node.js v19.8.1
➜ set-metadata

Cloudflare Worker support - avoid using 'crypto' from Node

Just used wrangler locally to try the Cloudflare Worker support. I know a lot has been done recently to add support for non-Node JS environments.

Tried it at this commit from yesterday:
1c2e183

Here's the last thing I'm running into:

    src/util/server-sdk-js-main/dist/WebhookReceiver.js:1:19:
      1 │ import crypto from 'crypto';                       
        ╵                    ~~~~~~~~

  The package "crypto" wasn't found on the file system but is built into node.

They recommend the Web Crypto API: https://developers.cloudflare.com/workers/runtime-apis/web-crypto

After just commenting that code out locally, it was able to generate a JWT while running in wrangler - so I think this is the last thing left. Thanks!

Livekit importing err when working with nestjs.

I am getting error

const livekit_server_sdk_1 = require("livekit-server-sdk");
                             ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /home/aldrich/temp/nest/livekit-server/node_modules/.pnpm/[email protected]/node_modules/livekit-server-sdk/dist/index.js from /home/
aldrich/temp/nest/livekit-server/dist/app.service.js not supported.
Instead change the require of index.js in /home/aldrich/temp/nest/livekit-server/dist/app.service.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/home/aldrich/temp/nest/livekit-server/dist/app.service.js:11:30)
    at Object.<anonymous> (/home/aldrich/temp/nest/livekit-server/dist/app.controller.js:14:23)
    at Object.<anonymous> (/home/aldrich/temp/nest/livekit-server/dist/app.module.js:11:26)
    at Object.<anonymous> (/home/aldrich/temp/nest/livekit-server/dist/main.js:4:22)

when I try to import livekit from a nestjs backend.

Steps for Reproduction:

  1. git clone https://github.com/jossephus/livekit-with-nestjs
  2. cd livekit-with-nestjs && pnpm install
  3. pnpm start:dev

further info: this is the only place I am using Livekit sdk

image

sendData is not working

First problem. I am using:

await this.client.sendData(roomId, encoder.encode(JSON.stringify(message)), DataPacket_Kind.RELIABLE, {});

The data is sent successfully, but none of the recipients receive the data. The client settings are all fine, and I can create and use rooms without any issues.
Second problem: After several minutes of creating a room, this method starts throwing an error

Error: Request failed with status 503: Service Unavailable
    at <anonymous> (./app/backend/node_modules/livekit-server-sdk/dist/TwirpRPC.js:27:14)
    at processTicksAndRejections (:12:39)
      at ./app/backend/src/lib/LiveKitManager.ts:73:13

and I don't know why. After creating a new room, the method works for 5-7 minutes before encountering the same error again (but clients do not receive anything in both scenarios).

Join room using the sdk from server

I'm trying to implement a similar idea that of https://blog.livekit.io/meet-kitt/. I was able to set up a local livekit-server and use a nodeJs app to support creating tokens and rooms. I have also a web hook receiver that is called on room event.
What I want to achieve is to make a bot (text to speech service) respond to the room programmatically but I couldn't find anything from the documentation or code.

Something like KITT ConnectToRoomWithToken or go-server-sdk JoinRoom

How can I achieve the same using javascript sdk??

Issue with Parallel Room Instances and Audio Publishing

Hi,

When running two instances of a room in parallel, the second instance stops publishing audio after the first instance completes its execution and calls the await room.disconnect() method, even though these are two separate, independent room instances. The issue occurs as follows snippet from example:

const room = new Room();
await room.connect(process.env.LIVEKIT_URL, jwt, { autoSubscribe: true, dynacast: true });

const sample = readFileSync(join(process.cwd(), './speex.wav'));
const channels = sample.readUInt16LE(22);
const sampleRate = sample.readUInt32LE(24);
const dataSize = sample.readUInt32LE(40) / 2;

const source = new AudioSource(sampleRate, channels);
const track = LocalAudioTrack.createAudioTrack('audio', source);
const options = new TrackPublishOptions();
const buffer = new Int16Array(sample.buffer);
options.source = TrackSource.SOURCE_MICROPHONE;
await room.localParticipant.publishTrack(track, options);
await new Promise((resolve) => setTimeout(resolve, 1000)); // wait a bit so the start doesn't cut off

let written = 44; // start of WAVE data stream
const FRAME_DURATION = 1; // write 1s of audio at a time
const numSamples = sampleRate / FRAME_DURATION;
while (written < dataSize) {
  const available = dataSize - written;
  const frameSize = Math.min(numSamples, available);

  const frame = new AudioFrame(
    buffer.slice(written, written + frameSize),
    sampleRate,
    channels,
    Math.trunc(frameSize / channels),
  );
  await source.captureFrame(frame);

  written += frameSize;
}

await room.disconnect();

Steps to Reproduce:

  • Run the above script to set up and connect two independent room instances in parallel.
  • Ensure both instances start publishing audio.
  • Let the first instance complete.
  • Observe that the second instance stops publishing audio to the room.

Node.js package version:
@livekit/rtc-node: 0.5.0

Dependency issue livekit-server-sdk

Have this error in Nest.js server:

api  | const livekit_server_sdk_1 = require("livekit-server-sdk");
api  |                              ^
api  | Error [ERR_REQUIRE_ESM]: require() of ES Module /usr/src/app/node_modules/livekit-server-sdk/dist/index.js from /usr/src/app/dist/src/infrastructure/third-party-services/livekit/livekit.service.js not supported.
api  | Instead change the require of index.js in /usr/src/app/dist/src/infrastructure/third-party-services/livekit/livekit.service.js to a dynamic import() which is available in all CommonJS modules.
api  |     at Object.<anonymous> (/usr/src/app/dist/src/infrastructure/third-party-services/livekit/livekit.service.js:17:30)

Version:
"livekit-server-sdk": "^2.4.0",
"@nestjs/core": "^10.0.0",

updateParticipant throws uncatchable 500 error

I have an interval that is supposed to update the metadata for an ingress participant every second like this:

     try {
       roomServiceClient.updateParticipant(room, ingressOptions.participantIdentity, metadata);
     } catch (error) {
       console.error(error);
     }

And it works some of the time, running the full ~200 times (length of the stream), but most of the time it will fail at some point and return an incredibly lengthy 500 error from Axios that is not being caught in the try catch. I don't really care if the request fails occasionally, but I really need it to not crash the script, so any guidance would be appreciated.

Seems perhaps related to this issue: #22

full error
C:\Users\thoma\metaverse\metaverse-backend\node_modules\axios\lib\core\settle.js:19
    reject(new AxiosError(
           ^
AxiosError: Request failed with status code 500
    at settle (C:\Users\thoma\metaverse\metaverse-backend\node_modules\axios\lib\core\settle.js:19:12)
    at IncomingMessage.handleStreamEnd (C:\Users\thoma\metaverse\metaverse-backend\node_modules\axios\lib\adapters\http.js:572:11)
    at IncomingMessage.emit (node:events:526:35)
    at IncomingMessage.emit (node:domain:489:12)
    at endReadableNT (node:internal/streams/readable:1359:12)
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  code: 'ERR_BAD_RESPONSE',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [ 'xhr', 'http' ],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function], Blob: [class Blob] },
    validateStatus: [Function: validateStatus],
    headers: Object [AxiosHeaders] {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiIxOmF2OjEifSwiaWF0IjoxNzAyNjAzMjYwLCJuYmYiOjE3MDI2MDMyNjAsImV4cCI6MTcwMjYwMzg2MCwiaXNzIjoiQVBJbUxBTnlBUE5Fa2tVIn0.LjGQsQFTcDmwQwowmf5Fr4674TPtMtxyuDNy8ayNPew',
      'User-Agent': 'axios/1.5.1',
      'Content-Length': '114',
      'Accept-Encoding': 'gzip, compress, deflate, br'
    },
    baseURL: 'https://mkmv.livekit.cloud/',
    method: 'post',
    url: '/twirp/livekit.RoomService/UpdateParticipant',
    data: '{"room":"1:av:1","identity":"streaming_bot","metadata":"{\\"timestamp\\":1702603227817,\\"iteration\\":30}","name":""}'
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      finish: [Function: requestOnFinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    maxRequestsOnConnectionReached: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    strictContentLength: false,
    _contentLength: '114',
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: false,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: false,
      _SNICallback: null,
      servername: 'mkmv.livekit.cloud',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'mkmv.livekit.cloud',
      _closeAfterHandlingError: false,
      _readableState: [ReadableState],
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(async_id_symbol)]: 1526,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(kSetKeepAlive)]: true,
      [Symbol(kSetKeepAliveInitialDelay)]: 60,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'POST /twirp/livekit.RoomService/UpdateParticipant HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json\r\n' +
      'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiIxOmF2OjEifSwiaWF0IjoxNzAyNjAzMjYwLCJuYmYiOjE3MDI2MDMyNjAsImV4cCI6MTcwMjYwMzg2MCwiaXNzIjoiQVBJbUxBTnlBUE5Fa2tVIn0.LjGQsQFTcDmwQwowmf5Fr4674TPtMtxyuDNy8ayNPew\r\n' +
      'User-Agent: axios/1.5.1\r\n' +
      'Content-Length: 114\r\n' +
      'Accept-Encoding: gzip, compress, deflate, br\r\n' +
      'Host: mkmv.livekit.cloud\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: nop],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object: null prototype],
      requests: [Object: null prototype] {},
      sockets: [Object: null prototype],
      freeSockets: [Object: null prototype] {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 2,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    joinDuplicateHeaders: undefined,
    path: '/twirp/livekit.RoomService/UpdateParticipant',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 4,
      _maxListeners: undefined,
      socket: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      joinDuplicateHeaders: undefined,
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 500,
      statusMessage: 'Internal Server Error',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'https://mkmv.livekit.cloud/twirp/livekit.RoomService/UpdateParticipant',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 10,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'mkmv.livekit.cloud',
    protocol: 'https:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 114,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'https://mkmv.livekit.cloud/twirp/livekit.RoomService/UpdateParticipant',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kBytesWritten)]: 0,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      authorization: [Array],
      'user-agent': [Array],
      'content-length': [Array],
      'accept-encoding': [Array],
      host: [Array]
    },
    [Symbol(errored)]: null,
    [Symbol(kHighWaterMark)]: 16384,
    [Symbol(kRejectNonStandardBodyWrites)]: false,
    [Symbol(kUniqueHeaders)]: null
  },
  response: {
    status: 500,
    statusText: 'Internal Server Error',
    headers: Object [AxiosHeaders] {
      'content-length': '57',
      'content-type': 'application/json',
      date: 'Fri, 15 Dec 2023 01:21:15 GMT',
      vary: 'Origin',
      connection: 'close'
    },
    config: {
      transitional: [Object],
      adapter: [Array],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [Object [AxiosHeaders]],
      baseURL: 'https://mkmv.livekit.cloud/',
      method: 'post',
      url: '/twirp/livekit.RoomService/UpdateParticipant',
      data: '{"room":"1:av:1","identity":"streaming_bot","metadata":"{\\"timestamp\\":1702603227817,\\"iteration\\":30}","name":""}'
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      maxRequestsOnConnectionReached: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      strictContentLength: false,
      _contentLength: '114',
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [TLSSocket],
      _header: 'POST /twirp/livekit.RoomService/UpdateParticipant HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/json\r\n' +
        'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQWRtaW4iOnRydWUsInJvb20iOiIxOmF2OjEifSwiaWF0IjoxNzAyNjAzMjYwLCJuYmYiOjE3MDI2MDMyNjAsImV4cCI6MTcwMjYwMzg2MCwiaXNzIjoiQVBJbUxBTnlBUE5Fa2tVIn0.LjGQsQFTcDmwQwowmf5Fr4674TPtMtxyuDNy8ayNPew\r\n' +
        'User-Agent: axios/1.5.1\r\n' +
        'Content-Length: 114\r\n' +
        'Accept-Encoding: gzip, compress, deflate, br\r\n' +
        'Host: mkmv.livekit.cloud\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: nop],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      joinDuplicateHeaders: undefined,
      path: '/twirp/livekit.RoomService/UpdateParticipant',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'mkmv.livekit.cloud',
      protocol: 'https:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype],
      [Symbol(errored)]: null,
      [Symbol(kHighWaterMark)]: 16384,
      [Symbol(kRejectNonStandardBodyWrites)]: false,
      [Symbol(kUniqueHeaders)]: null
    },
    data: { code: 'internal', msg: 'operation cannot be completed' }
  }
}

deleteRoom doesn't work (throws exception)

when running deleteRoom() it throws an Error: Request failed with status code 401

Here's the full exception
Error: Request failed with status code 401
    at createError (C:\Users\Alex\git\roomService\node_modules\axios\lib\core\createError.js:16:15)
    at settle (C:\Users\Alex\git\roomService\node_modules\axios\lib\core\settle.js:17:12)
    at IncomingMessage.handleStreamEnd (C:\Users\Alex\git\roomService\node_modules\axios\lib\adapters\http.js:269:11)
    at IncomingMessage.emit (events.js:412:35)
    at endReadableNT (internal/streams/readable.js:1317:12)
    at processTicksAndRejections (internal/process/task_queues.js:82:21) {
  config: {
    url: '/twirp/livekit.RoomService/DeleteRoom',
    method: 'post',
    data: '{"room":"L11NOJ9PFWO0KP1P8CLIW"}',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'application/json',
      Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQ3JlYXRlIjp0cnVlfSwiaWF0IjoxNjM3MTI3OTQ4LCJuYmYiOjE2MzcxMjc5NDgsImV4cCI6MTYzNzEyODU0OCwiaXNzIjoiQVBJQ0VDVkpOYXU2NDlWIn0.YEiOV55zjJu3SXfYgPBweakvoeh4ax9g5W3_DwaRbZo',
      'User-Agent': 'axios/0.21.4',
      'Content-Length': 32
    },
    baseURL: 'http://myhost.mydomain:7880',
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    }
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      connect: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'myhost.mydomain',
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [Circular *1],
      [Symbol(async_id_symbol)]: 23,
      [Symbol(kHandle)]: [TCP],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'POST /twirp/livekit.RoomService/DeleteRoom HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: application/json\r\n' +
      'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQ3JlYXRlIjp0cnVlfSwiaWF0IjoxNjM3MTI3OTQ4LCJuYmYiOjE2MzcxMjc5NDgsImV4cCI6MTYzNzEyODU0OCwiaXNzIjoiQVBJQ0VDVkpOYXU2NDlWIn0.YEiOV55zjJu3SXfYgPBweakvoeh4ax9g5W3_DwaRbZo\r\n' +
      'User-Agent: axios/0.21.4\r\n' +
      'Content-Length: 32\r\n' +
      'Host: myhost.mydomain:7880\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 80,
      protocol: 'http:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 1,
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/twirp/livekit.RoomService/DeleteRoom',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [Socket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 401,
      statusMessage: 'Unauthorized',
      client: [Socket],
      _consuming: false,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'http://myhost.mydomain:7880/twirp/livekit.RoomService/DeleteRoom',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: 'myhost.mydomain',
    protocol: 'http:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 32,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'http://myhost.mydomain:7880/twirp/livekit.RoomService/DeleteRoom',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      authorization: [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array]
    }
  },
  response: {
    status: 401,
    statusText: 'Unauthorized',
    headers: {
      'content-length': '53',
      'content-type': 'application/json',
      date: 'Wed, 17 Nov 2021 05:47:14 GMT',
      connection: 'close'
    },
    config: {
      url: '/twirp/livekit.RoomService/DeleteRoom',
      method: 'post',
      data: '{"room":"L11NOJ9PFWO0KP1P8CLIW"}',
      headers: [Object],
      baseURL: 'http://myhost.mydomain:7880',
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: [Function: validateStatus],
      transitional: [Object]
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [Socket],
      _header: 'POST /twirp/livekit.RoomService/DeleteRoom HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: application/json\r\n' +
        'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tQ3JlYXRlIjp0cnVlfSwiaWF0IjoxNjM3MTI3OTQ4LCJuYmYiOjE2MzcxMjc5NDgsImV4cCI6MTYzNzEyODU0OCwiaXNzIjoiQVBJQ0VDVkpOYXU2NDlWIn0.YEiOV55zjJu3SXfYgPBweakvoeh4ax9g5W3_DwaRbZo\r\n' +
        'User-Agent: axios/0.21.4\r\n' +
        'Content-Length: 32\r\n' +
        'Host: myhost.mydomain:7880\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/twirp/livekit.RoomService/DeleteRoom',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: 'myhost.mydomain',
      protocol: 'http:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: { code: 'unauthenticated', msg: 'permissions denied' }
  },
  isAxiosError: true,
  toJSON: [Function: toJSON]
}

note: it's also broken on livekit-cli (doesn't throw an error here, but doesn't do anything either)

tested on:
livekit-server-sdk 0.5.6
livekit-server 0.14.0

Protobufjs import & ts compile error

Ran into this issue via a Firebase Functions NodeJS project. I haven't had a chance to try outside of Firebase, but I think it shouldn't be Firebase specific, as it's the TS compiler that is tripping up over an import. I
To repro (assuming you have a firebase account):

  1. Get the firebase sdk npm install -g firebase-tools
  2. Log into the account: firebase login
  3. Create Functions: firebase init functions and choose Typescript. This essentially creates a Node Express project.
  4. Modify the main.ts file with a livekit import import {AccessToken} from "livekit-server-sdk";
  5. Run `npm install' in the functions dir
  6. Add the "Create Access Tokens" example into one of the functions (like "Hello" - doesn't matter which one, as long as the linter is happy).
  7. Run npm run build, which should call the Typescript compiler.

The compiler should complain about the line from various *.d.ts files and the lack of a default export:

import _m0 from "protobufjs/minimal";

I fixed this by manually editing those files to look like:

import * as _m0 from "protobufjs/minimal";

I am on Node 14.17.6 and npm 6.14.15, but I have seen this issue in older and newer versions of both Node and npm.

Send Data from server-sdk-js

Good Day.

I am trying to send custom message from the server side using the server-sdk-js. As an example code below:

app.get('/publish/:room', function(req, res, next) {
	if (allowedIp.indexOf(req.connection.remoteAddress) >-1)  {
		const encoder = new TextEncoder();
		const data = encoder.encode('hello world');
		const opts = {
			room: 'roomName',
			data: data,
			kind: DataPacket_Kind.RELIABLE,
		};
    svc.sendData(opts).then((_) => {
			res.json(_);
			console.log('Data published', _);
		}).catch((e) => {
	    console.log('Handle error here: ', e.message);
	    next();
	 	});
	} else {
		res.send("Publish fail");
	}
});

However, I am always getting error status 401. From what I can tell, do I need to pass token for the roomAdmin?

Thank you.

Cannot find module 'long'

image

Its looks like you use long in src/proto/livekit_ingress.ts but not added into dependencies field in package.json

Did you visit it by shadow module? I cant use it in pnpm

key "name" missing in WebhookEvent type

the WeebhookEvent for ingress_created or ingress_ended can have a name key under ingressInfo which the same name for creating the ingress using CreateIngressOptions.

Screenshot 2024-02-04 at 12 13 20 AM Screenshot 2024-02-04 at 12 13 47 AM

I have some doubts and issues found.....

Issues:

  1. After successful connection between two user, i get the warning in server terminal that " channel congestion detected, updating channel capacity " and then connection gets poor.
  2. When any user start screen sharing the quality suddenly started decreasing.

My doubts:

  1. How can i set expiration of token using node js.
  2. Can you please tell me the server requirement for 10,000 user at a time(both video audio).

Expose WebhookEvent type

Hi! I have a small quality of live improvement request :).

When using this library from TypeScript, I was trying to write a function which takes a WebhookEvent (result of WebhookReceiver.receive), but I couldn't figure out how to get the type of WebhookEvent easily.

Right now, here's how I am getting it, but as you can see that's a bit of a roundabout way of getting it:

import * as livekit from 'livekit-server-sdk';
type LivekitWebhookEvent = ReturnType<
  InstanceType<typeof livekit.WebhookReceiver>['receive']
>;

I tried import * as livekit from 'livekit-server-sdk/proto but it didn't work for mysterious JavaScript module system reasons.

Nonetheless, I think it would be nice if it WebhookEvent was exported from index.ts :).

mutePublishedTrack doesn't unmute tracks

when you mute a track, it works fine:
RoomServiceClient.mutePublishedTrack(room, identity, true)

but it doesn't do anything if you try to unmute it:
RoomServiceClient.mutePublishedTrack(room, identity, false)

the TrackInfo returned by that last call incorrectly reports a muted=false, but if you query the participant trackinfo it will still report muted=true

tested on:
livekit-server-sdk 0.5.6
livekit-server 0.14.0

Subscribe/Unsubscribe to many users at the same time

Hi, y'all!

I'm new in the LiveKit environment and I have a question. Is there a way I can update the subscriptions for many users instead of one by one? Because I ran into this:

I have a set of users (User 1, User 2, User 3, and User 4), so the idea is that User 1 can talk just to 2 of them or all of them, but I see that the only way to update the stream channel is by using the function updateSubscriptions individually.

const changeUserSub = async (req, res) => {
    const { room } = req.params;
    const { users, sids, subscribe } = req.body;

    const usersPromises = users.map((user) => {
        return svc.updateSubscriptions(room, user, sids, subscribe);
    });

    try {
        await Promise.all(usersPromises);
    catch(_) {
        ...
    }
    ...
}

I have to loop in all the users and change the subscriptions one by one for doing something like this:

    {
      "users": ["User 2", "User 3"],
      "sids": ["TR_AMfKU8MF3wGQjn"], // This is User 1 track id
      "subscribe": true
    }

Thanks!
Really appreciate it if someone can help me :)

Safe-buffer error when using livekit-server-sdk

Describe the bug
Getting an error related to safe-buffer when importing livekit-server-sdk. I've checked my other code and it looks like this is the only thing that's causing the error (it works just fine when I don't import it).

Server

  • Version: 1.0.0
  • Environment: local, Node
  • Using ViteJS
  • Using local Docker container as server

Client

  • SDK: React
  • Version: 1.0.1
  • Browsers: Chromium, Firefox

To Reproduce
Steps to reproduce the behavior:

  1. Copy code below
  2. Run project and check dev console (wish I could say more, but not sure what's causing this)

Expected behavior
livekit-server-sdk should import without giving an error.

Screenshots
image

Additional context
I'm very new to LiveKit, so I'm using the online playground as a starting point [https://livekit.io/playground#code=045cdb4c65c1876645e0c00b]. A lot of the code is taken from there.

Code
`
import { render } from "react-dom";
import React from "react";
import "../index.css";
import * as ReactFeather from "react-feather";
import * as LiveKitReact from "@livekit/react-components";
import * as Chakra from "@chakra-ui/react";
import "livekit-server-sdk";

/*
Playground lets you build a real-time video room using LiveKit's React component.
Feel free to cutomize the code below to your heart's content.
Send this page to a friend or open it in a new browser tab to see multi-user conferencing in action.

In scope:
token: An access token that joins the room, valid for 2h.
React: The React library object
LiveKitReact: The LiveKit React client SDK
LiveKitClient: The LiveKit JavaScript client SDK
ReactFeather: Feather icons to make things snazzy
Chakra: ChakraUI for React
*/

const { useParticipant, VideoRenderer, AudioRenderer, LiveKitRoom } =
LiveKitReact;

const { Flex, Grid, HStack, VStack, Box, Text, Icon, Button } = Chakra;

const { Mic, MicOff, Video, VideoOff, Monitor, XSquare, Power } = ReactFeather;

const RoomView = () => (

<LiveKitRoom
url={url}
token={token}
stageRenderer={StageView}
onConnected={(room) => {
handleConnected(room);
}}
/>

);

const CustomParticipantView = ({ participant }) => {
const { cameraPublication, isLocal } = useParticipant(participant);
if (
!cameraPublication ||
!cameraPublication.isSubscribed ||
!cameraPublication.track ||
cameraPublication.isMuted
) {
return null;
}
return (



);
};

const ControlButton = ({ icon, onClick, children }) => (




{children}



);

const ControlsView = ({ room }) => {
const { unpublishTrack } = useParticipant(room.localParticipant);

const onToggleMic = () => {
const enabled = room.localParticipant.isMicrophoneEnabled;
room.localParticipant.setMicrophoneEnabled(!enabled);
};
const onToggleVideo = () => {
const enabled = room.localParticipant.isCameraEnabled;
room.localParticipant.setCameraEnabled(!enabled);
};
const onPowerOff = () => {
room.disconnect();
};

return (

<ControlButton
icon={room.localParticipant.isMicrophoneEnabled ? Mic : MicOff}
onClick={onToggleMic}
>
{room.localParticipant.isMicrophoneEnabled ? "Mute" : "Unmute"}

<ControlButton
icon={room.localParticipant.isCameraEnabled ? Video : VideoOff}
onClick={onToggleVideo}
>
{room.localParticipant.isCameraEnabled ? "Stop Video" : "Start Video"}


Disconnect


);
};

const RoomStatusView = ({ children }) => (


{children}


);

// renderStage prepares the layout of the stage using subcomponents. Feel free to
// modify as you see fit. It uses the built-in ParticipantView component in this
// example; you may use a custom component instead.
function StageView({ roomState }) {
const { room, participants, audioTracks, isConnecting, error } = roomState;
const gridRef = React.useRef(null);
const [gridTemplateColumns, setGridTemplateColumns] = React.useState("1fr");

React.useEffect(() => {
const gridEl = gridRef.current;
if (!gridEl || participants.length === 0) return;

const totalWidth = gridEl.clientWidth;
const numCols = Math.ceil(Math.sqrt(participants.length));
const colSize = Math.floor(totalWidth / numCols);
setGridTemplateColumns(`repeat(${numCols}, minmax(50px, ${colSize}px))`);

}, [participants]);

if (isConnecting) {
return Connecting...;
}
if (error) {
return Error: {error.message};
}
if (!room) {
return Room closed;
}

return (

<Grid
ref={gridRef}
__css={{
display: "grid",
aspectRatio: "1.77778",
overflow: "hidden",
background: "black",
alignItems: "center",
justifyContent: "center",
width: "100%",
gridTemplateColumns: gridTemplateColumns,
}}
>
{audioTracks.map((track) => (

))}
{participants.map((participant) => (

))}



);
}

async function handleConnected(room) {
console.log("connected to room", room);

const tracks = await LiveKitClient.createLocalTracks({
audio: true,
video: true,
});
tracks.forEach((track) => {
room.localParticipant.publishTrack(track, { simulcast: true });
});
}

export default RoomView;
'

Using ingress breaks livekit.cloud project

I'm trying to get the https://github.com/livekit-examples/livestream project to work locally, and came across a weird issue.

I can't get a stream started with the given Ingress presets, so I tried removing them to see if that would let me stream from OBS. Now, when I try create a RMTP URL I get a status 500 info (nothing useful in the response), and from that point forward any new API keys I generate are useless. To get new, working keys I need to create a new project on cloud.livekit.io

wait - compiling /api/trpc/[trpc] (client and server)...
event - compiled successfully in 56 ms (131 modules)
❌ tRPC failed on ingress.create: Request failed with status code 500

  const ingress = await ingressClient.createIngress(
    IngressInput.RTMP_INPUT,
    {
      name: input.roomSlug,
      roomName: input.roomSlug,
      participantName: input.streamerName,
      participantIdentity: input.roomSlug,
      },
    }
  );

[BUG] listEgress throws an error when trying to parse what is already JSON data

Summary

The method egressClient.listEgress(roomName?) is throwing SyntaxError: Unexpected token o in JSON at position 1 because JSON.parse is invoked on a data structure that is already in a JSON format as seen on the following screenshot taken for a debugger attached to the nodeJS process:

image


The error lies at the line of EgressClient in the function listEgress: https://github.com/livekit/server-sdk-js/blob/main/src/EgressClient.ts#L244

Using NodeJS v16.13.0 and livekit-server-sdk v1.0.0, data at line 238 is already in JSON format.
This causes the following error to be thrown:

SyntaxError: Unexpected token o in JSON at position 1
    at JSON.parse (<anonymous>)
    at EgressClient.<anonymous> (/api/node_modules/livekit-server-sdk/dist/EgressClient.js:184:31)
    at Generator.next (<anonymous>)
    at fulfilled (/api/node_modules/livekit-server-sdk/dist/EgressClient.js:5:58)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

Issue Type

Bug Report

Component Name

EgressClient

OS / Environment

  • Docker version 20.10.17, build 100c701
  • NodeJS docker container v16.13.0
  • livekit-server-sdk v1.0.0 (nodeJS dependency)
  • Egress docker container v1.0
  • Livekit docker container v1.0

Steps to reproduce

Just run the following snippet.

  const egressClient = new EgressClient(LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET);
  const egressListForRoom = await egressClient.listEgress(); // throws "SyntaxError: Unexpected token o in JSON at position 1"

Inquiry about compatibility of Live Kit SDK with Deno

Hello,

I'm interested in using the Live Kit SDK in a project that's being developed with Deno, and I was wondering if the SDK is compatible with the Deno runtime environment.

I've searched the documentation and couldn't find any mention of Deno compatibility, so I thought I'd ask here to see if anyone has experience using the SDK with Deno.

If anyone knows whether the Live Kit SDK works with Deno or has any tips or resources for making it work, I'd appreciate any information you can provide.

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.