diff --git a/.changeset/lemon-readers-eat.md b/.changeset/lemon-readers-eat.md new file mode 100644 index 00000000..942cc122 --- /dev/null +++ b/.changeset/lemon-readers-eat.md @@ -0,0 +1,5 @@ +--- +"@livekit/rtc-node": patch +--- + +Use shared mutex helper lib diff --git a/packages/livekit-rtc/package.json b/packages/livekit-rtc/package.json index c736b4e3..0d854481 100644 --- a/packages/livekit-rtc/package.json +++ b/packages/livekit-rtc/package.json @@ -34,13 +34,14 @@ }, "dependencies": { "@bufbuild/protobuf": "^1.4.2", + "@livekit/mutex": "^1.0.0", "@livekit/typed-emitter": "^3.0.0" }, "devDependencies": { "@napi-rs/cli": "^2.18.0", "@types/node": "^20.9.2", - "typescript": "^5.2.2", - "prettier": "^3.0.3" + "prettier": "^3.0.3", + "typescript": "^5.2.2" }, "optionalDependencies": { "@livekit/rtc-node-darwin-arm64": "workspace:*", diff --git a/packages/livekit-rtc/src/audio_stream.ts b/packages/livekit-rtc/src/audio_stream.ts index 809220ad..d012c9c2 100644 --- a/packages/livekit-rtc/src/audio_stream.ts +++ b/packages/livekit-rtc/src/audio_stream.ts @@ -1,13 +1,13 @@ // SPDX-FileCopyrightText: 2024 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 +import { Mutex } from '@livekit/mutex'; import { AudioFrame } from './audio_frame.js'; import type { FfiEvent } from './ffi_client.js'; import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js'; import type { AudioStreamInfo, NewAudioStreamResponse } from './proto/audio_frame_pb.js'; import { AudioStreamType, NewAudioStreamRequest } from './proto/audio_frame_pb.js'; import type { Track } from './track.js'; -import { Mutex } from './utils.js'; export class AudioStream implements AsyncIterableIterator { /** @internal */ diff --git a/packages/livekit-rtc/src/utils.test.ts b/packages/livekit-rtc/src/utils.test.ts deleted file mode 100644 index 7ff0a0f1..00000000 --- a/packages/livekit-rtc/src/utils.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -// 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); - }); -}); diff --git a/packages/livekit-rtc/src/utils.ts b/packages/livekit-rtc/src/utils.ts deleted file mode 100644 index e2596f9d..00000000 --- a/packages/livekit-rtc/src/utils.ts +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-FileCopyrightText: 2024 LiveKit, Inc. -// -// SPDX-License-Identifier: Apache-2.0 -export class Mutex { - #locking: Promise; - #locks: number; - #limit: number; - - constructor(limit = 1) { - this.#locking = Promise.resolve(); - this.#locks = 0; - this.#limit = limit; - } - - isLocked(): boolean { - return this.#locks >= this.#limit; - } - - async lock(): Promise<() => void> { - if (this.#locks >= this.#limit) { - await this.#locking; - } - - this.#locks += 1; - - let unlock: () => void; - let unlocked = false; - - const willLock = new Promise( - (resolve) => - (unlock = () => { - if (unlocked) { - throw new Error('This unlock method has already been called'); - } - unlocked = true; - this.#locks -= 1; - resolve(); - }), - ); - - this.#locking = this.#locking.then(() => willLock); - return unlock; - } -} diff --git a/packages/livekit-rtc/src/video_stream.ts b/packages/livekit-rtc/src/video_stream.ts index 6de71231..aaf57162 100644 --- a/packages/livekit-rtc/src/video_stream.ts +++ b/packages/livekit-rtc/src/video_stream.ts @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: 2024 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 +import { Mutex } from '@livekit/mutex'; import type { FfiEvent } from './ffi_client.js'; import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js'; import type { @@ -10,7 +11,6 @@ import type { } from './proto/video_frame_pb.js'; import { NewVideoStreamRequest, VideoStreamType } from './proto/video_frame_pb.js'; import type { Track } from './track.js'; -import { Mutex } from './utils.js'; import { VideoFrame } from './video_frame.js'; export type VideoFrameEvent = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8773746e..c83e7bf0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -149,6 +149,9 @@ importers: '@bufbuild/protobuf': specifier: ^1.4.2 version: 1.10.0 + '@livekit/mutex': + specifier: ^1.0.0 + version: 1.0.0 '@livekit/typed-emitter': specifier: ^3.0.0 version: 3.0.0 @@ -715,6 +718,9 @@ packages: '@livekit/changesets-changelog-github@0.0.4': resolution: {integrity: sha512-MXaiLYwgkYciZb8G2wkVtZ1pJJzZmVx5cM30Q+ClslrIYyAqQhRbPmZDM79/5CGxb1MTemR/tfOM25tgJgAK0g==} + '@livekit/mutex@1.0.0': + resolution: {integrity: sha512-aiUhoThBNF9UyGTxEURFzJLhhPLIVTnQiEVMjRhPnfHNKLfo2JY9xovHKIus7B78UD5hsP6DlgpmAsjrz4U0Iw==} + '@livekit/protocol@1.24.0': resolution: {integrity: sha512-9dCsqnkMn7lvbI4NGh18zhLDsrXyUcpS++TEFgEk5Xv1WM3R2kT3EzqgL1P/mr3jaabM6rJ8wZA/KJLuQNpF5w==} @@ -3499,6 +3505,8 @@ snapshots: transitivePeerDependencies: - encoding + '@livekit/mutex@1.0.0': {} + '@livekit/protocol@1.24.0': dependencies: '@bufbuild/protobuf': 1.10.0