910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/cast_streaming/browser/cast_message_port_impl.h"

#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/values.h"
#include "components/cast_streaming/browser/cast_message_port_converter.h"
#include "components/cast_streaming/common/message_serialization.h"
#include "third_party/openscreen/src/platform/base/error.h"

namespace cast_streaming {

namespace {

const char kKeyMediaSessionId[] = "mediaSessionId";
const char kKeyPlaybackRate[] = "playbackRate";
const char kKeyPlayerState[] = "playerState";
const char kKeyCurrentTime[] = "currentTime";
const char kKeySupportedMediaCommands[] = "supportedMediaCommands";
const char kKeyDisableStreamGrouping[] = "disableStreamGrouping";
const char kKeyMedia[] = "media";
const char kKeyContentId[] = "contentId";
const char kKeyStreamType[] = "streamType";
const char kKeyContentType[] = "contentType";
const char kValuePlaying[] = "PLAYING";
const char kValueLive[] = "LIVE";
const char kValueVideoWebm[] = "video/webm";

base::Value::Dict GetMediaCurrentStatusValue() {
  base::Value::Dict media;
  media.Set(kKeyContentId, "");
  media.Set(kKeyStreamType, kValueLive);
  media.Set(kKeyContentType, kValueVideoWebm);

  base::Value::Dict media_current_status;
  media_current_status.Set(kKeyMediaSessionId, 0);
  media_current_status.Set(kKeyPlaybackRate, 1.0);
  media_current_status.Set(kKeyPlayerState, kValuePlaying);
  media_current_status.Set(kKeyCurrentTime, 0);
  media_current_status.Set(kKeySupportedMediaCommands, 0);
  media_current_status.Set(kKeyDisableStreamGrouping, true);
  media_current_status.Set(kKeyMedia, std::move(media));

  return media_current_status;
}

// Implementation of CastMessagePortConverter using CastMessagePortImpl.
class CastMessagePortConverterImpl : public CastMessagePortConverter {
 public:
  CastMessagePortConverterImpl(
      ReceiverSession::MessagePortProvider message_port_provider,
      base::OnceClosure on_close)
      : message_port_(std::move(message_port_provider).Run()),
        on_close_(std::move(on_close)) {}
  ~CastMessagePortConverterImpl() override = default;

  openscreen::cast::MessagePort& GetMessagePort() override {
    if (!openscreen_port_) {
      DCHECK(message_port_);
      openscreen_port_ = std::make_unique<CastMessagePortImpl>(
          std::move(message_port_), std::move(on_close_));
    }
    return *openscreen_port_;
  }

 private:
  std::unique_ptr<cast_api_bindings::MessagePort> message_port_;
  base::OnceClosure on_close_;

  std::unique_ptr<openscreen::cast::MessagePort> openscreen_port_;
};

}  // namespace

std::unique_ptr<CastMessagePortConverter> CastMessagePortConverter::Create(
    ReceiverSession::MessagePortProvider message_port_provider,
    base::OnceClosure on_close) {
  return std::make_unique<CastMessagePortConverterImpl>(
      std::move(message_port_provider), std::move(on_close));
}

CastMessagePortImpl::CastMessagePortImpl(
    std::unique_ptr<cast_api_bindings::MessagePort> message_port,
    base::OnceClosure on_close)
    : message_port_(std::move(message_port)), on_close_(std::move(on_close)) {
  DVLOG(1) << __func__;
  message_port_->SetReceiver(this);

  // Initialize the connection with the Cast Streaming Sender.
  PostMessage(kValueSystemSenderId, kSystemNamespace, kInitialConnectMessage);
}

CastMessagePortImpl::~CastMessagePortImpl() = default;

void CastMessagePortImpl::MaybeClose() {
  if (message_port_) {
    message_port_.reset();
  }
  if (client_) {
    client_->OnError(
        openscreen::Error(openscreen::Error::Code::kCastV2CastSocketError));
  }
  if (on_close_) {
    // |this| might be deleted as part of |on_close_| being run. Do not add any
    // code after running the closure.
    std::move(on_close_).Run();
  }
}

void CastMessagePortImpl::SetClient(
    openscreen::cast::MessagePort::Client& client) {
  DVLOG(2) << __func__;
  client_ = &client;
}

void CastMessagePortImpl::ResetClient() {
  client_ = nullptr;
  MaybeClose();
}

void CastMessagePortImpl::SendInjectResponse(const std::string& sender_id,
                                             const std::string& message) {
  std::optional<base::Value::Dict> value =
      base::JSONReader::ReadDict(message, base::JSON_PARSE_CHROMIUM_EXTENSIONS);
  if (!value) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": non-dictionary json payload: " << message;
    return;
  }

