Skip to content

Commit

Permalink
Merge branch 'main' into nbsp/add/audioresampler
Browse files Browse the repository at this point in the history
  • Loading branch information
nbsp authored Oct 3, 2024
2 parents e600623 + 5d0edf3 commit b229e96
Show file tree
Hide file tree
Showing 16 changed files with 237 additions and 138 deletions.
7 changes: 7 additions & 0 deletions .changeset/empty-eggs-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@livekit/rtc-node": patch
"livekit-server-sdk": patch
---

Fix mutex in livekit-rtc
Fix linter warnings in livekit-server-sdk
84 changes: 50 additions & 34 deletions .github/workflows/rtc-node.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Test, build, release
name: CI
env:
APP_NAME: rtc-node
MACOSX_DEPLOYMENT_TARGET: '10.13'
Expand All @@ -21,61 +21,77 @@ on:
- main

jobs:
lint:
name: Lint & Test
check-changes:
name: Check for changes
runs-on: ubuntu-latest
outputs:
rtc_build: ${{ steps.changes.outputs.rtc_build }}
server_sdk_build: ${{ steps.changes.outputs.server_sdk_build }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: paths
with:
filters: |
livekit-rtc:
- 'packages/livekit-rtc/**'
server-sdk:
- 'packages/livekit-server-sdk/**'
- name: Store change outputs
id: changes
run: |
echo "rtc_build=${{ steps.paths.outputs.livekit-rtc == 'true' || github.ref == 'refs/heads/main' }}" >> $GITHUB_OUTPUT
echo "server_sdk_build=${{ steps.paths.outputs.server-sdk == 'true' || github.ref == 'refs/heads/main' }}" >> $GITHUB_OUTPUT
lint:
name: Formatting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4

- name: Use Node.js 20
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'

- name: REUSE-4.0 compliance check
uses: fsfe/reuse-action@v4

cache: pnpm
- name: Install dependencies
run: pnpm install

- name: Lint
run: pnpm lint

- name: Prettier
run: pnpm format:check

- name: Test Node env livekit-server-sdk
run: pnpm --filter="livekit-server-sdk" test
reuse:
name: REUSE-3.2
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: fsfe/reuse-action@v4

- name: Test browser env livekit-server-sdk
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Test livekit-rtc
run: pnpm --filter="livekit-rtc" test
- name: Test livekit-server-sdk (Node)
run: pnpm --filter="livekit-server-sdk" test
- name: Test livekit-server-sdk (Browser)
run: pnpm --filter="livekit-server-sdk" test:browser

- name: Test edge runtime env livekit-server-sdk
- name: Test env livekit-server-sdk (Edge Runtime)
run: pnpm --filter="livekit-server-sdk" test:edge

- uses: dorny/paths-filter@v3
id: paths
with:
filters: |
livekit-rtc:
- 'packages/livekit-rtc/**'
server-sdk:
- 'packages/livekit-server-sdk/**'
- name: Store change outputs
id: changes
run: |
echo "rtc_build=${{ steps.paths.outputs.livekit-rtc == 'true' || github.ref == 'refs/heads/main' }}" >> $GITHUB_OUTPUT
echo "server_sdk_build=${{ steps.paths.outputs.server-sdk == 'true' || github.ref == 'refs/heads/main' }}" >> $GITHUB_OUTPUT
build:
if: ${{ needs.lint.outputs.rtc_build == 'true' }}
if: ${{ needs.check-changes.outputs.rtc_build == 'true' }}
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -104,7 +120,7 @@ jobs:
runs-on: ${{ matrix.os }}
env:
RUST_BACKTRACE: full
needs: lint
needs: check-changes
steps:
- uses: actions/checkout@v4
with:
Expand Down
47 changes: 47 additions & 0 deletions packages/livekit-rtc/src/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
//
// SPDX-License-Identifier: Apache-2.0
import { describe, expect, it } from 'vitest';
import { Mutex } from './utils';

describe('Mutex', () => {
it('should not be locked initially', () => {
const mutex = new Mutex();
expect(mutex.isLocked()).toBe(false);
});

it('should lock and unlock correctly', async () => {
const mutex = new Mutex();
const unlock = await mutex.lock();
expect(mutex.isLocked()).toBe(true);
unlock();
expect(mutex.isLocked()).toBe(false);
});

it('should handle multiple locks', async () => {
const mutex = new Mutex(2);
const unlock1 = await mutex.lock();
const unlock2 = await mutex.lock();
expect(mutex.isLocked()).toBe(true);
unlock1();
expect(mutex.isLocked()).toBe(false);
const unlock3 = await mutex.lock();
expect(mutex.isLocked()).toBe(true);
unlock2();
expect(mutex.isLocked()).toBe(false);
unlock3();
expect(mutex.isLocked()).toBe(false);
});

it('should throw an error when unlocking the same lock twice', async () => {
const mutex = new Mutex(2);
const unlock1 = await mutex.lock();
const unlock2 = await mutex.lock();
expect(mutex.isLocked()).toBe(true);
unlock1();
expect(mutex.isLocked()).toBe(false);
expect(() => unlock1()).toThrow('This unlock method has already been called');
unlock2();
expect(mutex.isLocked()).toBe(false);
});
});
16 changes: 12 additions & 4 deletions packages/livekit-rtc/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@ export class Mutex {
}

async lock(): Promise<() => void> {
if (this.#locks >= this.#limit) {
await this.#locking;
}

this.#locks += 1;

let unlockNext: () => void;
let unlock: () => void;
let unlocked = false;

const willLock = new Promise<void>(
(resolve) =>
(unlockNext = () => {
(unlock = () => {
if (unlocked) {
throw new Error('This unlock method has already been called');
}
unlocked = true;
this.#locks -= 1;
resolve();
}),
);

const willUnlock = this.#locking.then(() => unlockNext);
this.#locking = this.#locking.then(() => willLock);
return willUnlock;
return unlock;
}
}
3 changes: 2 additions & 1 deletion packages/livekit-rtc/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
"sourceMap": true,
"outDir": "dist"
},
"include": ["src/**/*.ts"]
"include": ["src/**/*.ts"],
"exclude": ["src/**/*.test.ts", "vite.config.ts"],
}
File renamed without changes.
4 changes: 2 additions & 2 deletions packages/livekit-server-sdk/src/AccessToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ export class AccessToken {

/**
* Creates a new AccessToken
* @param apiKey API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret Secret, can be set in env LIVEKIT_API_SECRET
* @param apiKey - API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret - Secret, can be set in env LIVEKIT_API_SECRET
*/
constructor(apiKey?: string, apiSecret?: string, options?: AccessTokenOptions) {
if (!apiKey) {
Expand Down
60 changes: 32 additions & 28 deletions packages/livekit-server-sdk/src/EgressClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,19 @@ export class EgressClient extends ServiceBase {
private readonly rpc: Rpc;

/**
* @param host hostname including protocol. i.e. 'https://cluster.livekit.io'
* @param apiKey API Key, can be set in env var LIVEKIT_API_KEY
* @param secret API Secret, can be set in env var LIVEKIT_API_SECRET
* @param host - hostname including protocol. i.e. 'https://cluster.livekit.io'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
*/
constructor(host: string, apiKey?: string, secret?: string) {
super(apiKey, secret);
this.rpc = new TwirpRpc(host, livekitPackage);
}

/**
* @param roomName room name
* @param output file or stream output
* @param opts RoomCompositeOptions
* @param roomName - room name
* @param output - file or stream output
* @param opts - RoomCompositeOptions
*/
async startRoomCompositeEgress(
roomName: string,
Expand Down Expand Up @@ -213,9 +213,9 @@ export class EgressClient extends ServiceBase {
}

/**
* @param url url
* @param output file or stream output
* @param opts WebOptions
* @param url - url
* @param output - file or stream output
* @param opts - WebOptions
*/
async startWebEgress(
url: string,
Expand Down Expand Up @@ -259,9 +259,9 @@ export class EgressClient extends ServiceBase {
/**
* Export a participant's audio and video tracks,
*
* @param roomName room name
* @param output one or more outputs
* @param opts ParticipantEgressOptions
* @param roomName - room name
* @param output - one or more outputs
* @param opts - ParticipantEgressOptions
*/
async startParticipantEgress(
roomName: string,
Expand Down Expand Up @@ -291,9 +291,9 @@ export class EgressClient extends ServiceBase {
}

/**
* @param roomName room name
* @param output file or stream output
* @param opts TrackCompositeOptions
* @param roomName - room name
* @param output - file or stream output
* @param opts - TrackCompositeOptions
*/
async startTrackCompositeEgress(
roomName: string,
Expand Down Expand Up @@ -361,6 +361,7 @@ export class EgressClient extends ServiceBase {
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private isEncodedOutputs(output: any): output is EncodedOutputs {
return (
(<EncodedOutputs>output).file !== undefined ||
Expand All @@ -369,13 +370,15 @@ export class EgressClient extends ServiceBase {
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private isEncodedFileOutput(output: any): output is EncodedFileOutput {
return (
(<EncodedFileOutput>output).filepath !== undefined ||
(<EncodedFileOutput>output).fileType !== undefined
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private isSegmentedFileOutput(output: any): output is SegmentedFileOutput {
return (
(<SegmentedFileOutput>output).filenamePrefix !== undefined ||
Expand All @@ -384,6 +387,7 @@ export class EgressClient extends ServiceBase {
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
private isStreamOutput(output: any): output is StreamOutput {
return (
(<StreamOutput>output).protocol !== undefined || (<StreamOutput>output).urls !== undefined
Expand Down Expand Up @@ -492,9 +496,9 @@ export class EgressClient extends ServiceBase {
}

/**
* @param roomName room name
* @param output file or websocket output
* @param trackId track Id
* @param roomName - room name
* @param output - file or websocket output
* @param trackId - track Id
*/
async startTrackEgress(
roomName: string,
Expand Down Expand Up @@ -540,8 +544,8 @@ export class EgressClient extends ServiceBase {
}

/**
* @param egressId
* @param layout
* @param egressId -
* @param layout -
*/
async updateLayout(egressId: string, layout: string): Promise<EgressInfo> {
const data = await this.rpc.request(
Expand All @@ -554,9 +558,9 @@ export class EgressClient extends ServiceBase {
}

/**
* @param egressId
* @param addOutputUrls
* @param removeOutputUrls
* @param egressId -
* @param addOutputUrls -
* @param removeOutputUrls -
*/
async updateStream(
egressId: string,
Expand All @@ -576,17 +580,17 @@ export class EgressClient extends ServiceBase {
}

/**
* @param options options to filter listed Egresses, by default returns all
* @param options - options to filter listed Egresses, by default returns all
* Egress instances
*/
async listEgress(options?: ListEgressOptions): Promise<Array<EgressInfo>>;
/**
* @deprecated
* @param roomName list egress for one room only
* @deprecated use `listEgress(options?: ListEgressOptions)` instead
* @param roomName - list egress for one room only
*/
async listEgress(roomName?: string): Promise<Array<EgressInfo>>;
/**
* @param roomName list egress for one room only
* @param roomName - list egress for one room only
*/
async listEgress(options?: string | ListEgressOptions): Promise<Array<EgressInfo>> {
let req: Partial<ListEgressRequest> = {};
Expand All @@ -606,7 +610,7 @@ export class EgressClient extends ServiceBase {
}

/**
* @param egressId
* @param egressId -
*/
async stopEgress(egressId: string): Promise<EgressInfo> {
const data = await this.rpc.request(
Expand Down
Loading

0 comments on commit b229e96

Please sign in to comment.