LiveKit JavaScript/TypeScript Client SDK

repository·main·Indexed 20 days ago

https://github.com/livekit/client-sdk-js

A JavaScript/TypeScript client SDK for LiveKit (v2.21.0) that enables developers to add real-time video, audio, and data features to web applications. It supports connecting to LiveKit Cloud and self-hosted servers, featuring tools for managing media tracks, device handling, Remote Procedure Calls (RPC), and adaptive streaming. The SDK provides high-level APIs for room connection, participant management, and custom MediaStreamTrack publishing.

Tokens
10.6K
Snippets
35
Records
51
Agent score
70%

What's inside livekit-client

  1. Perform Remote Procedure Calls (RPC)

    main

    LiveKit RPC allows participants to call predefined methods on other participants. This is useful for triggering actions in a client application from an Agent or another user.

    1. Register a method: Use room.localParticipant.registerRpcMethod(name, handler) to define a method that can be called remotely. The handler receives RpcInvocationData (including payload and callerIdentity) and should return a response.
    2. Perform a request: Use room.localParticipant.performRpc({ destinationIdentity, method, payload }) to invoke a method on a specific participant.

    Errors: If a handler throws an RpcError, the message is passed to the caller. Other errors arrive as a generic 1500 ("Application Error").

    // 1. Registering a method
    room.localParticipant?.registerRpcMethod(
      'greet',
      async (data: RpcInvocationData) => {
        return `Hello, ${data.callerIdentity}!`;
      }
    );
    
    // 2. Performing the call
    try {
      const response = await room.localParticipant!.performRpc({
        destinationIdentity: 'recipient-identity',
        method: 'greet',
        payload: 'Hello!',
      });
      console.log(response);
    } catch (error) {
      console.error('RPC call failed:', error);
    }
  2. Understand the SDK logging levels

    main

    The SDK follows a specific rubric for log levels to help you filter noise during development:

    • error: Unrecoverable failures (e.g., publish rejected by server, permanent decoding failure).
    • warn: Recoverable anomalies or automatic retries (e.g., ICE restarts, signal reconnection attempts).
    • info: Significant lifecycle transitions occurring roughly once per second (e.g., connecting, connected, track published, permission changes).
    • debug: High-frequency technical details (e.g., individual signal messages, SDP, ICE candidates, data channel lifecycle).
    • trace: Reserved for deep dives; unused by default.
  3. Use TokenSource to fetch credentials

    main

    A TokenSource is an abstraction for fetching server URLs and participant tokens. There are several types:

    • Fixed (TokenSource.literal): Returns static credentials or uses a function to compute them without external input.
    • Configurable (TokenSource.endpoint): Makes a POST (or other method) request to a URL. The request body follows the standard LiveKit token endpoint schema.
    • Configurable (TokenSource.developmentTokenServer): Uses a LiveKit-hosted sandbox token server (for prototyping only).
    • Configurable (TokenSource.custom): Allows you to implement your own logic for fetching tokens, which are then cached until they expire or options change.
    // Example: Using an endpoint token source
    const endpoint = TokenSource.endpoint("http://example.com/credentials-endpoint", {
      method: "PUT",
      headers: { "X-Custom-Header": "value" }
    });
    const response = await endpoint.fetch({ agentName: "my-agent" });
    await room.connect(response.serverUrl, response.participantToken);
  4. Check browser and feature support

    main

    The LiveKit SDK requires specific browser APIs. You can programmatically check for compatibility using the following helper functions:

    • isBrowserSupported(): Checks general compatibility with the required browser APIs.
    • supportsAdaptiveStream(): Checks if the browser supports adaptiveStream functionality.
    • supportsDynacast(): Checks if the browser supports dynacast functionality.

    Legacy Browser Support: If you are targeting legacy browsers, you may need to provide polyfills for ResizeObserver and IntersectionObserver to maintain adaptiveStream functionality. Additionally, ensure you transpile the library code using Babel and include necessary polyfills via core-js.

  5. Adjust logging verbosity per subsystem

    main
    The SDK uses loglevel and provides named loggers for different subsystems (defined in LoggerNames). You can increase or decrease the verbosity of a specific area of the SDK without affecting others by using setLogLevel(level, loggerName). This is useful for debugging specific components like the Engine or Signal without being overwhelmed by logs from other parts of the system.
  6. Install the LiveKit JavaScript/TypeScript SDK

    main

    You can install the livekit-client package using Yarn or NPM, or include it directly in your HTML via a CDN for projects without a package manager.

    Using Yarn

    yarn add livekit-client

    Using NPM

    npm install livekit-client --save

    Using Minified JS (CDN)

    Include the following script tag in your HTML:

    <script src="https://cdn.jsdelivr.net/npm/livekit-client/dist/livekit-client.umd.min.js"></script>

    When using the CDN version, all symbols are exported under the LivekitClient global namespace. You must prefix class names with LivekitClient.. For example, Room is accessed as LivekitClient.Room.

    npm install livekit-client --save
  7. Run the LiveKit RPC Demo

    main

    This demo provides a multi-participant implementation of the LiveKit RPC (Remote Procedure Call) feature. To run the demo locally, follow these steps:

    1. Configure Environment Variables: Create a .env.local file in the project root and populate it with your LiveKit credentials:
      • LIVEKIT_API_KEY
      • LIVEKIT_API_SECRET
      • LIVEKIT_URL
    2. Install Dependencies: Use pnpm to install the required packages.
    3. Start the Development Server: Run the dev command to launch the local server.
    4. Access the Demo: Open your browser to the local URL (usually http://localhost:5173) and interact with the UI to trigger the RPC demonstration.
    # 1. Setup .env.local
    # LIVEKIT_API_KEY=your_key
    # LIVEKIT_API_SECRET=your_secret
    # LIVEKIT_URL=your_url
    
    # 2. Install dependencies
    pnpm install
    
    # 3. Start server
    pnpm dev
  8. Run the Data Tracks Demo

    main

    The Data Tracks Demo demonstrates multi-participant real-time data transmission. One participant (the publisher) sends ASCII-encoded integers via a slider, while another participant (the subscriber) receives these values and renders them on a real-time chart.

    To run the demo locally, follow these steps:

    1. Configure Environment Variables: Create a .env.local file in the project root containing your LiveKit credentials:
      • LIVEKIT_API_KEY
      • LIVEKIT_API_SECRET
      • LIVEKIT_URL
    2. Install Dependencies: Use pnpm to install the required packages.
    3. Start the Development Server: Run the dev command.
    4. Access the App: Open your browser to the local URL (usually http://localhost:5173).
    5. Test Data Transmission: Connect two participants, ensure a data track is published, and use the slider to send data.
    # 1. Setup .env.local
    LIVEKIT_API_KEY=your_key
    LIVEKIT_API_SECRET=your_secret
    LIVEKIT_URL=your_url
    
    # 2. Install
    pnpm install
    
    # 3. Run
    pnpm dev
  9. Use structured context with loggers

    main

    The SDK supports structured logging via logContext objects. When using setLogExtension, you can receive full metadata for ingestion. To implement this efficiently in your own classes, use a context provider function when initializing a logger via getLogger. This ensures that any updates to your class's context are automatically reflected in every log call without needing to manually pass the context every time.

    // in a class constructor
    this.log = getLogger(LoggerNames.Engine, () => this.logContext);
    
    // at call sites
    this.log.debug('got ICE candidate from peer', { candidate, target });
    // devtools: got ICE candidate from peer, { room: 'foo', participant: 'alice', ..., candidate, target }
  10. Handle browser audio autoplay restrictions

    main

    Browsers often block audio playback unless triggered by user interaction. LiveKit monitors this via RoomEvent.AudioPlaybackStatusChanged. If room.canPlaybackAudio is false, you must call room.startAudio() inside a user-initiated event handler (like onclick or ontap) to enable audio playback for the session.

    room.on(RoomEvent.AudioPlaybackStatusChanged, () => {
      if (!room.canPlaybackAudio) {
        button.onclick = async () => {
          await room.startAudio();
          // Audio is now enabled for the session
          button.remove();
        };
      }
    });
  11. Connect to a room and publish audio/video

    main

    To start a LiveKit session, create a Room instance, optionally pre-warm the connection with prepareConnection, and then call connect. Once connected, you can publish tracks using localParticipant.enableCameraAndMicrophone() or by manually publishing MediaStreamTrack objects. Use RoomEvent listeners to handle remote tracks being subscribed or unsubscribed to attach them to HTML elements.

    import {
      Room,
      RoomEvent,
      Track,
    } from 'livekit-client';
    
    const room = new Room({
      adaptiveStream: true,
      dynacast: true,
    });
    
    const url = "ws://localhost:7800";
    const token = "...";
    
    // Pre-warm connection
    room.prepareConnection(url, token);
    
    // Set up event listeners
    room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
      if (track.kind === Track.Kind.Video || track.kind === Track.Kind.Audio) {
        const element = track.attach();
        parentElement.appendChild(element);
      }
    });
    
    // Connect
    await room.connect(url, token);
    
    // Publish tracks
    await room.localParticipant.enableCameraAndMicrophone();