The Google Meet Live Sharing SDK is in preview. Developers can apply for access through our Early Access Program.

Get started

You can start integrating the Google Meet Live Sharing SDK into your Android app using Java.

You can find Android documentation and additional Android libraries to expand the functionality and features of your app through the official Android Developers Documentation.

Using the SDK

The first step to begin Google Meet Live Sharing is to call LiveSharingClientFactory.getClient(). This returns a LiveSharingClient that can be used to start a co-watching activity, a co-doing activity, or both.

The co-watching and co-doing APIs are independent and can be used in parallel with each other.

Java

/** Provides a {@link LiveSharingClient}. */
public final class LiveSharingClientFactory {
  /** Returns the singleton instance of {@link LiveSharingClient}. */
  public static LiveSharingClient getClient();
}

/**
 * Primary interface for starting and stopping live sharing with Meet as the live video
 * provider.
 */
public interface LiveSharingClient {
  /**
   * Returns the status of ongoing Meet sessions, if any. This is a single, one-time check.
   *
   * <p>Utilized to detect any ongoing Meet standalone or live sharing sessions. In the event of
   * detected active sessions, will return {@link LiveSharingMeetingInfo} with the {@link
   * MeetingStatus} member set as {@link MeetingStatus#CONNECTED} or {@link
   * MeetingStatus#CONNECTED_WITH_LIVE_SHARING}. No active session returns {@link
   * MeetingStatus#NOT_CONNECTED}
   *
   * <p>Accepts {@link Optional} of {@link Handler} as parameter for application controlled thread
   * management. In the absence of {@link Handler}, one will be spawned during execution. Only allow
   * this if you do not care to have control over the {@link Handler} instance.
   *
   * @param appContext the {@link Context#getApplicationContext()} value of the application that is
   *     using the Meet Live Sharing SDK.
   * @param handler an {@link Optional} of {@link Handler} for asynchronous execution
   * @return A {@link ListenableFuture} of {@link LiveSharingMeetingInfo} describing the status of
   *     the current meeting, if any.
   */
  ListenableFuture<LiveSharingMeetingInfo> queryMeeting(
      Context appContext, Optional<Handler> handler);

  /**
   * Connects to a meeting, either by creating a meeting or by connecting to an ongoing meeting.
   *
   * <p>If a meeting is created, the current user will be the only participant initially.
   *
   * <p>The returned URL is intended to be exposed to the user to be manually shared with their
   * intended live sharing group.
   *
   * <p>If this method is called before calling {@link #disconnectMeeting} for an existing meeting,
   * the future will fail with an {@link IllegalStateException}.
   *
   * @param appContext the {@link Context#getApplicationContext()} value of the application that is
   *     using the Meet Live Sharing SDK.
   * @param liveSharingApplicationName the globally-unique canonical name for the Live Sharing App
   *     connecting to Meet, e.g. {@code youtube}.
   * @param meetingDisconnectHandler a {@link MeetingDisconnectHandler} to receive notification when
   *     the Meet client has disconnected.
   * @return A {@link ListenableFuture} which will resolve with a {@link LiveSharingMeetingInfo}
   *     object if the connection was successful; or to an {@link IllegalStateException} if already
   *     connected to a meeting (i.e. {@link #disconnectMeeting} was not called); or to a {@link
   *     LiveSharingException} if there was an unexpected error.
   * @throws NullPointerException if any of the provided arguments are null.
   * @throws IllegalStateException if {@code liveSharingApplicationName} is an empty string or isn't
   *     part of the onboarded list of Apps.
   */
  ListenableFuture<LiveSharingMeetingInfo> connectMeeting(
      Context appContext,
      String liveSharingApplicationName,
      MeetingDisconnectHandler meetingDisconnectHandler);

  /**
   * Disconnects the user from the connected meeting, but does not force Meet to end the meeting.
   *
   * @return A {@link ListenableFuture} which evaluates to success if the user successfully left the
   *     meeting; or to an {@link IllegalStateException} if not connected to a meeting (i.e. {@link
   *     #connectMeeting} was not called); or to a {@link LiveSharingException} if there was an
   *     unexpected error.
   */
  ListenableFuture<Void> disconnectMeeting();

  /**
   * Begins a {@link CoDoingSession}.
   *
   * <p><b>Note:</b> Only one co-doing session can be active at one time.
   *
   * @return A {@link ListenableFuture} which evaluates to a {@link CoDoingSession} instance if a
   *     co-doing session was successfully started; or to an {@link IllegalStateException} if not
   *     connected to a meeting or if another co-doing session is still running (i.e. {@link
   *     #endCoDoing} was not called); or to a {@link LiveSharingException} if there was an
   *     unexpected error.
   * @throws NullPointerException if {@code delegate} is null.
   */
  ListenableFuture<CoDoingSession> beginCoDoing(CoDoingSessionDelegate delegate);

  /**
   * Ends the current {@link CoDoingSession}.
   *
   * @return A {@link ListenableFuture} which evaluates to success if the co-doing session
   *     successfully ended; or to an {@link IllegalStateException} if not connected to a meeting or
   *     if there is no ongoing co-doing session (i.e. {@link #beginCoDoing} was not called); or to
   *     a {@link LiveSharingException} if there was an unexpected error.
   */
  ListenableFuture<Void> endCoDoing();