  const std::string* type = value->FindString(kKeyType);
  if (!type) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": no message type: " << message;
    return;
  }
  if (*type != kValueWrapped) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": unknown message type: " << *type;
    return;
  }

  std::optional<int> request_id = value->FindInt(kKeyRequestId);
  if (!request_id) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": no request id: " << message;
    return;
  }

  // Build the response message.
  base::Value::Dict response_value;
  response_value.Set(kKeyType, kValueError);
  response_value.Set(kKeyRequestId, request_id.value());
  response_value.Set(kKeyData, kValueInjectNotSupportedError);
  response_value.Set(kKeyCode, kValueWrappedError);

  std::string json_message;
  CHECK(base::JSONWriter::Write(response_value, &json_message));
  PostMessage(sender_id, kInjectNamespace, json_message);
}

void CastMessagePortImpl::HandleMediaMessage(const std::string& sender_id,
                                             const std::string& message) {
  std::optional<base::Value::Dict> value =
      base::JSONReader::ReadDict(message, base::JSON_PARSE_CHROMIUM_EXTENSIONS);
  if (!value) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": non-dictionary json payload: " << message;
    return;
  }

  const std::string* type = value->FindString(kKeyType);
  if (!type) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": no message type: " << message;
    return;
  }

  if (*type == kValueMediaPlay || *type == kValueMediaPause) {
    // Not supported. Just ignore.
    return;
  }

  if (*type != kValueMediaGetStatus) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": unknown message type: " << *type;
    return;
  }

  std::optional<int> request_id = value->FindInt(kKeyRequestId);
  if (!request_id) {
    LOG(ERROR) << "Malformed message from sender " << sender_id
               << ": no request id: " << message;
    return;
  }

  base::Value::List message_status_list;
  message_status_list.Append(GetMediaCurrentStatusValue());

  base::Value::Dict response_value;
  response_value.Set(kKeyRequestId, request_id.value());
  response_value.Set(kKeyType, kValueMediaStatus);
  response_value.Set(kKeyStatus, std::move(message_status_list));

  std::string json_message;
  CHECK(base::JSONWriter::Write(response_value, &json_message));
  PostMessage(sender_id, kMediaNamespace, json_message);
}

void CastMessagePortImpl::PostMessage(const std::string& sender_id,
                                      const std::string& message_namespace,
                                      const std::string& message) {
  DVLOG(3) << __func__;
  if (!message_port_) {
    return;
  }

  DVLOG(3) << "Received Open Screen message. SenderId: " << sender_id
           << ". Namespace: " << message_namespace << ". Message: " << message;
  message_port_->PostMessage(
      SerializeCastMessage(sender_id, message_namespace, message));
}

bool CastMessagePortImpl::OnMessage(
    std::string_view message,
    std::vector<std::unique_ptr<cast_api_bindings::MessagePort>> ports) {
  DVLOG(3) << __func__;

  // If |client_| was cleared, |message_port_| should have been reset.
  DCHECK(client_);

  if (!ports.empty()) {
    // We should never receive any ports for Cast Streaming.
    LOG(ERROR) << "Received ports on Cast Streaming MessagePort.";
    return false;
  }

  std::string sender_id;
  std::string message_namespace;
  std::string str_message;
  if (!DeserializeCastMessage(message, &sender_id, &message_namespace,
                              &str_message)) {
    LOG(ERROR) << "Received bad message.";
    client_->OnError(
        openscreen::Error(openscreen::Error::Code::kCastV2InvalidMessage));
    return true;
  }
  DVLOG(3) << "Received Cast message. SenderId: " << sender_id
           << ". Namespace: " << message_namespace
           << ". Message: " << str_message;

  // TODO(b/156118960): Have Open Screen handle message namespaces.
  if (message_namespace == kMirroringNamespace ||
      message_namespace == kRemotingNamespace) {
    client_->OnMessage(sender_id, message_namespace, str_message);
  } else if (message_namespace == kInjectNamespace) {
    SendInjectResponse(sender_id, str_message);
  } else if (message_namespace == kMediaNamespace) {
    HandleMediaMessage(sender_id, str_message);
  } else if (message_namespace != kSystemNamespace) {
    // System messages are ignored, log messages from unknown namespaces.
    DVLOG(2) << "Unknown message from " << sender_id
             << ", namespace=" << message_namespace
             << ", message=" << str_message;
  }

  return true;
}

void CastMessagePortImpl::OnPipeError() {
  DVLOG(3) << __func__;
  MaybeClose();
}

}  // namespace cast_streaming