livekit / node-sdks Goto Github PK
View Code? Open in Web Editor NEWLiveKit real-time and server SDKs for Node.JS
Home Page: https://docs.livekit.io
License: Apache License 2.0
LiveKit real-time and server SDKs for Node.JS
Home Page: https://docs.livekit.io
License: Apache License 2.0
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:
For reference here is how I'm calling this method:
const livekitClient = new RoomServiceClient(LIVEKIT_URL, API_KEY, API_SECRET);
const result = await livekitClient.mutePublishedTrack(roomId, userToMute, sid, mute);
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:
further info: this is the only place I am using Livekit sdk
Change commit: 8cad1ba#diff-220adc3013305af91ae2598008e4b021fecda4a13c905830f622a7ab0f09d63fL169
listRooms response, field creationTime has been changed from Int to BigInt. I couldn't find any doc or changelog for this.
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?
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
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 :)
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
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' }
}
}
Twirp is returning values in snake_case while our JSON to protobuf parser is expecting camelCase.
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
}
}
I made a lot of searches and I did not find any example or tutorial for js server, please provide it
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
);
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
Client
To Reproduce
Steps to reproduce the behavior:
Expected behavior
livekit-server-sdk should import without giving an error.
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;
'
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,
},
}
);
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:
/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
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",
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!
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:
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)
Bug Report
EgressClient
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"
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
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).
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??
/**
* number of seconds the room should clean up after being empty
*/
emptyTimeout?: number;
/**
* 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;
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 export
ed from index.ts
:).
When you run listRooms() and print the numParticipants of every room, it will always be 0
on the other hand, if you listParticipants() on every room, it will give you all the participants correctly.
tested on:
livekit-server-sdk 0.5.6
livekit-server 0.14.0
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.
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
@rushstack/heft
, @types/node
, @typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, eslint-config-next
, eslint-config-turbo
, eslint-plugin-n
, eslint-plugin-prettier
, eslint-plugin-promise
, eslint-plugin-react
, prettier
, turbo
, typedoc
, typescript
, vite
, vitest
)prost
, prost-types
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
)These are blocked by an existing closed PR and will not be recreated unless you click a checkbox below.
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/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
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 ^7.0.0
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
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!
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
/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]
}
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.
Issues:
My doubts:
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
jsonwebtoken
8.5.1 has a security vulnerability: GHSA-27h2-hvpr-p74q. Please upgrade to 9.0.0.
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):
npm install -g firebase-tools
firebase login
firebase init functions
and choose Typescript. This essentially creates a Node Express project.import {AccessToken} from "livekit-server-sdk";
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.
when running deleteRoom() it throws an Error: Request failed with status code 401
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
With express + bodyParser.json, it's not straight forward to get the raw payload. (which is needed to validate sha).
It's possible to store the raw body with bodyParser's validate function. It'd be great if the SDK included this helper.
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
Steps to Reproduce
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:
Node.js package version:
@livekit/rtc-node: 0.5.0
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.