  /**
   * Begins a {@link CoWatchingSession}.
   *
   * <p><b>Note:</b> Only one co-watching session can be active at one time.
   *
   * @return A {@link ListenableFuture} which evaluates to a {@link CoWatchingSession} instance if a
   *     co-watching session was successfully started; or to an {@link IllegalStateException} if not
   *     connected to a meeting or if another co-watching session is still running (i.e. {@link
   *     #endCoWatching} was not called); or to a {@link LiveSharingException} if there was an
   *     unexpected error.
   * @throws NullPointerException if {@code delegate} is null.
   */
  ListenableFuture<CoWatchingSession> beginCoWatching(CoWatchingSessionDelegate delegate);

  /**
   * Ends the current {@link CoWatchingSession}.
   *
   * @return A {@link ListenableFuture} which evaluates to success if the co-watching session
   *     successfully ended; or to an {@link IllegalStateException} if not connected to a meeting or
   *     if there is no ongoing co-watching session (i.e. {@link #beginCoWatching} was not called);
   *     or to a {@link LiveSharingException} if there was an unexpected error.
   */
  ListenableFuture<Void> endCoWatching();
}

interface CoWatchingSessionDelegate {
  /**
   * Apply the supplied state to media playout, up to and including switching to a new
   * media stream if the mediaId changes.
   *
   * @param state the new state to be applied to the player.
   */
  void applyCoWatchingState(CoWatchingState state);

  /**
   * Return the current state of the local media playout. This is called regularly, so it
   * should be written to be performant.
   *
   * @return a {@link CoWatchingState} describing the current state.
   */
  Optional<CoWatchingState> queryCoWatchingState();
}

interface CoDoingSessionDelegate {
  /**
   * Callback for state updates broadcast by other participants in the meeting.
   *
   * @param update the {@link CoDoingState} update to be applied.
   */
  void applyUpdate(CoDoingState update);

  /**
   * Callback to retrieve the state of live sharing. This is called regularly, so it
   * should be written to be performant.
   *
   * @return the current {@link CoDoingState} of the live sharing app.
   */
  CoDoingState queryCoDoingState();
}

Co-watching API

Java

abstract class CoWatchingState {
  /**
   * Returns the identifier for the media being played.
   *
   * <p><b>Note:</b> the actual format only matters to co-watching app.
   */
  public abstract String mediaId();

  /** Returns the position of the media playout. */
  public abstract Duration mediaPlayoutPosition();

  /** Returns the playout rate, where {@code 1.0} is regular speed. */
  public abstract double mediaPlayoutRate();

  /** Represents the state of media playback. */
  public enum PlaybackState {
    /** The media is buffering and will begin playback when ready. */
    BUFFERING,
    /** The media is playing. */
    PLAY,
    /** The media is paused. */
    PAUSE,
    /** The media player reached the end of the current media. */
    ENDED
  }

  /** Returns the state of media playback. */
  public abstract PlaybackState playbackState();
}

/**
 * Provides common methods for interacting with Meet, primarily around informing Meet
 * of recent user actions (such as play, pause, and seek), and also relevant environmental
 * factors like delays due to buffering media.
 */
interface CoWatchingSession {
  /**
   * Notify Meet that the user has switched media, so Meet can pass that along to other users.
   *
   * @param mediaTitle the title of the media switched to. This title is reflected in the Meet
   *     UI when other users are considering connecting to the co-watching session.
   * @param mediaId the string URI of the media switched to.
   * @param mediaPlayoutPosition the position at which the media began playout.

   */
  void notifySwitchedToMedia(String mediaTitle, String mediaId, Duration mediaPlayoutPosition);

  /**
   * Notify Meet the user has paused or unpaused the playback of media, so Meet can mirror that
   * action for other users.
   *
   * @param paused the new paused or unpaused state.
   */
  void notifyPauseState(boolean paused);

  /**
   * Notify Meet the user has sought the playback point of the media, so Meet can mirror that
   * action for other users.
   *
   * @param mediaPlayoutPosition the timestamp to which the user sought.
   */
  void notifySeekToTimestamp(Duration mediaPlayoutPosition);

  /**
   * Notifies Meet the user has updated the playout rate of the media to a new value (for
   * example, 1.25x).
   *
   * @param rate the rate at which media is now being played out.
   */
  void notifyPlayoutRate(double rate);

  /**
   * Notifies Meet the media is not ready to be played out due to buffering, a prior
   * {@link CoWatchingSessionDelegate.#switch()}, {@link CoWatchingSessionDelegate.#seek()}, or normal
   * network congestion.
   *
   * @param mediaPlayoutPosition the timestamp at which the media is paused, waiting for
   *     buffering to complete.
   */
  void notifyBuffering(Duration mediaPlayoutPosition);

  /**
   * Notifies Meet buffering is complete and the media is now ready to be played out,
   * starting at the supplied timestamp.
   *
   * @param mediaPlayoutPosition the timestamp at which the media is buffered and ready to play.
   */
  void notifyReady(Duration mediaPlayoutPosition);
}

Co-doing API

The co-doing version is semantically much simpler than co-watching as it passes around arbitrary state blobs between participants:

Java

abstract class CoDoingState {
  // Opaque binary-encoded state update
  public abstract ByteString state();
}

interface CoDoingSession {
  /**
   * Broadcasts state to all other participants, and becomes the default state for any
   * participants until some other state is broadcast.
   *
   * @param updatedCoDoingState the updated activity state to be broadcast to other
   *     participants.
   */
  void broadcastStateUpdate(CoDoingState updatedCoDoingState);
}