chromium/chromecast/starboard/media/media/starboard_api_wrapper.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// The structs/enums in this file represent corresponding structs/enums in
// starboard. By using these types instead of Starboard's, we can abstract away
// minor changes (e.g. function renames) in Starboard without having to change
// the rest of the MediaPipelineBackend. Additionally, these types can be
// converted to different version-specific Starboard types.
//
// Users of this header should interact with Starboard via a StarboardApiWrapper
// created via GetStarboardApiWrapper(). For testing purposes, a mock
// StarboardApiWrapper can be used instead.

#ifndef CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_
#define CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_

#include <cstdint>
#include <cstring>
#include <memory>

namespace chromecast {
namespace media {

// Copy of SbMediaSupportType from starboard.
enum StarboardMediaSupportType {
  kStarboardMediaSupportTypeNotSupported,
  kStarboardMediaSupportTypeMaybe,
  kStarboardMediaSupportTypeProbably,
};

// Copy of SbMediaType from starboard.
enum StarboardMediaType {
  kStarboardMediaTypeAudio,
  kStarboardMediaTypeVideo,
};

// Copy of SbMediaAudioCodec from starboard.
enum StarboardAudioCodec {
  kStarboardAudioCodecNone,
  kStarboardAudioCodecAac,
  kStarboardAudioCodecAc3,
  kStarboardAudioCodecEac3,
  kStarboardAudioCodecOpus,
  kStarboardAudioCodecVorbis,
  kStarboardAudioCodecMp3,
  kStarboardAudioCodecFlac,
  kStarboardAudioCodecPcm,
};

// Copy of SbMediaVideoCodec from starboard.
enum StarboardVideoCodec {
  kStarboardVideoCodecNone,
  kStarboardVideoCodecH264,
  kStarboardVideoCodecH265,
  kStarboardVideoCodecMpeg2,
  kStarboardVideoCodecTheora,
  kStarboardVideoCodecVc1,
  kStarboardVideoCodecAv1,
  kStarboardVideoCodecVp8,
  kStarboardVideoCodecVp9,
};

// Copy of SbPlayerSampleSideDataType from starboard.
enum StarboardSampleSideDataType {
  kStarboardSampleSideDataTypeMatroskaBlockAdditional,
};

// Copy of SbPlayerDecoderState from starboard.
enum StarboardDecoderState {
  kStarboardDecoderStateNeedsData,
};

// Copy of SbPlayerOutputMode from starboard.
enum StarboardPlayerOutputMode {
  kStarboardPlayerOutputModeDecodeToTexture,
  kStarboardPlayerOutputModePunchOut,
  kStarboardPlayerOutputModeInvalid,
};

// Copy of SbPlayerState from starboard.
enum StarboardPlayerState {
  kStarboardPlayerStateInitialized,
  kStarboardPlayerStatePrerolling,
  kStarboardPlayerStatePresenting,
  kStarboardPlayerStateEndOfStream,
  kStarboardPlayerStateDestroyed,
};

// Copy of SbPlayerError from starboard.
enum StarboardPlayerError {
  kStarboardPlayerErrorDecode,
  kStarboardPlayerErrorCapabilityChanged,
  kStarboardPlayerErrorMax,
};

// Copy of SbDrmEncryptionScheme from starboard.
enum StarboardDrmEncryptionScheme {
  kStarboardDrmEncryptionSchemeAesCtr,
  kStarboardDrmEncryptionSchemeAesCbc,
};

// Copy of SbDrmStatus from starboard.
enum StarboardDrmStatus {
  kStarboardDrmStatusSuccess,
  kStarboardDrmStatusTypeError,
  kStarboardDrmStatusNotSupportedError,
  kStarboardDrmStatusInvalidStateError,
  kStarboardDrmStatusQuotaExceededError,
  kStarboardDrmStatusUnknownError,
};

// Copy of SbDrmSessionRequestType from starboard.
enum StarboardDrmSessionRequestType {
  kStarboardDrmSessionRequestTypeLicenseRequest,
  kStarboardDrmSessionRequestTypeLicenseRenewal,
  kStarboardDrmSessionRequestTypeLicenseRelease,
  kStarboardDrmSessionRequestTypeIndividualizationRequest,
};

// Copy of SbDrmKeyStatus from starboard.
enum StarboardDrmKeyStatus {
  kStarboardDrmKeyStatusUsable,
  kStarboardDrmKeyStatusExpired,
  kStarboardDrmKeyStatusReleased,
  kStarboardDrmKeyStatusRestricted,
  kStarboardDrmKeyStatusDownscaled,
  kStarboardDrmKeyStatusPending,
  kStarboardDrmKeyStatusError,
};

// Copy of SbMediaMasteringMetadata from starboard.
struct StarboardMediaMasteringMetadata {
  float primary_r_chromaticity_x;
  float primary_r_chromaticity_y;
  float primary_g_chromaticity_x;
  float primary_g_chromaticity_y;
  float primary_b_chromaticity_x;
  float primary_b_chromaticity_y;
  float white_point_chromaticity_x;
  float white_point_chromaticity_y;
  float luminance_max;
  float luminance_min;
};

// Copy of SbMediaMasteringMetadata from starboard.
struct StarboardColorMetadata {
  unsigned int bits_per_channel;
  unsigned int chroma_subsampling_horizontal;
  unsigned int chroma_subsampling_vertical;
  unsigned int cb_subsampling_horizontal;
  unsigned int cb_subsampling_vertical;
  unsigned int chroma_siting_horizontal;
  unsigned int chroma_siting_vertical;
  StarboardMediaMasteringMetadata mastering_metadata;
  unsigned int max_cll;
  unsigned int max_fall;
  // See SbMediaPrimaryId from starboard.
  int primaries;
  // See SbMediaTransferId from starboard.
  int transfer;
  // See SbMediaMatrixId from starboard.
  int matrix;
  // See SbMediaRangeId from starboard.
  int range;
  float custom_primary_matrix[12];
};

// Copy of SbMediaAudioSampleInfo from starboard.
struct StarboardAudioSampleInfo {
  StarboardAudioCodec codec;
  const char* mime;
  uint16_t format_tag;
  uint16_t number_of_channels;
  uint32_t samples_per_second;
  uint32_t average_bytes_per_second;
  uint16_t block_alignment;
  uint16_t bits_per_sample;
  uint16_t audio_specific_config_size;
  const void* audio_specific_config;
};

// Copy of SbMediaVideoSampleInfo from starboard.
struct StarboardVideoSampleInfo {
  StarboardVideoCodec codec;
  const char* mime;
  const char* max_video_capabilities;
  bool is_key_frame;
  int frame_width;
  int frame_height;
  StarboardColorMetadata color_metadata;
};

// Copy of SbPlayerSampleSideData from starboard.
struct StarboardSampleSideData {
  StarboardSampleSideDataType type;
  const uint8_t* data;
  size_t size;
};

// Copy of SbDrmEncryptionPattern from starboard.
struct StarboardDrmEncryptionPattern {
  uint32_t crypt_byte_block;
  uint32_t skip_byte_block;
};

// Copy of SbDrmSubSampleMapping from starboard.
struct StarboardDrmSubSampleMapping {
  // How many bytes of the corresponding subsample are not encrypted
  int32_t clear_byte_count;

  // How many bytes of the corresponding subsample are encrypted.
  int32_t encrypted_byte_count;
};

// Copy of SbDrmSampleInfo from starboard.
struct StarboardDrmSampleInfo {
  StarboardDrmEncryptionScheme encryption_scheme;

  // The encryption pattern of this sample.
  StarboardDrmEncryptionPattern encryption_pattern;

  // The Initialization Vector needed to decrypt this sample.
  uint8_t initialization_vector[16];
  int initialization_vector_size;

  // The ID of the license (or key) required to decrypt this sample. For
  // PlayReady, this is the license GUID in packed little-endian binary form.
  uint8_t identifier[16];
  int identifier_size;

  // The number of subsamples in this sample, must be at least 1.
  int32_t subsample_count;

  // The clear/encrypted mapping of each subsample in this sample. This must be
  // an array of |subsample_count| mappings.
  const StarboardDrmSubSampleMapping* subsample_mapping;
};

// Copy of SbPlayerSampleInfo from starboard.
struct StarboardSampleInfo {
  // See SbMediaType.
  int type;
  // Points to the buffer containing the sample data.
  const void* buffer;
  // Size of the data pointed to by |buffer|.
  int buffer_size;
  // The timestamp of the sample.
  int64_t timestamp;
  // Points to an array of side data for the input, when available.
  StarboardSampleSideData* side_data;
  // The number of side data pointed by |side_data|.  It should be set to 0 if
  // there is no side data for the input.
  int side_data_count;
  union {
    // Information about an audio sample. This value can only be used when
    // |type| is kSbMediaTypeAudio.
    StarboardAudioSampleInfo audio_sample_info;
    // Information about a video sample. This value can only be used when |type|
    // is kSbMediaTypeVideo.
    StarboardVideoSampleInfo video_sample_info;
  };
  // The DRM system related info for the media sample. This value is required
  // for encrypted samples. Otherwise, it must be |NULL|.
  const StarboardDrmSampleInfo* drm_info;
};

// Copy of SbPlayerCreationParam from starboard.
struct StarboardPlayerCreationParam {
  // Note: a DRM system is not included in this struct. Due to the architecture
  // of cast, the MediaPipelineBackend does not have direct access to the CDM.
  // So instead we pass a global to Starboard (in starboard_media_api.cc).

  // Contains a populated SbMediaAudioSampleInfo if |audio_sample_info.codec|
  // isn't |kSbMediaAudioCodecNone|.  When |audio_sample_info.codec| is
  // |kSbMediaAudioCodecNone|, the video doesn't have an audio track.
  StarboardAudioSampleInfo audio_sample_info;

  // Contains a populated SbMediaVideoSampleInfo if |video_sample_info.codec|
  // isn't |kSbMediaVideoCodecNone|.  When |video_sample_info.codec| is
  // |kSbMediaVideoCodecNone|, the video is audio only.
  StarboardVideoSampleInfo video_sample_info;

  // Selects how the decoded video frames will be output.  For example,
  // |kSbPlayerOutputModePunchOut| indicates that the decoded video frames will
  // be output to a background video layer by the platform, and
  // |kSbPlayerOutputDecodeToTexture| indicates that the decoded video frames
  // should be made available for the application to pull via calls to
  // SbPlayerGetCurrentFrame().
  StarboardPlayerOutputMode output_mode;
};

// Copy of SbPlayerInfo2 from starboard.
struct StarboardPlayerInfo {
  // The position of the playback head, as precisely as possible, in
  // microseconds.
  int64_t current_media_timestamp_micros;
  // The known duration of the currently playing media stream, in microseconds.
  int64_t duration_micros;
  // The result of getStartDate for the currently playing media stream, in
  // microseconds since the epoch of January 1, 1601 UTC.
  int64_t start_date;
  // The width of the currently displayed frame, in pixels, or 0 if not provided
  // by this player.
  int frame_width;
  // The height of the currently displayed frame, in pixels, or 0 if not
  // provided by this player.
  int frame_height;
  // Whether playback is currently paused.
  bool is_paused;
  // The current player volume in [0, 1].
  double volume;
  // The number of video frames sent to the player since the creation of the
  // player.
  int total_video_frames;
  // The number of video frames decoded but not displayed since the creation of
  // the player.
  int dropped_video_frames;
  // The number of video frames that failed to be decoded since the creation of
  // the player.
  int corrupted_video_frames;
  // The rate of playback. The video is played back in a speed that is
  // proportional to this. By default it is 1.0 which indicates that the
  // playback is at normal speed. When it is greater than one, the video is
  // played in a faster than normal speed. When it is less than one, the video
  // is played in a slower than normal speed. Negative speeds are not supported.
  double playback_rate;
};

// Copy of SbDrmKeyId from starboard.
struct StarboardDrmKeyId {
  uint8_t identifier[16];
  int identifier_size;
};

// Copy of SbPlayerDecoderStatusFunc from starboard.
using StarboardPlayerDecoderStatusFunc =
    void (*)(void* player,
             void* context,
             StarboardMediaType type,
             StarboardDecoderState decoder_state,
             int ticket);

// Copy of SbPlayerDeallocateSampleFunc from starboard.
using StarboardPlayerDeallocateSampleFunc = void (*)(void* player,
                                                     void* context,
                                                     const void* sample_buffer);

// Copy of SbPlayerStatusFunc from starboard.
using StarboardPlayerStatusFunc = void (*)(void* player,
                                           void* context,
                                           StarboardPlayerState state,
                                           int ticket);

// Copy of SbPlayerErrorFunc from starboard.
using StarboardPlayerErrorFunc = void (*)(void* player,
                                          void* context,
                                          StarboardPlayerError error,
                                          const char* message);

// Copy of SbDrmSessionUpdateRequestFunc from starboard.
using StarboardDrmSessionUpdateRequestFunc =
    void (*)(void* drm_system,
             void* context,
             int ticket,
             StarboardDrmStatus status,
             StarboardDrmSessionRequestType type,
             const char* error_message,
             const void* session_id,
             int session_id_size,
             const void* content,
             int content_size,
             const char* url);

// Copy of SbDrmSessionUpdatedFunc from starboard.
using StarboardDrmSessionUpdatedFunc = void (*)(void* drm_system,
                                                void* context,
                                                int ticket,
                                                StarboardDrmStatus status,
                                                const char* error_message,
                                                const void* session_id,
                                                int session_id_size);

// Copy of SbDrmSessionKeyStatusesChangedFunc from starboard.
using StarboardDrmSessionKeyStatusesChangedFunc =
    void (*)(void* drm_system,
             void* context,
             const void* session_id,
             int session_id_size,
             int number_of_keys,
             const StarboardDrmKeyId* key_ids,
             const StarboardDrmKeyStatus* key_statuses);

// Copy of SbDrmServerCertificateUpdatedFunc from starboard.
using StarboardDrmServerCertificateUpdatedFunc =
    void (*)(void* drm_system,
             void* context,
             int ticket,
             StarboardDrmStatus status,
             const char* error_message);

// Copy of SbDrmSessionClosedFunc from starboard.
using StarboardDrmSessionClosedFunc = void (*)(void* drm_system,
                                               void* context,
                                               const void* session_id,
                                               int session_id_size);

// A wrapper for the player-related callbacks that starboard calls.
struct StarboardPlayerCallbackHandler {
  // The context that will be passed to all functions.
  void* context;
  StarboardPlayerDecoderStatusFunc decoder_status_fn;
  StarboardPlayerDeallocateSampleFunc deallocate_sample_fn;
  StarboardPlayerStatusFunc player_status_fn;
  StarboardPlayerErrorFunc player_error_fn;
};

// A wrapper for the DRM-related callbacks that starboard calls.
struct StarboardDrmSystemCallbackHandler {
  // The context that will be passed to all functions.
  void* context;
  StarboardDrmSessionUpdateRequestFunc update_request_fn;
  StarboardDrmSessionUpdatedFunc session_updated_fn;
  StarboardDrmSessionKeyStatusesChangedFunc key_statuses_changed_fn;
  StarboardDrmServerCertificateUpdatedFunc server_certificate_updated_fn;
  StarboardDrmSessionClosedFunc session_closed_fn;
};

// A wrapper around the Starboard API, allowing a mock to be used for testing.
// It also abstracts away details specific to certain versions of Starboard, by
// utilizing the structs defined above. Internally, those structs will be
// converted to the relevant starboard structs for the given starboard version.
class StarboardApiWrapper {
 public:
  virtual ~StarboardApiWrapper();

