Skip to content

Live API v2 #9215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: dl/live
Choose a base branch
from
Open

Live API v2 #9215

wants to merge 2 commits into from

Conversation

dlarocque
Copy link
Contributor

@dlarocque dlarocque commented Aug 19, 2025

Adds startAudioConversation, a new helper function for creating real-time voice conversations with the model.

The existing LiveSession API is low-level and requires a lot of boilerplate to manage microphone audio and playback. This helper handles all that complexity, making it much easier for developers to add voice features to their apps.

  • Handles microphone permissions and captures audio.
  • Processes raw audio into the format required by the server.
  • Plays back the model's audio response smoothly, without gaps or clicks.
  • Supports user interruptions (talking over the model).
  • Integrates function calling via a simple handler.
  • Includes unit tests with mocks for the Web Audio API.

Sample

const liveSession = await model.connect();
let conversationController;

// This function must be called from within a click handler.
async function startConversation() {
  try {
    conversationController = await startAudioConversation(liveSession);
  } catch (e) {
    // Handle AI-specific errors
    if (e instanceof AIError) {
      console.error("AI Error:", e.message);
    }
    // Handle microphone permission and hardware errors
    else if (e instanceof DOMException) {
      console.error("Microphone Error:", e.message);
    }
    // Handle other unexpected errors
    else {
      console.error("An unexpected error occurred:", e);
    }
  }
}

// Later, to stop the conversation:
// if (conversationController) {
//   await conversationController.stop();
// }

Copy link

changeset-bot bot commented Aug 19, 2025

⚠️ No Changeset found

Latest commit: 774fecc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@dlarocque dlarocque changed the base branch from main to dl/live August 19, 2025 19:19
@google-oss-bot
Copy link
Contributor

google-oss-bot commented Aug 20, 2025

Size Report 1

Affected Products

  • @firebase/ai

    TypeBase (3bb3f36)Merge (a95ef8c)Diff
    browser47.2 kB54.5 kB+7.26 kB (+15.4%)
    main50.6 kB58.0 kB+7.37 kB (+14.6%)
    module47.2 kB54.5 kB+7.26 kB (+15.4%)
  • firebase

    TypeBase (3bb3f36)Merge (a95ef8c)Diff
    firebase-ai.js37.3 kB43.3 kB+6.06 kB (+16.3%)

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/imVimFeD9F.html

@google-oss-bot
Copy link
Contributor

google-oss-bot commented Aug 20, 2025

Size Analysis Report 1

Affected Products

  • @firebase/ai

    • LiveGenerativeModel

      Size

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      size8.39 kB8.41 kB+26 B (+0.3%)
      size-with-ext-deps26.0 kB26.0 kB+26 B (+0.1%)
    • LiveSession

      Size

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      size4.92 kB4.95 kB+26 B (+0.5%)
      size-with-ext-deps22.5 kB22.5 kB+26 B (+0.1%)
    • ResponseModality

      Size

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      size2.47 kB2.49 kB+14 B (+0.6%)
      size-with-ext-deps20.0 kB20.0 kB+14 B (+0.1%)
    • getLiveGenerativeModel

      Size

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      size10.9 kB10.9 kB+26 B (+0.2%)
      size-with-ext-deps28.5 kB28.5 kB+26 B (+0.1%)
    • startAudioConversation

      Size

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      size?8.52 kB? (?)
      size-with-ext-deps?26.1 kB? (?)

      Dependency

      TypeBase (3bb3f36)Merge (a95ef8c)Diff
      functions?

      decodeInstanceIdentifier
      registerAI
      startAudioConversation

      ?
      classes?

      AIError
      AIService
      AudioConversationRunner
      Backend
      GoogleAIBackend
      VertexAIBackend

      ?
      variables?

      12 dependencies

      AIErrorCode
      AI_TYPE
      AUDIO_PROCESSOR_NAME
      BackendType
      DEFAULT_LOCATION
      SERVER_INPUT_SAMPLE_RATE
      SERVER_OUTPUT_SAMPLE_RATE
      Task
      audioProcessorWorkletString
      logger
      name
      version

      ?
      enums??

      External Dependency

      ModuleBase (3bb3f36)Merge (a95ef8c)Diff
      @firebase/app?

      _registerComponent
      registerVersion

      ?
      @firebase/component?

      Component

      ?
      @firebase/logger?

      Logger

      ?
      @firebase/util?

      FirebaseError

      ?

Test Logs

  1. https://storage.googleapis.com/firebase-sdk-metric-reports/WSfEIGEANz.html

@dlarocque dlarocque marked this pull request as ready for review August 21, 2025 19:15
@dlarocque dlarocque requested review from a team as code owners August 21, 2025 19:15
@@ -323,5 +323,9 @@ describe('Live', function () {
});
*/
});

describe('startAudioConversation', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there supposed to be something here?

/** A flag to indicate if the conversation has been stopped. */
private isStopped = false;
/** A resolver function for the `stopPromise`. */
private stopResolver!: () => void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to use a Deferred? I think this is the deferred pattern. Here's a usage: https://github.com/firebase/firebase-js-sdk/blob/realtime-for-web/packages/analytics/src/index.test.ts#L132 I don't know that you gain a lot except that it reads clearly that you're doing the deferred pattern, and it is a bit bulkier than you need (you don't need wrapCallback or reject). Maybe you can just refactor this so you put both stopPromise and stopResolver into a deferred object like:

  private stopDeferred: { promise: Promise<void>; resolve: () => void } = {
    resolve: () => {},
    promise: new Promise(resolve => {
      this.stopDeferred.resolve = resolve;
    })
  };

And then you just refer to this.stopDeferred.resolve() and this.stopDeferred.promise everywhere you reference them. That way it's clear this is a Deferred and they belong to each other.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants