1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "remoting/protocol/session_config.h"
6
7#include <algorithm>
8
9namespace remoting {
10namespace protocol {
11
12const int kDefaultStreamVersion = 2;
13
14// The control channel version that supports the "capabilities" message.
15const int kControlStreamVersion = 3;
16const int kControlStreamVersionNoCapabilities = kDefaultStreamVersion;
17
18ChannelConfig ChannelConfig::None() {
19  return ChannelConfig();
20}
21
22ChannelConfig::ChannelConfig()
23    : transport(TRANSPORT_NONE),
24      version(0),
25      codec(CODEC_UNDEFINED) {
26}
27
28ChannelConfig::ChannelConfig(TransportType transport, int version, Codec codec)
29    : transport(transport),
30      version(version),
31      codec(codec) {
32}
33
34bool ChannelConfig::operator==(const ChannelConfig& b) const {
35  // If the transport field is set to NONE then all other fields are irrelevant.
36  if (transport == ChannelConfig::TRANSPORT_NONE)
37    return transport == b.transport;
38  return transport == b.transport && version == b.version && codec == b.codec;
39}
40
41SessionConfig::SessionConfig() {
42}
43
44bool SessionConfig::SupportsCapabilities() const {
45  return control_config_.version >= kControlStreamVersion;
46}
47
48// static
49SessionConfig SessionConfig::ForTest() {
50  SessionConfig result;
51  result.set_control_config(ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
52                                          kControlStreamVersionNoCapabilities,
53                                          ChannelConfig::CODEC_UNDEFINED));
54  result.set_event_config(ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
55                                        kDefaultStreamVersion,
56                                        ChannelConfig::CODEC_UNDEFINED));
57  result.set_video_config(ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
58                                        kDefaultStreamVersion,
59                                        ChannelConfig::CODEC_VP8));
60  result.set_audio_config(ChannelConfig(ChannelConfig::TRANSPORT_NONE,
61                                        kDefaultStreamVersion,
62                                        ChannelConfig::CODEC_VERBATIM));
63  return result;
64}
65
66CandidateSessionConfig::CandidateSessionConfig() { }
67
68CandidateSessionConfig::CandidateSessionConfig(
69    const CandidateSessionConfig& config)
70    : control_configs_(config.control_configs_),
71      event_configs_(config.event_configs_),
72      video_configs_(config.video_configs_),
73      audio_configs_(config.audio_configs_) {
74}
75
76CandidateSessionConfig::~CandidateSessionConfig() { }
77
78bool CandidateSessionConfig::Select(
79    const CandidateSessionConfig* client_config,
80    SessionConfig* result) {
81  ChannelConfig control_config;
82  ChannelConfig event_config;
83  ChannelConfig video_config;
84  ChannelConfig audio_config;
85
86  if (!SelectCommonChannelConfig(
87          control_configs_, client_config->control_configs_, &control_config) ||
88      !SelectCommonChannelConfig(
89          event_configs_, client_config->event_configs_, &event_config) ||
90      !SelectCommonChannelConfig(
91          video_configs_, client_config->video_configs_, &video_config) ||
92      !SelectCommonChannelConfig(
93          audio_configs_, client_config->audio_configs_, &audio_config)) {
94    return false;
95  }
96
97  result->set_control_config(control_config);
98  result->set_event_config(event_config);
99  result->set_video_config(video_config);
100  result->set_audio_config(audio_config);
101
102  return true;
103}
104
105bool CandidateSessionConfig::IsSupported(
106    const SessionConfig& config) const {
107  return
108      IsChannelConfigSupported(control_configs_, config.control_config()) &&
109      IsChannelConfigSupported(event_configs_, config.event_config()) &&
110      IsChannelConfigSupported(video_configs_, config.video_config()) &&
111      IsChannelConfigSupported(audio_configs_, config.audio_config());
112}
113
114bool CandidateSessionConfig::GetFinalConfig(SessionConfig* result) const {
115  if (control_configs_.size() != 1 ||
116      event_configs_.size() != 1 ||
117      video_configs_.size() != 1 ||
118      audio_configs_.size() != 1) {
119    return false;
120  }
121
122  result->set_control_config(control_configs_.front());
123  result->set_event_config(event_configs_.front());
124  result->set_video_config(video_configs_.front());
125  result->set_audio_config(audio_configs_.front());
126
127  return true;
128}
129
130// static
131bool CandidateSessionConfig::SelectCommonChannelConfig(
132    const std::vector<ChannelConfig>& host_configs,
133    const std::vector<ChannelConfig>& client_configs,
134    ChannelConfig* config) {
135  // Usually each of these vectors will contain just several elements,
136  // so iterating over all of them is not a problem.
137  std::vector<ChannelConfig>::const_iterator it;
138  for (it = client_configs.begin(); it != client_configs.end(); ++it) {
139    if (IsChannelConfigSupported(host_configs, *it)) {
140      *config = *it;
141      return true;
142    }
143  }
144  return false;
145}
146
147// static
148bool CandidateSessionConfig::IsChannelConfigSupported(
149    const std::vector<ChannelConfig>& vector,
150    const ChannelConfig& value) {
151  return std::find(vector.begin(), vector.end(), value) != vector.end();
152}
153
154scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::Clone() const {
155  return scoped_ptr<CandidateSessionConfig>(new CandidateSessionConfig(*this));
156}
157
158// static
159scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateEmpty() {
160  return scoped_ptr<CandidateSessionConfig>(new CandidateSessionConfig());
161}
162
163// static
164scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateFrom(
165    const SessionConfig& config) {
166  scoped_ptr<CandidateSessionConfig> result = CreateEmpty();
167  result->mutable_control_configs()->push_back(config.control_config());
168  result->mutable_event_configs()->push_back(config.event_config());
169  result->mutable_video_configs()->push_back(config.video_config());
170  result->mutable_audio_configs()->push_back(config.audio_config());
171  return result.Pass();
172}
173
174// static
175scoped_ptr<CandidateSessionConfig> CandidateSessionConfig::CreateDefault() {
176  scoped_ptr<CandidateSessionConfig> result = CreateEmpty();
177
178  // Control channel.
179  result->mutable_control_configs()->push_back(
180      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
181                    kControlStreamVersion,
182                    ChannelConfig::CODEC_UNDEFINED));
183  result->mutable_control_configs()->push_back(
184      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
185                    kControlStreamVersionNoCapabilities,
186                    ChannelConfig::CODEC_UNDEFINED));
187  result->mutable_control_configs()->push_back(
188      ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
189                    kControlStreamVersionNoCapabilities,
190                    ChannelConfig::CODEC_UNDEFINED));
191
192  // Event channel.
193  result->mutable_event_configs()->push_back(
194      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
195                    kDefaultStreamVersion,
196                    ChannelConfig::CODEC_UNDEFINED));
197  result->mutable_event_configs()->push_back(
198      ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
199                    kDefaultStreamVersion,
200                    ChannelConfig::CODEC_UNDEFINED));
201
202  // Video channel.
203  result->mutable_video_configs()->push_back(
204      ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
205                    kDefaultStreamVersion,
206                    ChannelConfig::CODEC_VP8));
207
208  // Audio channel.
209  result->mutable_audio_configs()->push_back(
210      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
211                    kDefaultStreamVersion,
212                    ChannelConfig::CODEC_OPUS));
213  result->mutable_audio_configs()->push_back(
214      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
215                    kDefaultStreamVersion,
216                    ChannelConfig::CODEC_SPEEX));
217  result->mutable_audio_configs()->push_back(
218      ChannelConfig(ChannelConfig::TRANSPORT_STREAM,
219                    kDefaultStreamVersion,
220                    ChannelConfig::CODEC_SPEEX));
221  result->mutable_audio_configs()->push_back(
222      ChannelConfig(ChannelConfig::TRANSPORT_MUX_STREAM,
223                    kDefaultStreamVersion,
224                    ChannelConfig::CODEC_VERBATIM));
225  result->mutable_audio_configs()->push_back(ChannelConfig::None());
226
227  return result.Pass();
228}
229
230// static
231void CandidateSessionConfig::DisableAudioChannel(
232  CandidateSessionConfig* config) {
233  config->mutable_audio_configs()->clear();
234  config->mutable_audio_configs()->push_back(ChannelConfig());
235}
236
237}  // namespace protocol
238}  // namespace remoting
239