// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_REMOTING_RPC_PROTO_UTILS_H_
#define MEDIA_REMOTING_RPC_PROTO_UTILS_H_

#include <cstdint>
#include <string>
#include <vector>

#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/cdm_config.h"
#include "media/base/cdm_key_information.h"
#include "media/base/cdm_promise.h"
#include "media/base/decoder_buffer.h"
#include "media/base/demuxer_stream.h"
#include "media/base/eme_constants.h"
#include "media/base/media_keys.h"
#include "media/base/pipeline_status.h"
#include "media/base/video_decoder_config.h"
#include "media/remoting/remoting_rpc_message.pb.h"

namespace media {
namespace remoting {

class CdmPromiseResult;

// Utility class to convert data between ::media::DecoderBuffer and byte array.
// It is to serialize ::media::DecoderBuffer structure except for actual data
// into pb::DecoderBuffer followed by byte array of decoder buffer. The reason
// data is not part of proto buffer because it would cost unnecessary time to
// wait for whole proto received before conversion given the fact that decoder
// buffer data can vary from hundred bytes to 3~5MB. Also, it would costs extra
// CPU to sirealize/de-serialize decoder buffer which is encoded and encrypted
// as wire format for data transmission.
//
// DecoderBufferSegment {
//  // Payload version. Default value is 0.
//  u8 payload_version;
//
//  // Length of pb::DecoderBuffer (protobuf-encoded of ::media::DecoderBuffer
//                   except for data).
//  u16 buffer_segment_size;
//  // pb::DecoderBuffer.
//  u8[buffer_segment_size] buffer_segment;
//
//  // Length of data in media::DecoderBuffer.
//  u32 data_buffer_size;
//  // media::DecoderBuffer data.
//  u8[data_buffer_size] data_buffer;
//};

// Converts DecoderBufferSegment into byte array.
std::vector<uint8_t> DecoderBufferToByteArray(
    const scoped_refptr<::media::DecoderBuffer>& decoder_buffer);

// Converts byte array into DecoderBufferSegment.
scoped_refptr<::media::DecoderBuffer> ByteArrayToDecoderBuffer(
    const uint8_t* data,
    uint32_t size);

// Data type conversion between ::media::AudioDecoderConfig and proto buffer.
void ConvertAudioDecoderConfigToProto(
    const ::media::AudioDecoderConfig& audio_config,
    pb::AudioDecoderConfig* audio_message);
bool ConvertProtoToAudioDecoderConfig(
    const pb::AudioDecoderConfig& audio_message,
    ::media::AudioDecoderConfig* audio_config);

// Data type conversion between ::media::VideoDecoderConfig and proto buffer.
void ConvertVideoDecoderConfigToProto(
    const ::media::VideoDecoderConfig& video_config,
    pb::VideoDecoderConfig* video_message);
bool ConvertProtoToVideoDecoderConfig(
    const pb::VideoDecoderConfig& video_message,
    ::media::VideoDecoderConfig* video_config);

// Data type conversion between ::media::CdmKeysInfo and proto buffer.
void ConvertCdmKeyInfoToProto(
    const ::media::CdmKeysInfo& keys_information,
    pb::CdmClientOnSessionKeysChange* key_change_message);
void ConvertProtoToCdmKeyInfo(
    const pb::CdmClientOnSessionKeysChange keychange_message,
    CdmKeysInfo* key_information);

// Data type conversion between CdmPromiseResult and proto buffer.
void ConvertCdmPromiseToProto(const CdmPromiseResult& result,
                              pb::CdmPromise* promise_message);
void ConvertCdmPromiseWithSessionIdToProto(const CdmPromiseResult& result,
                                           const std::string& session_id,
                                           pb::CdmPromise* promise_message);
void ConvertCdmPromiseWithCdmIdToProto(const CdmPromiseResult& result,
                                       int cdm_id,
                                       pb::CdmPromise* promise_message);
bool ConvertProtoToCdmPromise(const pb::CdmPromise& promise_message,
                              CdmPromiseResult* result);
bool ConvertProtoToCdmPromiseWithCdmIdSessionId(const pb::RpcMessage& message,
                                                CdmPromiseResult* result,
                                                int* cdm_id,
                                                std::string* session_id);

//==================================================================
class CdmPromiseResult {
 public:
  CdmPromiseResult();
  CdmPromiseResult(::media::CdmPromise::Exception exception,
                   uint32_t system_code,
                   std::string error_message);
  CdmPromiseResult(const CdmPromiseResult& other);
  ~CdmPromiseResult();

  static CdmPromiseResult SuccessResult();

  bool success() const { return success_; }
  ::media::CdmPromise::Exception exception() const { return exception_; }
  uint32_t system_code() const { return system_code_; }
  const std::string& error_message() const { return error_message_; }

 private:
  bool success_;
  ::media::CdmPromise::Exception exception_;
  uint32_t system_code_;
  std::string error_message_;
};

}  // namespace remoting
}  // namespace media

#endif  // MEDIA_REMOTING_RPC_PROTO_UTILS_H_
