// Copyright (c) 2012 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.
#include "remoting/protocol/session_config.h"
#include <algorithm>
namespace remoting {
namespace protocol {
const int kDefaultStreamVersion = 2;
// The control channel version that supports the "capabilities" message.
const int kControlStreamVersion = 3;
const int kControlStreamVersionNoCapabilities = kDefaultStreamVersion;
ChannelConfig ChannelConfig::None() {
return ChannelConfig();
}
ChannelConfig::ChannelConfig()
: transport(TRANSPORT_NONE),
version(0),
codec(CODEC_UNDEFINED) {
}
ChannelConfig::ChannelConfig(TransportType transport, int version, Codec codec)
: transport(transport),
version(version),
codec(codec) {
}
bool ChannelConfig::operator==(const ChannelConfig& b) const {
// If the transport field is set to NONE then all other fields are irrelevant.
if (transport == ChannelConfig::TRANSPORT_NONE)
return transport == b.transport;
return transport == b.transport && version == b.version && codec == b.codec;
}
SessionConfig::SessionConfig() {
}
bool SessionConfig::SupportsCapabilities() const {
return control_config_.version >= kControlStreamVersion;
}
// static
SessionConfig SessionConfig::ForTest() {
SessionConfig result;
result.set_control_config(ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kControlStreamVersionNoCapabilities,
ChannelConfig::CODEC_UNDEFINED));
result.set_event_config(ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_UNDEFINED));
result.set_video_config(ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_VP8));
result.set_audio_config(ChannelConfig(ChannelConfig::TRANSPORT_NONE,
kDefaultStreamVersion,
ChannelConfig::CODEC_UNDEFINED));
return result;
}
CandidateSessionConfig::CandidateSessionConfig() { }
CandidateSessionConfig::CandidateSessionConfig(
const CandidateSessionConfig& config)
: control_configs_(config.control_configs_),
event_configs_(config.event_configs_),
video_configs_(config.video_configs_),
audio_configs_(config.audio_configs_) {
}
CandidateSessionConfig::~CandidateSessionConfig() { }
bool CandidateSessionConfig::Select(
const CandidateSessionConfig* client_config,
SessionConfig* result) {
ChannelConfig control_config;
ChannelConfig event_config;
ChannelConfig video_config;
ChannelConfig audio_config;
if (!SelectCommonChannelConfig(
control_configs_, client_config->control_configs_, &control_config) ||
!SelectCommonChannelConfig(
event_configs_, client_config->event_configs_, &event_config) ||
!SelectCommonChannelConfig(
video_configs_, client_config->video_configs_, &video_config) ||
!SelectCommonChannelConfig(
audio_configs_, client_config->audio_configs_, &audio_config)) {
return false;
}
result->set_control_config(control_config);
result->set_event_config(event_config);
result->set_video_config(video_config);
result->set_audio_config(audio_config);
return true;
}
bool CandidateSessionConfig::IsSupported(
const SessionConfig& config) const {
return
IsChannelConfigSupported(control_configs_, config.control_config()) &&
IsChannelConfigSupported(event_configs_, config.event_config()) &&
IsChannelConfigSupported(video_configs_, config.video_config()) &&
IsChannelConfigSupported(audio_configs_, config.audio_config());
}
bool CandidateSessionConfig::GetFinalConfig(SessionConfig* result) const {
if (control_configs_.size() != 1 ||
event_configs_.size() != 1 ||
video_configs_.size() != 1 ||
audio_configs_.size() != 1) {
return false;
}
result->set_control_config(control_configs_.front());
result->set_event_config(event_configs_.front());
result->set_video_config(video_configs_.front());
result->set_audio_config(audio_configs_.front());
return true;
}
// static
bool CandidateSessionConfig::SelectCommonChannelConfig(
const std::vector<ChannelConfig>& host_configs,
const std::vector<ChannelConfig>& client_configs,
ChannelConfig* config) {
// Usually each of these vectors will contain just several elements,
// so iterating over all of them is not a problem.
std::vector<ChannelConfig>::const_iterator it;
for (it = client_configs.begin(); it != client_configs.end(); ++it) {
if (IsChannelConfigSupported(host_configs, *it)) {
*config = *it;
return true;
}
}
return false;
}
// static
bool CandidateSessionConfig::IsChannelConfigSupported(
const std::vector<ChannelConfig>& vector,
const ChannelConfig& value) {
return std::find(vector.begin(), vector.end(), value) != vector.end();
}
scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::Clone() const {
return scoped_ptr<CandidateSessionConfig>(new CandidateSessionConfig(*this));
}
// static
scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateEmpty() {
return scoped_ptr<CandidateSessionConfig>(new CandidateSessionConfig());
}
// static
scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateFrom(
const SessionConfig& config) {
scoped_ptr<CandidateSessionConfig> result = CreateEmpty();
result->mutable_control_configs()->push_back(config.control_config());
result->mutable_event_configs()->push_back(config.event_config());
result->mutable_video_configs()->push_back(config.video_config());
result->mutable_audio_configs()->push_back(config.audio_config());
return result.Pass();
}
// static
scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateDefault() {
scoped_ptr<CandidateSessionConfig> result = CreateEmpty();
// Control channel.
result->mutable_control_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kControlStreamVersion,
ChannelConfig::CODEC_UNDEFINED));
result->mutable_control_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kControlStreamVersionNoCapabilities,
ChannelConfig::CODEC_UNDEFINED));
// Event channel.
result->mutable_event_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_UNDEFINED));
// Video channel.
result->mutable_video_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_VP9));
result->mutable_video_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_VP8));
// Audio channel.
result->mutable_audio_configs()->push_back(
ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
kDefaultStreamVersion,
ChannelConfig::CODEC_OPUS));
result->mutable_audio_configs()->push_back(ChannelConfig::None());
return result.Pass();
}
// static
void CandidateSessionConfig::DisableAudioChannel(
CandidateSessionConfig* config) {
config->mutable_audio_configs()->clear();
config->mutable_audio_configs()->push_back(ChannelConfig());
}
// static
void CandidateSessionConfig::DisableVideoCodec(
CandidateSessionConfig* config,
ChannelConfig::Codec codec) {
std ::vector<ChannelConfig>::iterator i;
for (i = config->mutable_video_configs()->begin();
i != config->mutable_video_configs()->end();) {
if (i->codec == codec) {
i = config->mutable_video_configs()->erase(i);
} else {
++i;
}
}
}
} // namespace protocol
} // namespace remoting