  // This function matches the EnsureInitialized function in
  // cast_starboard_api_adapter.h. It blocks until Starboard has started and
  // returns true, or returns false if initialization fails.
  //
  // This function is included in this wrapper so we can avoid calling the
  // production implementation in unit tests, thus removing a dependency on
  // Starboard.
  virtual bool EnsureInitialized() = 0;

  // Version-agnostic functions for SbPlayer. See starboard/player.h for more
  // info about the corresponding functions.
  //
  // StarboardPlayerCallbackHandler is used to wrap multiple callbacks that are
  // passed to starboard.
  virtual void* CreatePlayer(
      const StarboardPlayerCreationParam* creation_param,
      const StarboardPlayerCallbackHandler* callback_handler) = 0;
  virtual void SetPlayerBounds(void* player,
                               int z_index,
                               int x,
                               int y,
                               int width,
                               int height) = 0;
  virtual void SeekTo(void* player, int64_t time, int seek_ticket) = 0;
  virtual void WriteSample(void* player,
                           StarboardMediaType type,
                           StarboardSampleInfo* sample_infos,
                           int sample_infos_count) = 0;
  virtual void WriteEndOfStream(void* player, StarboardMediaType type) = 0;
  virtual void GetPlayerInfo(void* player,
                             StarboardPlayerInfo* player_info) = 0;
  virtual void SetVolume(void* player, double volume) = 0;
  virtual bool SetPlaybackRate(void* player, double playback_rate) = 0;
  virtual void DestroyPlayer(void* player) = 0;

  // Version-agnostic functions for SbDrmSystem. See starboard/drm.h for more
  // info about the corresponding functions.
  //
  // StarboardDrmSystemCallbackHandler is used to wrap multiple callbacks that
  // are passed to starboard.
  virtual void* CreateDrmSystem(
      const char* key_system,
      const StarboardDrmSystemCallbackHandler* callback_handler) = 0;
  virtual void DrmGenerateSessionUpdateRequest(
      void* drm_system,
      int ticket,
      const char* type,
      const void* initialization_data,
      int initialization_data_size) = 0;
  virtual void DrmUpdateSession(void* drm_system,
                                int ticket,
                                const void* key,
                                int key_size,
                                const void* session_id,
                                int session_id_size) = 0;
  virtual void DrmCloseSession(void* drm_system,
                               const void* session_id,
                               int session_id_size) = 0;
  virtual void DrmUpdateServerCertificate(void* drm_system,
                                          int ticket,
                                          const void* certificate,
                                          int certificate_size) = 0;
  virtual bool DrmIsServerCertificateUpdatable(void* drm_system) = 0;
  virtual void DrmDestroySystem(void* drm_system) = 0;

  // Version-agnostic functions for starboard/media.h.
  virtual StarboardMediaSupportType CanPlayMimeAndKeySystem(
      const char* mime,
      const char* key_system) = 0;
};

// Returns a StarboardApiWrapper that calls into libcast_starboard_api.so. This
// function is defined for each starboard version supported by cast. For
// example, there is a starboard 15 version that calls the starboard 15 APIs, a
// starboard 14 version that calls the starboard 14 APIs, etc.
std::unique_ptr<StarboardApiWrapper> GetStarboardApiWrapper();

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_STARBOARD_MEDIA_MEDIA_STARBOARD_API_WRAPPER_H_