summaryrefslogtreecommitdiff
path: root/chromium/third_party/openscreen
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-09-01 11:08:40 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-01 12:16:21 +0000
commit03c549e0392f92c02536d3f86d5e1d8dfa3435ac (patch)
treefe49d170a929b34ba82cd10db1a0bd8e3760fa4b /chromium/third_party/openscreen
parent5d013f5804a0d91fcf6c626b2d6fb6eca5c845b0 (diff)
downloadqtwebengine-chromium-03c549e0392f92c02536d3f86d5e1d8dfa3435ac.tar.gz
BASELINE: Update Chromium to 91.0.4472.160
Change-Id: I0def1f08a2412aeed79a9ab95dd50eb5c3f65f31 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/openscreen')
-rw-r--r--chromium/third_party/openscreen/src/DEPS2
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/bindings/api_bindings.proto9
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/common/application_config.proto5
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/common/runtime_metadata.proto8
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/common/service_info.proto5
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/core/cast_core_service.proto39
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/metrics/metrics_recorder.proto15
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/platform/platform_service.proto10
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_channel_service.proto (renamed from chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_decoder_service.proto)326
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/runtime/runtime_service.proto35
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/v2/cast_message.proto7
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/v2/core_application_service.proto23
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/v2/runtime_application_service.proto29
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/v2/url_rewrite.proto5
-rw-r--r--chromium/third_party/openscreen/src/cast/cast_core/api/web/message_channel.proto5
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc184
-rw-r--r--chromium/third_party/openscreen/src/cast/common/certificate/cast_crl.cc11
-rw-r--r--chromium/third_party/openscreen/src/cast/common/discovery/e2e_test/tests.cc2
-rw-r--r--chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_examples/answer.json3
-rw-r--r--chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_schema.json6
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/cast_service.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc2
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc27
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc5
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h10
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/main.cc2
-rw-r--r--chromium/third_party/openscreen/src/cast/standalone_sender/streaming_vp8_encoder.cc1
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/BUILD.gn1
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/answer_messages.cc51
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/answer_messages.h12
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.cc16
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.h2
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/capture_recommendations_unittest.cc4
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/constants.h11
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/message_fields.cc11
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc8
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/offer_messages_unittest.cc105
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver_message.cc48
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/receiver_message.h16
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/remoting.proto15
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/remoting_capabilities.h60
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rpc_broker.cc36
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rpc_broker.h21
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rpc_broker_unittest.cc30
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc46
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h17
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_message.cc8
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_message.h6
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_packet_router.h2
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session.cc310
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session.h156
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc115
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/session_messager.cc15
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/session_messager.h6
-rw-r--r--chromium/third_party/openscreen/src/cast/streaming/session_messager_unittest.cc29
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc5
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph_unittest.cc15
-rw-r--r--chromium/third_party/openscreen/src/discovery/dnssd/impl/service_instance.cc10
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc10
-rw-r--r--chromium/third_party/openscreen/src/discovery/mdns/mdns_records.h3
-rw-r--r--chromium/third_party/openscreen/src/osp/demo/osp_demo.cc3
-rw-r--r--chromium/third_party/openscreen/src/osp/impl/discovery/mdns/mdns_demo.cc3
-rw-r--r--chromium/third_party/openscreen/src/platform/base/error.cc6
-rw-r--r--chromium/third_party/openscreen/src/platform/base/error.h8
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/platform_client_posix.cc55
-rw-r--r--chromium/third_party/openscreen/src/platform/impl/platform_client_posix.h27
-rw-r--r--chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated.gni58
-rw-r--r--chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated_tests.gni54
-rw-r--r--chromium/third_party/openscreen/src/util/BUILD.gn10
-rw-r--r--chromium/third_party/openscreen/src/util/base64.cc16
-rw-r--r--chromium/third_party/openscreen/src/util/base64.h3
-rw-r--r--chromium/third_party/openscreen/src/util/base64_unittest.cc20
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc15
-rw-r--r--chromium/third_party/openscreen/src/util/crypto/certificate_utils.h2
-rw-r--r--chromium/third_party/openscreen/src/util/operation_loop.cc57
-rw-r--r--chromium/third_party/openscreen/src/util/operation_loop.h74
-rw-r--r--chromium/third_party/openscreen/src/util/operation_loop_unittest.cc42
77 files changed, 1588 insertions, 845 deletions
diff --git a/chromium/third_party/openscreen/src/DEPS b/chromium/third_party/openscreen/src/DEPS
index 7fbb8aeab51..9c0499ea839 100644
--- a/chromium/third_party/openscreen/src/DEPS
+++ b/chromium/third_party/openscreen/src/DEPS
@@ -92,7 +92,7 @@ deps = {
# python ./src/util/generate_build_files.py gn
'third_party/boringssl/src': {
'url' : Var('boringssl_git') + '/boringssl.git' +
- '@' + '78987bb7bb4764ca3a8b08b0a6f7bd14b53c3e4f',
+ '@' + 'f6bd54efbcafcf4625ce99b5f702dc4850b0ca50',
'condition': 'not build_with_chromium',
},
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/bindings/api_bindings.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/bindings/api_bindings.proto
index 23e734dea3e..78da4236c7f 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/bindings/api_bindings.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/bindings/api_bindings.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.bindings;
@@ -11,6 +16,8 @@ message ApiBinding {
string before_load_script = 1;
}
+message GetAllRequest {}
+
message GetAllResponse {
repeated ApiBinding bindings = 1;
}
@@ -19,3 +26,5 @@ message ConnectRequest {
string port_name = 1;
cast.web.MessagePortDescriptor port = 2;
}
+
+message ConnectResponse {}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/common/application_config.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/common/application_config.proto
index 6104e96e7b3..cb426824c83 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/common/application_config.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/common/application_config.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.common;
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/common/runtime_metadata.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/common/runtime_metadata.proto
index 00079f65618..38693389a2a 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/common/runtime_metadata.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/common/runtime_metadata.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.common;
@@ -51,9 +56,6 @@ message RuntimeCapabilities {
ApplicationCapabilities native_application_capabilities = 2;
}
- // Flags if heartbeat is supported.
- bool heartbeat_supported = 3;
-
// Flags if metrics recording is supported.
bool metrics_recorder_supported = 4;
}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/common/service_info.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/common/service_info.proto
index 012414e889a..e8dc7dd1bbb 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/common/service_info.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/common/service_info.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.common;
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/core/cast_core_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/core/cast_core_service.proto
index 5a9e8271e5f..ffd564d43a8 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/core/cast_core_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/core/cast_core_service.proto
@@ -1,10 +1,13 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.core;
-import "google/protobuf/empty.proto";
import "cast/cast_core/api/common/runtime_metadata.proto";
-import "cast/cast_core/api/common/service_info.proto";
option optimize_for = LITE_RUNTIME;
@@ -16,42 +19,24 @@ service CastCoreService {
// Unregisters a Cast Runtime. Usually called by platform.
rpc UnregisterRuntime(UnregisterRuntimeRequest)
returns (UnregisterRuntimeResponse);
-
- // Called by the Runtime when it starts up.
- rpc RuntimeStarted(RuntimeStartedNotification)
- returns (google.protobuf.Empty);
-
- // Called when the runtime is shutdown. May be called for an active Cast
- // session.
- rpc RuntimeStopped(RuntimeStoppedNotification)
- returns (google.protobuf.Empty);
}
message RegisterRuntimeRequest {
- // Platform-generated runtime ID associated with this runtime. Uniqueness is
- // guaranteed by the CastCore service.
- string runtime_id = 1;
+ // DEPRECATED.
+ string runtime_id = 1 [deprecated = true];
// Metadata about the runtime.
cast.common.RuntimeMetadata runtime_metadata = 2;
}
-message RegisterRuntimeResponse {}
-
-message UnregisterRuntimeRequest {
- // Runtime ID.
+message RegisterRuntimeResponse {
+ // A randomly generated runtime ID. Cast Core will use this ID to reference a
+ // particular Runtime.
string runtime_id = 1;
}
-message UnregisterRuntimeResponse {}
-
-message RuntimeStartedNotification {
+message UnregisterRuntimeRequest {
// Runtime ID.
string runtime_id = 1;
- // Runtime service info.
- cast.common.ServiceInfo runtime_service_info = 2;
}
-message RuntimeStoppedNotification {
- // Runtime ID.
- string runtime_id = 1;
-}
+message UnregisterRuntimeResponse {}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/metrics/metrics_recorder.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/metrics/metrics_recorder.proto
index 30227d3b566..c6654abe5fa 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/metrics/metrics_recorder.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/metrics/metrics_recorder.proto
@@ -1,20 +1,25 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.metrics;
-import "google/protobuf/empty.proto";
-
option optimize_for = LITE_RUNTIME;
service MetricsRecorderService {
// Record a set of|Event|
- rpc Record(RecordRequest) returns (google.protobuf.Empty);
+ rpc Record(RecordRequest) returns (RecordResponse);
}
message RecordRequest {
repeated Event event = 1;
}
+message RecordResponse {}
+
// This repliciates the Fuchsia approach to Cast metrics; for documentation on
// event structure, refer to
// fuchsia.googlesource.com/fuchsia/+/master/sdk/fidl/fuchsia.legacymetrics/event.fidl
@@ -28,7 +33,7 @@ message Event {
message UserActionEvent {
string name = 1;
- optional int64 time = 2;
+ int64 time = 2;
}
message Histogram {
@@ -45,5 +50,5 @@ message HistogramBucket {
message ImplementationDefinedEvent {
bytes data = 1;
- optional string name = 2;
+ string name = 2;
}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/platform/platform_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/platform/platform_service.proto
index 858339bf707..9369ab93cad 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/platform/platform_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/platform/platform_service.proto
@@ -1,7 +1,14 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.platform;
+import "cast/cast_core/api/common/service_info.proto";
+
option optimize_for = LITE_RUNTIME;
// Platform service. Implemented and hosted by Platform.
@@ -18,7 +25,10 @@ service PlatformService {
}
message StartRuntimeRequest {
+ // Cast Runtime ID assigned in CastCoreService.RegisterRuntime.
string runtime_id = 1;
+ // gRPC endpoint Cast Runtime must run on.
+ cast.common.ServiceInfo runtime_service_info = 2;
}
message StartRuntimeResponse {}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_decoder_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_channel_service.proto
index a051edbaa2f..900e9c3b74e 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_decoder_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/cast_audio_channel_service.proto
@@ -1,12 +1,183 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.media;
import "google/protobuf/duration.proto";
-import "google/protobuf/empty.proto";
option optimize_for = LITE_RUNTIME;
+// Cast audio service hosted by Cast Core.
+//
+// It defines a state machine with the following states:
+// - Uninitialized
+// - Playing
+// - Stopped
+// - Paused
+//
+// Note that the received ordering between different RPC calls is not
+// guaranteed to match the sent order.
+service CastAudioChannelService {
+ // Initializes the service and places the pipeline into the 'Stopped' state.
+ // This must be the first call received by the server, and no other calls
+ // may be sent prior to receiving this call's response.
+ rpc Initialize(InitializeRequest) returns (InitializeResponse);
+
+ // Returns the minimum buffering delay (min_delay) required by Cast. This is
+ // a constant value and only needs to be queried once for each service.
+ // During a StartRequest or ResumeRequest, the system timestamp must be
+ // greater than this delay and the current time in order for the buffer to be
+ // successfully rendered on remote devices.
+ rpc GetMinimumBufferDelay(GetMinimumBufferDelayRequest)
+ returns (GetMinimumBufferDelayResponse);
+
+ // Update the pipeline state.
+ //
+ // StartRequest:
+ // Places pipeline into 'Playing' state. Playback will start at the
+ // specified buffer and system timestamp.
+ //
+ // May only be called in the 'Stopped' state, and following this call the
+ // state machine will be in the 'Playing' state.
+ //
+ // StopRequest
+ // Stops media playback and drops all pushed buffers which have not yet been
+ // played.
+ //
+ // May only be called in the 'Playing' or 'Paused' states, and following
+ // this call the state machine will be in the 'Stopped' state.
+ //
+ // PauseRequest
+ // Pauses media playback.
+ //
+ // May only be called in the 'Playing' state, and following this call the
+ // state machine will be in the 'Paused' state.
+ //
+ // ResumeRequest
+ // Resumes media playback at the specified buffer and system timestamp.
+ //
+ // May only be called in the 'Paused' state, and following this call the
+ // state machine will be in the 'Playing'' state.
+ //
+ // TimestampUpdateRequest
+ // Sends a timestamp update for a specified buffer for audio
+ // synchronization. This should be called when operating in
+ // CAST_AUDIO_DECODER_MODE_MULTIROOM_ONLY when the runtime has detected a
+ // discrepancy in the system clock or pipeline delay from the original
+ // playback schedule. See example below:
+ //
+ // Assume all buffers have duration of 100us.
+ //
+ // StartRequest(id=1, system_timestamp=0);
+ // -> Cast expects id=1 to play at 0, id=2 at 100us, id=3 at 200 us...
+ //
+ // TimestampUpdateRequest(id=4, system_timestamp=405us);
+ // -> Cast expects id=4 to play at 405, id=5 at 505us, id=6 at 605 us...
+ //
+ // May be called from any state.
+ //
+ // A state transition may only occur after a successful PushBuffer()
+ // call has been made with a valid configuration.
+ rpc StateChange(StateChangeRequest) returns (StateChangeResponse);
+
+ // Sets the volume multiplier for this audio stream.
+ // The multiplier is in the range [0.0, 1.0]. If not called, a default
+ // multiplier of 1.0 is assumed.
+ //
+ // May be called in any state, and following this call the state machine
+ // will be in the same state.
+ rpc SetVolume(SetVolumeRequest) returns (SetVolumeResponse);
+
+ // Sets the playback rate for this audio stream.
+ //
+ // May be called in any state, and following this call the state machine
+ // will be in the same state.
+ rpc SetPlaybackRate(SetPlaybackRateRequest) returns (SetPlaybackRateResponse);
+
+ // Sends decoded bits and responses to the audio service. The client must
+ // wait for a response from the server before sending another
+ // PushBufferRequest.
+ //
+ // May only be called in the 'Playing' or 'Paused' states, and following
+ // this call the state machine will remain the same state.
+ //
+ rpc PushBuffer(PushBufferRequest) returns (PushBufferResponse);
+
+ // Returns the current media time that has been rendered.
+ rpc GetMediaTime(GetMediaTimeRequest) returns (GetMediaTimeResponse);
+}
+
+message InitializeRequest {
+ // Cast session ID.
+ string cast_session_id = 1;
+
+ // Configures how the server should operate.
+ CastAudioDecoderMode mode = 2;
+}
+
+message InitializeResponse {}
+
+message GetMinimumBufferDelayRequest {}
+
+message GetMinimumBufferDelayResponse {
+ // The minimum buffering delay in microseconds.
+ int64 delay_micros = 1;
+}
+
+message StateChangeRequest {
+ oneof request {
+ StartRequest start = 1;
+ StopRequest stop = 2;
+ PauseRequest pause = 3;
+ ResumeRequest resume = 4;
+ TimestampUpdateRequest timestamp_update = 5;
+ }
+}
+
+message StateChangeResponse {
+ // Pipeline state after state change.
+ PipelineState state = 1;
+}
+
+message SetVolumeRequest {
+ // The multiplier is in the range [0.0, 1.0].
+ float multiplier = 1;
+}
+
+message SetVolumeResponse {}
+
+message SetPlaybackRateRequest {
+ // Playback rate greater than 0.
+ double rate = 1;
+}
+
+message SetPlaybackRateResponse {}
+
+message PushBufferRequest {
+ AudioDecoderBuffer buffer = 1;
+
+ // Audio configuration for this buffer and all subsequent buffers. This
+ // field must be populated for the first request or if there is an audio
+ // configuration change.
+ AudioConfiguration audio_config = 2;
+}
+
+message PushBufferResponse {
+ // The total number of decoded bytes.
+ int64 decoded_bytes = 1;
+}
+
+message GetMediaTimeRequest {}
+
+message GetMediaTimeResponse {
+ // The current media time that has been rendered.
+ MediaTime media_time = 1;
+}
+
enum PipelineState {
PIPELINE_STATE_UNINITIALIZED = 0;
PIPELINE_STATE_STOPPED = 1;
@@ -137,19 +308,6 @@ message TimestampInfo {
int64 buffer_id = 2;
}
-message InitializeRequest {
- // Cast session ID.
- string cast_session_id = 1;
-
- // Configures how the server should operate.
- CastAudioDecoderMode mode = 2;
-}
-
-message GetMinimumBufferingDelayResponse {
- // The minimum buffering delay in microseconds.
- int64 delay_micros = 1;
-}
-
message StartRequest {
// The start presentation timestamp in microseconds.
int64 pts_micros = 1;
@@ -174,143 +332,3 @@ message ResumeRequest {
message TimestampUpdateRequest {
TimestampInfo timestamp_info = 1;
}
-
-message StateChangeRequest {
- oneof request {
- StartRequest start = 1;
- StopRequest stop = 2;
- PauseRequest pause = 3;
- ResumeRequest resume = 4;
- TimestampUpdateRequest timestamp_update = 5;
- }
-}
-
-message StateChangeResponse {
- // Pipeline state after state change.
- PipelineState state = 1;
-}
-
-message PushBufferRequest {
- AudioDecoderBuffer buffer = 1;
-
- // Audio configuration for this buffer and all subsequent buffers. This
- // field must be populated for the first request or if there is an audio
- // configuration change.
- AudioConfiguration audio_config = 2;
-}
-
-message PushBufferResponse {
- // The total number of decoded bytes.
- int64 decoded_bytes = 1;
-}
-
-message SetVolumeRequest {
- // The multiplier is in the range [0.0, 1.0].
- float multiplier = 1;
-}
-message SetPlaybackRateRequest {
- // Playback rate greater than 0.
- double rate = 1;
-}
-
-message GetMediaTimeResponse {
- // The current media time that has been rendered.
- MediaTime media_time = 1;
-}
-
-// Cast audio service hosted by Cast Core.
-//
-// It defines a state machine with the following states:
-// - Uninitialized
-// - Playing
-// - Stopped
-// - Paused
-//
-// Note that the received ordering between different RPC calls is not
-// guaranteed to match the sent order.
-service CastRuntimeAudioChannel {
- // Initializes the service and places the pipeline into the 'Stopped' state.
- // This must be the first call received by the server, and no other calls
- // may be sent prior to receiving this call's response.
- rpc Initialize(InitializeRequest) returns (google.protobuf.Empty);
-
- // Returns the minimum buffering delay (min_delay) required by Cast. This is
- // a constant value and only needs to be queried once for each service.
- // During a StartRequest or ResumeRequest, the system timestamp must be
- // greater than this delay and the current time in order for the buffer to be
- // successfully rendered on remote devices.
- rpc GetMinimumBufferDelay(google.protobuf.Empty)
- returns (GetMinimumBufferingDelayResponse);
-
- // Update the pipeline state.
- //
- // StartRequest:
- // Places pipeline into 'Playing' state. Playback will start at the
- // specified buffer and system timestamp.
- //
- // May only be called in the 'Stopped' state, and following this call the
- // state machine will be in the 'Playing' state.
- //
- // StopRequest
- // Stops media playback and drops all pushed buffers which have not yet been
- // played.
- //
- // May only be called in the 'Playing' or 'Paused' states, and following
- // this call the state machine will be in the 'Stopped' state.
- //
- // PauseRequest
- // Pauses media playback.
- //
- // May only be called in the 'Playing' state, and following this call the
- // state machine will be in the 'Paused' state.
- //
- // ResumeRequest
- // Resumes media playback at the specified buffer and system timestamp.
- //
- // May only be called in the 'Paused' state, and following this call the
- // state machine will be in the 'Playing'' state.
- //
- // TimestampUpdateRequest
- // Sends a timestamp update for a specified buffer for audio
- // synchronization. This should be called when operating in
- // CAST_AUDIO_DECODER_MODE_MULTIROOM_ONLY when the runtime has detected a
- // discrepancy in the system clock or pipeline delay from the original
- // playback schedule. See example below:
- //
- // Assume all buffers have duration of 100us.
- //
- // StartRequest(id=1, system_timestamp=0);
- // -> Cast expects id=1 to play at 0, id=2 at 100us, id=3 at 200 us...
- //
- // TimestampUpdateRequest(id=4, system_timestamp=405us);
- // -> Cast expects id=4 to play at 405, id=5 at 505us, id=6 at 605 us...
- //
- // May be called from any state.
- //
- // A state transition may only occur after a successful PushBuffer()
- // call has been made with a valid configuration.
- rpc StateChange(StateChangeRequest) returns (StateChangeResponse);
-
- // Sets the volume multiplier for this audio stream.
- // The multiplier is in the range [0.0, 1.0]. If not called, a default
- // multiplier of 1.0 is assumed.
- //
- // May be called in any state, and following this call the state machine
- // will be in the same state.
- rpc SetVolume(SetVolumeRequest) returns (google.protobuf.Empty);
-
- // Sets the playback rate for this audio stream.
- //
- // May be called in any state, and following this call the state machine
- // will be in the same state.
- rpc SetPlayback(SetPlaybackRateRequest) returns (google.protobuf.Empty);
-
- // Streams decoded bits and responses to the audio service.
- //
- // May only be called in the 'Playing' or 'Paused' states, and following
- // this call the state machine will remain the same state.
- rpc PushBuffer(stream PushBufferRequest) returns (PushBufferResponse);
-
- // Returns the current media time that has been rendered.
- rpc GetMediaTime(google.protobuf.Empty) returns (GetMediaTimeResponse);
-}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/runtime_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/runtime_service.proto
index cc30fdaf81b..b3010c6d5e8 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/runtime_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/runtime/runtime_service.proto
@@ -1,9 +1,13 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.runtime;
import "google/protobuf/duration.proto";
-import "google/protobuf/empty.proto";
import "cast/cast_core/api/common/service_info.proto";
option optimize_for = LITE_RUNTIME;
@@ -13,8 +17,8 @@ option optimize_for = LITE_RUNTIME;
// This service is called by CastCore after Runtime starts up.
service RuntimeService {
// Launches a Cast application. The application must connect to the
- // CoreApplicationService based on cast_protocol and
- // core_application_endpoint, and provide its endpoint.
+ // CoreApplicationService via core_application_service_info and start its
+ // RuntimeApplicationService on runtime_applicationn_service_info.
rpc LaunchApplication(LaunchApplicationRequest)
returns (LaunchApplicationResponse);
@@ -33,16 +37,11 @@ service RuntimeService {
// Provides information need by the runtime to start recording metrics via
// the core.
rpc StartMetricsRecorder(StartMetricsRecorderRequest)
- returns (google.protobuf.Empty);
+ returns (StartMetricsRecorderResponse);
// Stops the metrics recorder, which may also attempt to flush.
- rpc StopMetricsRecorder(google.protobuf.Empty)
- returns (google.protobuf.Empty);
-}
-
-message StartMetricsRecorderRequest {
- // Metrics service info.
- cast.common.ServiceInfo metrics_recorder_service_info = 1;
+ rpc StopMetricsRecorder(StopMetricsRecorderRequest)
+ returns (StopMetricsRecorderResponse);
}
message LaunchApplicationRequest {
@@ -51,6 +50,9 @@ message LaunchApplicationRequest {
// Cast session id used to setup a connection and pull the config from core
// application service.
string cast_session_id = 2;
+ // RuntimeApplication service info. The endpoint is generated by Cast Core and
+ // must be used by the Runtime to bind the RuntimeApplication service.
+ cast.common.ServiceInfo runtime_application_service_info = 3;
}
// Returned by the runtime in response to a launch application request.
@@ -77,3 +79,14 @@ message HeartbeatRequest {
}
message HeartbeatResponse {}
+
+message StartMetricsRecorderRequest {
+ // Metrics service info.
+ cast.common.ServiceInfo metrics_recorder_service_info = 1;
+}
+
+message StartMetricsRecorderResponse {}
+
+message StopMetricsRecorderRequest {}
+
+message StopMetricsRecorderResponse {}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/cast_message.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/cast_message.proto
index c429cf95454..62e7b1047e3 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/cast_message.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/cast_message.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.v2;
@@ -5,7 +10,7 @@ package cast.v2;
option optimize_for = LITE_RUNTIME;
// Cast V2 request definition.
-message CastMessage {
+message CastMessageRequest {
// Cast sender ID; distinct from virtual connection source ID.
string sender_id = 1;
// Cast namespace.
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/core_application_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/core_application_service.proto
index 86b729ab322..de4f2b02ec5 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/core_application_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/core_application_service.proto
@@ -1,8 +1,12 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.v2;
-import "google/protobuf/empty.proto";
import "cast/cast_core/api/bindings/api_bindings.proto";
import "cast/cast_core/api/common/application_config.proto";
import "cast/cast_core/api/common/service_info.proto";
@@ -21,13 +25,14 @@ service CoreApplicationService {
rpc GetConfig(GetConfigRequest) returns (GetConfigResponse);
// Send a Cast V2 message to core application.
- rpc SendCastMessage(CastMessage) returns (CastMessageResponse);
+ rpc SendCastMessage(CastMessageRequest) returns (CastMessageResponse);
// Notifies Cast Core on the application state changes. The callback must be
// called by the Runtime whenever the internal state of the application
// changes. Cast Core may discard any resources associated with the
// application upon failures.
- rpc OnApplicationStatus(ApplicationStatus) returns (google.protobuf.Empty);
+ rpc SetApplicationStatus(ApplicationStatusRequest)
+ returns (ApplicationStatusResponse);
// Posts messages between MessagePorts. MessagePorts are connected using other
// services (e.g. ApiBindings), then registered with the
@@ -35,17 +40,17 @@ service CoreApplicationService {
rpc PostMessage(cast.web.Message) returns (cast.web.MessagePortStatus);
// Gets the list of bindings to early-inject into javascript at page load.
- rpc GetAll(google.protobuf.Empty) returns (cast.bindings.GetAllResponse);
+ rpc GetAll(cast.bindings.GetAllRequest)
+ returns (cast.bindings.GetAllResponse);
// Connects to a binding returned by GetAll.
- rpc Connect(cast.bindings.ConnectRequest) returns (google.protobuf.Empty);
+ rpc Connect(cast.bindings.ConnectRequest)
+ returns (cast.bindings.ConnectResponse);
}
message GetConfigRequest {
// Cast session ID.
string cast_session_id = 1;
- // RuntimeApplication service info.
- cast.common.ServiceInfo runtime_application_service_info = 2;
}
message GetConfigResponse {
@@ -58,7 +63,7 @@ message GetConfigResponse {
}
// Contains information about an application status in the runtime.
-message ApplicationStatus {
+message ApplicationStatusRequest {
// The Cast session ID whose application status changed.
string cast_session_id = 1;
@@ -89,3 +94,5 @@ message ApplicationStatus {
// |stop_reason| is HTTP_ERROR.
int32 http_response_code = 4;
}
+
+message ApplicationStatusResponse {}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/runtime_application_service.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/runtime_application_service.proto
index e8bc21bab29..292dbaa9ffb 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/runtime_application_service.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/runtime_application_service.proto
@@ -1,8 +1,12 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.v2;
-import "google/protobuf/empty.proto";
import "cast/cast_core/api/v2/cast_message.proto";
import "cast/cast_core/api/v2/url_rewrite.proto";
import "cast/cast_core/api/web/message_channel.proto";
@@ -14,16 +18,8 @@ option optimize_for = LITE_RUNTIME;
// This service is implemented by the Runtime and represents services
// specific to a Cast application.
service RuntimeApplicationService {
- // Notifies the runtime that a new Cast V2 virtual connection has been opened.
- rpc OnVirtualConnectionOpen(VirtualConnectionInfo)
- returns (google.protobuf.Empty);
-
- // Notifies the runtime that a Cast V2 virtual connection has been closed.
- rpc OnVirtualConnectionClosed(VirtualConnectionInfo)
- returns (google.protobuf.Empty);
-
// Sends a Cast message to the runtime.
- rpc SendCastMessage(CastMessage) returns (CastMessageResponse);
+ rpc SendCastMessage(CastMessageRequest) returns (CastMessageResponse);
// Set the URL rewrite rules that the Runtime will use to contact the MSP
// This is called when the rewrite rules are changed
@@ -44,16 +40,3 @@ message SetUrlRewriteRulesRequest {
}
message SetUrlRewriteRulesResponse {}
-
-// Request by the sender to open or close a virtual connection to the Cast
-// runtime.
-message VirtualConnectionInfo {
- // The source of the virtual connection request. Connections from the
- // sender platform use an id of 'sender-0' and connections from applications
- // use a unique ID.
- string source_id = 1;
- // The destination of the connection request. Connections to the Cast
- // receiver platform use an id of 'receiver-0' and connections to applications
- // use the Cast session id.
- string destination_id = 2;
-}
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/url_rewrite.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/url_rewrite.proto
index 94d7f3b511d..6f637c8da70 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/v2/url_rewrite.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/v2/url_rewrite.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.v2;
diff --git a/chromium/third_party/openscreen/src/cast/cast_core/api/web/message_channel.proto b/chromium/third_party/openscreen/src/cast/cast_core/api/web/message_channel.proto
index df4ea15d2d0..4e3f1deda04 100644
--- a/chromium/third_party/openscreen/src/cast/cast_core/api/web/message_channel.proto
+++ b/chromium/third_party/openscreen/src/cast/cast_core/api/web/message_channel.proto
@@ -1,3 +1,8 @@
+// Copyright 2021 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.
+//
+// **** DO NOT EDIT - this .proto was automatically generated. ****
syntax = "proto3";
package cast.web;
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
index 350aca6ef4d..764ac3e4610 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_cert_validator_internal.cc
@@ -6,12 +6,16 @@
#include <openssl/asn1.h>
#include <openssl/evp.h>
+#include <openssl/mem.h>
+#include <openssl/ossl_typ.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <time.h>
#include <chrono>
+#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include "cast/common/certificate/types.h"
@@ -24,6 +28,14 @@ namespace {
constexpr static int32_t kMinRsaModulusLengthBits = 2048;
+// TODO(davidben): Switch this to bssl::UniquePtr after
+// https://boringssl-review.googlesource.com/c/boringssl/+/46105 lands.
+struct FreeNameConstraints {
+ void operator()(NAME_CONSTRAINTS* nc) { NAME_CONSTRAINTS_free(nc); }
+};
+using NameConstraintsPtr =
+ std::unique_ptr<NAME_CONSTRAINTS, FreeNameConstraints>;
+
// Stores intermediate state while attempting to find a valid certificate chain
// from a set of trusted certificates to a target certificate. Together, a
// sequence of these forms a certificate chain to be verified as well as a stack
@@ -59,23 +71,23 @@ bool CertInPath(X509_NAME* name,
return false;
}
-// Parse the data in |time| at |index| as a two-digit ascii number.
-uint8_t ParseAsn1TimeDoubleDigit(ASN1_GENERALIZEDTIME* time, int index) {
- return (time->data[index] - '0') * 10 + (time->data[index + 1] - '0');
+// Parse the data in |time| at |index| as a two-digit ascii number. Note this
+// function assumes the caller already did a bounds check and checked the inputs
+// are digits.
+uint8_t ParseAsn1TimeDoubleDigit(absl::string_view time, size_t index) {
+ OSP_DCHECK_LT(index + 1, time.size());
+ OSP_DCHECK('0' <= time[index] && time[index] <= '9');
+ OSP_DCHECK('0' <= time[index + 1] && time[index + 1] <= '9');
+ return (time[index] - '0') * 10 + (time[index + 1] - '0');
}
bssl::UniquePtr<BASIC_CONSTRAINTS> GetConstraints(X509* issuer) {
- const int basic_constraints_index =
- X509_get_ext_by_NID(issuer, NID_basic_constraints, -1);
- if (basic_constraints_index == -1) {
- return nullptr;
- }
-
- X509_EXTENSION* const basic_constraints_extension =
- X509_get_ext(issuer, basic_constraints_index);
+ // TODO(davidben): This and other |X509_get_ext_d2i| are missing
+ // error-handling for syntax errors in certificates. See BoringSSL
+ // documentation for the calling convention.
return bssl::UniquePtr<BASIC_CONSTRAINTS>{
reinterpret_cast<BASIC_CONSTRAINTS*>(
- X509V3_EXT_d2i(basic_constraints_extension))};
+ X509_get_ext_d2i(issuer, NID_basic_constraints, nullptr, nullptr))};
}
Error::Code VerifyCertTime(X509* cert, const DateTime& time) {
@@ -96,18 +108,8 @@ bool VerifyPublicKeyLength(EVP_PKEY* public_key) {
}
bssl::UniquePtr<ASN1_BIT_STRING> GetKeyUsage(X509* cert) {
- int pos = X509_get_ext_by_NID(cert, NID_key_usage, -1);
- if (pos == -1) {
- return nullptr;
- }
- X509_EXTENSION* key_usage = X509_get_ext(cert, pos);
- const uint8_t* value = key_usage->value->data;
- ASN1_BIT_STRING* key_usage_bit_string = nullptr;
- if (!d2i_ASN1_BIT_STRING(&key_usage_bit_string, &value,
- key_usage->value->length)) {
- return nullptr;
- }
- return bssl::UniquePtr<ASN1_BIT_STRING>{key_usage_bit_string};
+ return bssl::UniquePtr<ASN1_BIT_STRING>{reinterpret_cast<ASN1_BIT_STRING*>(
+ X509_get_ext_d2i(cert, NID_key_usage, nullptr, nullptr))};
}
Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
@@ -116,13 +118,14 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
// Default max path length is the number of intermediate certificates.
int max_pathlen = path.size() - 2;
- std::vector<NAME_CONSTRAINTS*> path_name_constraints;
+ std::vector<NameConstraintsPtr> path_name_constraints;
Error::Code error = Error::Code::kNone;
uint32_t i = step_index;
for (; i < path.size() - 1; ++i) {
X509* subject = path[i + 1].cert;
X509* issuer = path[i].cert;
bool is_root = (i == step_index);
+ bool issuer_is_self_issued = false;
if (!is_root) {
if ((error = VerifyCertTime(issuer, time)) != Error::Code::kNone) {
return error;
@@ -134,10 +137,10 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
}
--max_pathlen;
} else {
- issuer->ex_flags |= EXFLAG_SI;
+ issuer_is_self_issued = true;
}
} else {
- issuer->ex_flags |= EXFLAG_SI;
+ issuer_is_self_issued = true;
}
bssl::UniquePtr<ASN1_BIT_STRING> key_usage = GetKeyUsage(issuer);
@@ -172,7 +175,9 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
}
}
- if (X509_ALGOR_cmp(issuer->sig_alg, issuer->cert_info->signature) != 0) {
+ const X509_ALGOR* issuer_sig_alg;
+ X509_get0_signature(nullptr, &issuer_sig_alg, issuer);
+ if (X509_ALGOR_cmp(issuer_sig_alg, X509_get0_tbs_sigalg(issuer)) != 0) {
return Error::Code::kErrCertsVerifyGeneric;
}
@@ -183,47 +188,39 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
// NOTE: (!self-issued || target) -> verify name constraints. Target case
// is after the loop.
- const bool is_self_issued = issuer->ex_flags & EXFLAG_SI;
- if (!is_self_issued) {
- for (NAME_CONSTRAINTS* name_constraints : path_name_constraints) {
- if (NAME_CONSTRAINTS_check(subject, name_constraints) != X509_V_OK) {
+ if (!issuer_is_self_issued) {
+ for (const auto& name_constraints : path_name_constraints) {
+ if (NAME_CONSTRAINTS_check(subject, name_constraints.get()) !=
+ X509_V_OK) {
return Error::Code::kErrCertsVerifyGeneric;
}
}
}
- if (issuer->nc) {
- path_name_constraints.push_back(issuer->nc);
- } else {
- const int index = X509_get_ext_by_NID(issuer, NID_name_constraints, -1);
- if (index != -1) {
- X509_EXTENSION* ext = X509_get_ext(issuer, index);
- auto* nc = reinterpret_cast<NAME_CONSTRAINTS*>(X509V3_EXT_d2i(ext));
- if (nc) {
- issuer->nc = nc;
- path_name_constraints.push_back(nc);
- } else {
- return Error::Code::kErrCertsVerifyGeneric;
- }
- }
+ int critical;
+ NameConstraintsPtr nc{reinterpret_cast<NAME_CONSTRAINTS*>(
+ X509_get_ext_d2i(issuer, NID_name_constraints, &critical, nullptr))};
+ if (!nc && critical != -1) {
+ // X509_get_ext_d2i's error handling is a little confusing. See
+ // https://boringssl.googlesource.com/boringssl/+/215f4a0287/include/openssl/x509.h#1384
+ // https://boringssl.googlesource.com/boringssl/+/215f4a0287/include/openssl/x509v3.h#651
+ return Error::Code::kErrCertsVerifyGeneric;
+ }
+ if (nc) {
+ path_name_constraints.push_back(std::move(nc));
}
// Check that any policy mappings present are _not_ the anyPolicy OID. Even
// though we don't otherwise handle policies, this is required by RFC 5280
// 6.1.4(a).
- const int policy_mappings_index =
- X509_get_ext_by_NID(issuer, NID_policy_mappings, -1);
- if (policy_mappings_index != -1) {
- X509_EXTENSION* policy_mappings_extension =
- X509_get_ext(issuer, policy_mappings_index);
- auto* policy_mappings = reinterpret_cast<POLICY_MAPPINGS*>(
- X509V3_EXT_d2i(policy_mappings_extension));
- const uint32_t policy_mapping_count =
- sk_POLICY_MAPPING_num(policy_mappings);
+ //
+ // TODO(davidben): Switch to bssl::UniquePtr once
+ // https://boringssl-review.googlesource.com/c/boringssl/+/46104 has landed.
+ auto* policy_mappings = reinterpret_cast<POLICY_MAPPINGS*>(
+ X509_get_ext_d2i(issuer, NID_policy_mappings, nullptr, nullptr));
+ if (policy_mappings) {
const ASN1_OBJECT* any_policy = OBJ_nid2obj(NID_any_policy);
- for (uint32_t i = 0; i < policy_mapping_count; ++i) {
- POLICY_MAPPING* policy_mapping =
- sk_POLICY_MAPPING_value(policy_mappings, i);
+ for (const POLICY_MAPPING* policy_mapping : policy_mappings) {
const bool either_matches =
((OBJ_cmp(policy_mapping->issuerDomainPolicy, any_policy) == 0) ||
(OBJ_cmp(policy_mapping->subjectDomainPolicy, any_policy) == 0));
@@ -242,8 +239,8 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
int extension_count = X509_get_ext_count(issuer);
for (int i = 0; i < extension_count; ++i) {
X509_EXTENSION* extension = X509_get_ext(issuer, i);
- if (extension->critical > 0) {
- const int nid = OBJ_obj2nid(extension->object);
+ if (X509_EXTENSION_get_critical(extension)) {
+ const int nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
if (nid != NID_name_constraints && nid != NID_basic_constraints &&
nid != NID_key_usage) {
return Error::Code::kErrCertsVerifyGeneric;
@@ -251,7 +248,7 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
}
}
- int nid = OBJ_obj2nid(subject->sig_alg->algorithm);
+ int nid = X509_get_signature_nid(subject);
const EVP_MD* digest;
switch (nid) {
case NID_sha1WithRSAEncryption:
@@ -269,18 +266,24 @@ Error::Code VerifyCertificateChain(const std::vector<CertPathStep>& path,
default:
return Error::Code::kErrCertsVerifyGeneric;
}
+ uint8_t* tbs = nullptr;
+ int tbs_len = i2d_X509_tbs(subject, &tbs);
+ if (tbs_len < 0) {
+ return Error::Code::kErrCertsVerifyGeneric;
+ }
+ bssl::UniquePtr<uint8_t> free_tbs{tbs};
+ const ASN1_BIT_STRING* signature;
+ X509_get0_signature(&signature, nullptr, subject);
if (!VerifySignedData(
- digest, public_key.get(),
- {subject->cert_info->enc.enc,
- static_cast<uint32_t>(subject->cert_info->enc.len)},
- {subject->signature->data,
- static_cast<uint32_t>(subject->signature->length)})) {
+ digest, public_key.get(), {tbs, static_cast<uint32_t>(tbs_len)},
+ {ASN1_STRING_get0_data(signature),
+ static_cast<uint32_t>(ASN1_STRING_length(signature))})) {
return Error::Code::kErrCertsVerifyGeneric;
}
}
// NOTE: Other half of ((!self-issued || target) -> check name constraints).
- for (NAME_CONSTRAINTS* name_constraints : path_name_constraints) {
- if (NAME_CONSTRAINTS_check(path.back().cert, name_constraints) !=
+ for (const auto& name_constraints : path_name_constraints) {
+ if (NAME_CONSTRAINTS_check(path.back().cert, name_constraints.get()) !=
X509_V_OK) {
return Error::Code::kErrCertsVerifyGeneric;
}
@@ -302,24 +305,27 @@ bool ParseAsn1GeneralizedTime(ASN1_GENERALIZEDTIME* time, DateTime* out) {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
};
- if (time->length != 15) {
+ absl::string_view time_str{
+ reinterpret_cast<const char*>(ASN1_STRING_get0_data(time)),
+ static_cast<size_t>(ASN1_STRING_length(time))};
+ if (time_str.size() != 15) {
return false;
}
- if (time->data[14] != 'Z') {
+ if (time_str[14] != 'Z') {
return false;
}
- for (int i = 0; i < 14; ++i) {
- if (time->data[i] < '0' || time->data[i] > '9') {
+ for (size_t i = 0; i < 14; ++i) {
+ if (time_str[i] < '0' || time_str[i] > '9') {
return false;
}
}
- out->year = ParseAsn1TimeDoubleDigit(time, 0) * 100 +
- ParseAsn1TimeDoubleDigit(time, 2);
- out->month = ParseAsn1TimeDoubleDigit(time, 4);
- out->day = ParseAsn1TimeDoubleDigit(time, 6);
- out->hour = ParseAsn1TimeDoubleDigit(time, 8);
- out->minute = ParseAsn1TimeDoubleDigit(time, 10);
- out->second = ParseAsn1TimeDoubleDigit(time, 12);
+ out->year = ParseAsn1TimeDoubleDigit(time_str, 0) * 100 +
+ ParseAsn1TimeDoubleDigit(time_str, 2);
+ out->month = ParseAsn1TimeDoubleDigit(time_str, 4);
+ out->day = ParseAsn1TimeDoubleDigit(time_str, 6);
+ out->hour = ParseAsn1TimeDoubleDigit(time_str, 8);
+ out->minute = ParseAsn1TimeDoubleDigit(time_str, 10);
+ out->second = ParseAsn1TimeDoubleDigit(time_str, 12);
if (out->month == 0 || out->month > 12) {
return false;
}
@@ -350,18 +356,15 @@ bool ParseAsn1GeneralizedTime(ASN1_GENERALIZEDTIME* time, DateTime* out) {
bool GetCertValidTimeRange(X509* cert,
DateTime* not_before,
DateTime* not_after) {
- ASN1_GENERALIZEDTIME* not_before_asn1 = ASN1_TIME_to_generalizedtime(
- cert->cert_info->validity->notBefore, nullptr);
- ASN1_GENERALIZEDTIME* not_after_asn1 = ASN1_TIME_to_generalizedtime(
- cert->cert_info->validity->notAfter, nullptr);
+ bssl::UniquePtr<ASN1_GENERALIZEDTIME> not_before_asn1{
+ ASN1_TIME_to_generalizedtime(X509_get0_notBefore(cert), nullptr)};
+ bssl::UniquePtr<ASN1_GENERALIZEDTIME> not_after_asn1{
+ ASN1_TIME_to_generalizedtime(X509_get0_notAfter(cert), nullptr)};
if (!not_before_asn1 || !not_after_asn1) {
return false;
}
- bool times_valid = ParseAsn1GeneralizedTime(not_before_asn1, not_before) &&
- ParseAsn1GeneralizedTime(not_after_asn1, not_after);
- ASN1_GENERALIZEDTIME_free(not_before_asn1);
- ASN1_GENERALIZEDTIME_free(not_after_asn1);
- return times_valid;
+ return ParseAsn1GeneralizedTime(not_before_asn1.get(), not_before) &&
+ ParseAsn1GeneralizedTime(not_after_asn1.get(), not_after);
}
// static
@@ -428,8 +431,9 @@ Error FindCertificatePath(const std::vector<std::string>& der_certs,
OSP_DVLOG << "FindCertificatePath: Failed with invalid public key length";
return Error::Code::kErrCertsVerifyGeneric;
}
- if (X509_ALGOR_cmp(target_cert.get()->sig_alg,
- target_cert.get()->cert_info->signature) != 0) {
+ const X509_ALGOR* sig_alg;
+ X509_get0_signature(nullptr, &sig_alg, target_cert.get());
+ if (X509_ALGOR_cmp(sig_alg, X509_get0_tbs_sigalg(target_cert.get())) != 0) {
return Error::Code::kErrCertsVerifyGeneric;
}
bssl::UniquePtr<ASN1_BIT_STRING> key_usage = GetKeyUsage(target_cert.get());
diff --git a/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl.cc b/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl.cc
index c7635a4fe2a..aa269df5bd0 100644
--- a/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl.cc
+++ b/chromium/third_party/openscreen/src/cast/common/certificate/cast_crl.cc
@@ -107,14 +107,15 @@ bool VerifyCRL(const Crl& crl,
// (excluding trust anchor). No intermediates are provided above, so this
// just amounts to |signer_cert| vs. |not_after_seconds|.
*overall_not_after = not_after;
- ASN1_GENERALIZEDTIME* not_after_asn1 = ASN1_TIME_to_generalizedtime(
- result_path.target_cert->cert_info->validity->notAfter, nullptr);
+ bssl::UniquePtr<ASN1_GENERALIZEDTIME> not_after_asn1{
+ ASN1_TIME_to_generalizedtime(
+ X509_get0_notAfter(result_path.target_cert.get()), nullptr)};
if (!not_after_asn1) {
return false;
}
DateTime cert_not_after;
- bool time_valid = ParseAsn1GeneralizedTime(not_after_asn1, &cert_not_after);
- ASN1_GENERALIZEDTIME_free(not_after_asn1);
+ bool time_valid =
+ ParseAsn1GeneralizedTime(not_after_asn1.get(), &cert_not_after);
if (!time_valid) {
return false;
}
@@ -199,7 +200,7 @@ bool CastCRL::CheckRevocation(const std::vector<X509*>& trusted_chain,
// Only Google generated device certificates will be revoked by range.
// These will always be less than 64 bits in length.
ErrorOr<uint64_t> maybe_serial =
- ParseDerUint64(subordinate->cert_info->serialNumber);
+ ParseDerUint64(X509_get0_serialNumber(subordinate));
if (!maybe_serial) {
continue;
}
diff --git a/chromium/third_party/openscreen/src/cast/common/discovery/e2e_test/tests.cc b/chromium/third_party/openscreen/src/cast/common/discovery/e2e_test/tests.cc
index 9a02053b7a4..7c29441829a 100644
--- a/chromium/third_party/openscreen/src/cast/common/discovery/e2e_test/tests.cc
+++ b/chromium/third_party/openscreen/src/cast/common/discovery/e2e_test/tests.cc
@@ -143,7 +143,7 @@ class DiscoveryE2ETest : public testing::Test {
// Sleep to let any packets clear off the network before further tests.
std::this_thread::sleep_for(milliseconds(500));
- PlatformClientPosix::Create(milliseconds(50), milliseconds(50));
+ PlatformClientPosix::Create(milliseconds(50));
task_runner_ = PlatformClientPosix::GetInstance()->GetTaskRunner();
}
diff --git a/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_examples/answer.json b/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_examples/answer.json
index 97a3e59aaae..73c45ea26f4 100644
--- a/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_examples/answer.json
+++ b/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_examples/answer.json
@@ -12,8 +12,7 @@
"maxSampleRate": 96000,
"maxChannels": 5,
"minBitRate": 32000,
- "maxBitRate": 320000,
- "maxDelay": 4000
+ "maxBitRate": 320000
},
"video": {
"maxPixelsPerSecond": 62208000,
diff --git a/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_schema.json b/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_schema.json
index 2c2fc59acf2..392d135cd43 100644
--- a/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_schema.json
+++ b/chromium/third_party/openscreen/src/cast/protocol/castv2/streaming_schema.json
@@ -110,7 +110,7 @@
"maxBitRate": {"type": "integer", "minimum": 32000, "maximum": 320000},
"maxDelay": {"$ref": "#/definitions/delay"}
},
- "required": ["maxSampleRate", "maxChannels", "maxBitRate", "maxDelay"]
+ "required": ["maxSampleRate", "maxChannels", "maxBitRate"]
},
"video_constraints": {
"properties": {
@@ -122,10 +122,8 @@
"maxDelay": {"$ref": "#/definitions/delay"}
},
"required": [
- "maxPixelsPerSecond",
"maxDimensions",
- "maxBitRate",
- "maxDelay"
+ "maxBitRate"
]
},
"constraints": {
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_service.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_service.cc
index e4a5b531c80..75790197a3d 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_service.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/cast_service.cc
@@ -38,8 +38,7 @@ discovery::Config MakeDiscoveryConfig(const InterfaceInfo& interface) {
discovery::Config::NetworkInfo::kNoAddressFamily;
if (interface.GetIpAddressV4()) {
supported_address_families |= discovery::Config::NetworkInfo::kUseIpV4;
- }
- if (interface.GetIpAddressV6()) {
+ } else if (interface.GetIpAddressV6()) {
supported_address_families |= discovery::Config::NetworkInfo::kUseIpV6;
}
config.network_info.push_back({interface, supported_address_families});
@@ -84,6 +83,7 @@ CastService::CastService(TaskRunner* task_runner,
info.unique_id = HexEncode(interface.hardware_address);
info.friendly_name = friendly_name;
info.model_name = model_name;
+ info.capabilities = kHasVideoOutput | kHasAudioOutput;
Error error = discovery_publisher_->Register(info);
if (!error.ok()) {
OnFatalError(std::move(error));
diff --git a/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc b/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
index 1263f39cee2..9e305c8bd3c 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_receiver/main.cc
@@ -230,7 +230,7 @@ int RunStandaloneReceiver(int argc, char* argv[]) {
}
auto* const task_runner = new TaskRunnerImpl(&Clock::now);
- PlatformClientPosix::Create(milliseconds(50), milliseconds(50),
+ PlatformClientPosix::Create(milliseconds(50),
std::unique_ptr<TaskRunnerImpl>(task_runner));
RunCastService(task_runner, interface, std::move(creds.value()),
friendly_name, model_name, discovery_enabled);
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc
index 1a90cbb2cab..8c77577b655 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_cast_agent.cc
@@ -268,17 +268,28 @@ void LoopingFileCastAgent::OnRemoteMessagingOpened(bool success) {
void LoopingFileCastAgent::CreateAndStartSession() {
TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender);
+ OSP_DCHECK(remote_connection_.has_value());
environment_ =
std::make_unique<Environment>(&Clock::now, task_runner_, IPEndpoint{});
- OSP_DCHECK(remote_connection_.has_value());
- current_session_ = std::make_unique<SenderSession>(
- connection_settings_->receiver_endpoint.address, this, environment_.get(),
- &message_port_, remote_connection_->local_id,
- remote_connection_->peer_id);
+
+ SenderSession::Configuration config{
+ connection_settings_->receiver_endpoint.address,
+ this,
+ environment_.get(),
+ &message_port_,
+ remote_connection_->local_id,
+ remote_connection_->peer_id,
+ connection_settings_->use_android_rtp_hack};
+ current_session_ = std::make_unique<SenderSession>(std::move(config));
OSP_DCHECK(!message_port_.client_sender_id().empty());
AudioCaptureConfig audio_config;
+ // Opus does best at 192kbps, so we cap that here.
+ audio_config.bit_rate = 192 * 1000;
VideoCaptureConfig video_config;
+ // The video config is allowed to use whatever is left over after audio.
+ video_config.max_bit_rate =
+ connection_settings_->max_bitrate - audio_config.bit_rate;
// Use default display resolution of 1080P.
video_config.resolutions.emplace_back(DisplayResolution{});
@@ -299,11 +310,9 @@ void LoopingFileCastAgent::OnNegotiated(
return;
}
- OSP_LOG_INFO << "Streaming to " << connection_settings_->receiver_endpoint
- << "...";
file_sender_ = std::make_unique<LoopingFileSender>(
- environment_.get(), connection_settings_->path_to_file.c_str(), senders,
- connection_settings_->max_bitrate);
+ environment_.get(), connection_settings_->path_to_file.c_str(), session,
+ std::move(senders), connection_settings_->max_bitrate);
}
void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) {
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc
index 67aff23b20c..9fae843963b 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.cc
@@ -11,11 +11,12 @@ namespace cast {
LoopingFileSender::LoopingFileSender(Environment* environment,
const char* path,
+ const SenderSession* session,
SenderSession::ConfiguredSenders senders,
int max_bitrate)
: env_(environment),
path_(path),
- packet_router_(env_),
+ session_(session),
max_bitrate_(max_bitrate),
audio_encoder_(senders.audio_sender->config().channels,
StreamingOpusEncoder::kDefaultCastAudioFramesPerSecond,
@@ -51,7 +52,7 @@ void LoopingFileSender::UpdateEncoderBitrates() {
}
void LoopingFileSender::ControlForNetworkCongestion() {
- bandwidth_estimate_ = packet_router_.ComputeNetworkBandwidth();
+ bandwidth_estimate_ = session_->GetEstimatedNetworkBandwidth();
if (bandwidth_estimate_ > 0) {
// Don't ever try to use *all* of the network bandwidth! However, don't go
// below the absolute minimum requirement either.
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h
index 4f6c5d90715..e55a4a7e0c3 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/looping_file_sender.h
@@ -24,6 +24,7 @@ class LoopingFileSender final : public SimulatedAudioCapturer::Client,
public:
LoopingFileSender(Environment* environment,
const char* path,
+ const SenderSession* session,
SenderSession::ConfiguredSenders senders,
int max_bitrate);
@@ -59,11 +60,12 @@ class LoopingFileSender final : public SimulatedAudioCapturer::Client,
// The path to the media file to stream over and over.
const char* const path_;
- // The packet router allows both the Audio Sender and the Video Sender to
- // share the same UDP socket.
- SenderPacketRouter packet_router_;
+ // Session to query for bandwidth information.
+ const SenderSession* session_;
+
+ // User provided maximum bitrate (from command line argument).
+ const int max_bitrate_;
- const int max_bitrate_; // Passed by the user on the command line.
int bandwidth_estimate_ = 0;
int bandwidth_being_utilized_;
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
index da7ed24c71e..75b505534a4 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/main.cc
@@ -174,7 +174,7 @@ int StandaloneSenderMain(int argc, char* argv[]) {
#endif
auto* const task_runner = new TaskRunnerImpl(&Clock::now);
- PlatformClientPosix::Create(milliseconds(50), milliseconds(50),
+ PlatformClientPosix::Create(milliseconds(50),
std::unique_ptr<TaskRunnerImpl>(task_runner));
IPEndpoint remote_endpoint = ParseAsEndpoint(iface_or_endpoint);
diff --git a/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_vp8_encoder.cc b/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_vp8_encoder.cc
index 066e37f5ae1..8b8e18dc5f6 100644
--- a/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_vp8_encoder.cc
+++ b/chromium/third_party/openscreen/src/cast/standalone_sender/streaming_vp8_encoder.cc
@@ -226,6 +226,7 @@ void StreamingVp8Encoder::ProcessWorkUnitsUntilTimeToQuit() {
static_cast<WorkUnit&>(work_unit) = std::move(encode_queue_.front());
encode_queue_.pop();
force_key_frame = needs_key_frame_;
+ needs_key_frame_ = false;
target_bitrate = target_bitrate_;
}
diff --git a/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn b/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
index 04424cf4154..9f7d72524f4 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
+++ b/chromium/third_party/openscreen/src/cast/streaming/BUILD.gn
@@ -112,6 +112,7 @@ source_set("sender") {
"bandwidth_estimator.h",
"compound_rtcp_parser.cc",
"compound_rtcp_parser.h",
+ "remoting_capabilities.h",
"rtp_packetizer.cc",
"rtp_packetizer.h",
"sender.cc",
diff --git a/chromium/third_party/openscreen/src/cast/streaming/answer_messages.cc b/chromium/third_party/openscreen/src/cast/streaming/answer_messages.cc
index ed308260e8b..906e8901ed2 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/answer_messages.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/answer_messages.cc
@@ -210,10 +210,15 @@ bool AudioConstraints::ParseAndValidate(const Json::Value& root,
if (!json::ParseAndValidateInt(root[kMaxSampleRate],
&(out->max_sample_rate)) ||
!json::ParseAndValidateInt(root[kMaxChannels], &(out->max_channels)) ||
- !json::ParseAndValidateInt(root[kMaxBitRate], &(out->max_bit_rate)) ||
- !json::ParseAndValidateMilliseconds(root[kMaxDelay], &(out->max_delay))) {
+ !json::ParseAndValidateInt(root[kMaxBitRate], &(out->max_bit_rate))) {
return false;
}
+
+ std::chrono::milliseconds max_delay;
+ if (json::ParseAndValidateMilliseconds(root[kMaxDelay], &max_delay)) {
+ out->max_delay = max_delay;
+ }
+
if (!json::ParseAndValidateInt(root[kMinBitRate], &(out->min_bit_rate))) {
out->min_bit_rate = kDefaultAudioMinBitRate;
}
@@ -227,7 +232,9 @@ Json::Value AudioConstraints::ToJson() const {
root[kMaxChannels] = max_channels;
root[kMinBitRate] = min_bit_rate;
root[kMaxBitRate] = max_bit_rate;
- root[kMaxDelay] = Json::Value::Int64(max_delay.count());
+ if (max_delay.has_value()) {
+ root[kMaxDelay] = Json::Value::Int64(max_delay->count());
+ }
return root;
}
@@ -262,16 +269,25 @@ Json::Value Dimensions::ToJson() const {
// static
bool VideoConstraints::ParseAndValidate(const Json::Value& root,
VideoConstraints* out) {
- if (!json::ParseAndValidateDouble(root[kMaxPixelsPerSecond],
- &(out->max_pixels_per_second)) ||
- !Dimensions::ParseAndValidate(root[kMaxDimensions],
+ if (!Dimensions::ParseAndValidate(root[kMaxDimensions],
&(out->max_dimensions)) ||
!json::ParseAndValidateInt(root[kMaxBitRate], &(out->max_bit_rate)) ||
- !json::ParseAndValidateMilliseconds(root[kMaxDelay], &(out->max_delay)) ||
!ParseOptional<Dimensions>(root[kMinDimensions],
&(out->min_dimensions))) {
return false;
}
+
+ std::chrono::milliseconds max_delay;
+ if (json::ParseAndValidateMilliseconds(root[kMaxDelay], &max_delay)) {
+ out->max_delay = max_delay;
+ }
+
+ double max_pixels_per_second;
+ if (json::ParseAndValidateDouble(root[kMaxPixelsPerSecond],
+ &max_pixels_per_second)) {
+ out->max_pixels_per_second = max_pixels_per_second;
+ }
+
if (!json::ParseAndValidateInt(root[kMinBitRate], &(out->min_bit_rate))) {
out->min_bit_rate = kDefaultVideoMinBitRate;
}
@@ -280,7 +296,8 @@ bool VideoConstraints::ParseAndValidate(const Json::Value& root,
bool VideoConstraints::IsValid() const {
return max_pixels_per_second > 0 && min_bit_rate > 0 &&
- max_bit_rate > min_bit_rate && max_delay.count() > 0 &&
+ max_bit_rate > min_bit_rate &&
+ (!max_delay.has_value() || max_delay->count() > 0) &&
max_dimensions.IsValid() &&
(!min_dimensions.has_value() || min_dimensions->IsValid()) &&
max_dimensions.frame_rate.numerator > 0;
@@ -289,14 +306,20 @@ bool VideoConstraints::IsValid() const {
Json::Value VideoConstraints::ToJson() const {
OSP_DCHECK(IsValid());
Json::Value root;
- root[kMaxPixelsPerSecond] = max_pixels_per_second;
- if (min_dimensions.has_value()) {
- root[kMinDimensions] = min_dimensions->ToJson();
- }
root[kMaxDimensions] = max_dimensions.ToJson();
root[kMinBitRate] = min_bit_rate;
root[kMaxBitRate] = max_bit_rate;
- root[kMaxDelay] = Json::Value::Int64(max_delay.count());
+ if (max_pixels_per_second.has_value()) {
+ root[kMaxPixelsPerSecond] = max_pixels_per_second.value();
+ }
+
+ if (min_dimensions.has_value()) {
+ root[kMinDimensions] = min_dimensions->ToJson();
+ }
+
+ if (max_delay.has_value()) {
+ root[kMaxDelay] = Json::Value::Int64(max_delay->count());
+ }
return root;
}
@@ -346,9 +369,11 @@ bool DisplayDescription::IsValid() const {
if (aspect_ratio.has_value() && !aspect_ratio->IsValid()) {
return false;
}
+
if (dimensions.has_value() && !dimensions->IsValid()) {
return false;
}
+
// Sender behavior is undefined if the aspect ratio is fixed but no
// dimensions or aspect ratio are provided.
if (aspect_ratio_constraint.has_value() &&
diff --git a/chromium/third_party/openscreen/src/cast/streaming/answer_messages.h b/chromium/third_party/openscreen/src/cast/streaming/answer_messages.h
index 4298913b6dc..1f62706a1a8 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/answer_messages.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/answer_messages.h
@@ -41,10 +41,9 @@ struct AudioConstraints {
int max_sample_rate = 0;
int max_channels = 0;
- // Technically optional, sender will assume 32kbps if omitted.
- int min_bit_rate = 0;
+ int min_bit_rate = 0; // optional
int max_bit_rate = 0;
- std::chrono::milliseconds max_delay = {};
+ absl::optional<std::chrono::milliseconds> max_delay = {};
};
struct Dimensions {
@@ -62,13 +61,12 @@ struct VideoConstraints {
Json::Value ToJson() const;
bool IsValid() const;
- double max_pixels_per_second = {};
+ absl::optional<double> max_pixels_per_second = {};
absl::optional<Dimensions> min_dimensions = {};
Dimensions max_dimensions = {};
- // Technically optional, sender will assume 300kbps if omitted.
- int min_bit_rate = 0;
+ int min_bit_rate = 0; // optional
int max_bit_rate = 0;
- std::chrono::milliseconds max_delay = {};
+ absl::optional<std::chrono::milliseconds> max_delay = {};
};
struct Constraints {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.cc b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.cc
index 94ac47de66d..b30b5dc10d0 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.cc
@@ -83,7 +83,9 @@ void ApplyConstraints(const Constraints& constraints,
Recommendations* recommendations) {
// Audio has no fields in the display description, so we can safely
// ignore the current recommendations when setting values here.
- recommendations->audio.max_delay = constraints.audio.max_delay;
+ if (constraints.audio.max_delay.has_value()) {
+ recommendations->audio.max_delay = constraints.audio.max_delay.value();
+ }
recommendations->audio.max_channels = constraints.audio.max_channels;
recommendations->audio.max_sample_rate = constraints.audio.max_sample_rate;
@@ -93,9 +95,15 @@ void ApplyConstraints(const Constraints& constraints,
// With video, we take the intersection of values of the constraints and
// the display description.
- recommendations->video.max_delay = constraints.video.max_delay;
- recommendations->video.max_pixels_per_second =
- constraints.video.max_pixels_per_second;
+ if (constraints.video.max_delay.has_value()) {
+ recommendations->video.max_delay = constraints.video.max_delay.value();
+ }
+
+ if (constraints.video.max_pixels_per_second.has_value()) {
+ recommendations->video.max_pixels_per_second =
+ constraints.video.max_pixels_per_second.value();
+ }
+
recommendations->video.bit_rate_limits =
BitRateLimits{std::max(constraints.video.min_bit_rate,
recommendations->video.bit_rate_limits.minimum),
diff --git a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.h b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.h
index 94855c7c669..ccb2475b167 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations.h
@@ -29,7 +29,7 @@ namespace capture_recommendations {
// Default maximum delay for both audio and video. Used if the sender fails
// to provide any constraints.
-constexpr std::chrono::milliseconds kDefaultMaxDelayMs(4000);
+constexpr std::chrono::milliseconds kDefaultMaxDelayMs(400);
// Bit rate limits, used for both audio and video streams.
struct BitRateLimits {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations_unittest.cc
index 8e9765af99e..4f76b9d9ca6 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/capture_recommendations_unittest.cc
@@ -16,9 +16,9 @@ namespace capture_recommendations {
namespace {
constexpr Recommendations kDefaultRecommendations{
- Audio{BitRateLimits{32000, 256000}, milliseconds(4000), 2, 48000, 16000},
+ Audio{BitRateLimits{32000, 256000}, milliseconds(400), 2, 48000, 16000},
Video{BitRateLimits{300000, 1920 * 1080 * 30}, Resolution{320, 240, 30},
- Resolution{1920, 1080, 30}, false, milliseconds(4000),
+ Resolution{1920, 1080, 30}, false, milliseconds(400),
1920 * 1080 * 30 / 8}};
constexpr DisplayDescription kEmptyDescription{};
diff --git a/chromium/third_party/openscreen/src/cast/streaming/constants.h b/chromium/third_party/openscreen/src/cast/streaming/constants.h
index 1075a8171fb..ae1e8aa4658 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/constants.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/constants.h
@@ -67,10 +67,13 @@ constexpr int kDefaultAudioChannels = 2;
// Codecs known and understood by cast senders and receivers. Note: receivers
// are required to implement the following codecs to be Cast V2 compliant: H264,
-// VP8, AAC, Opus. Senders have to implement at least one codec for audio and
-// video to start a session.
-enum class AudioCodec { kAac, kOpus };
-enum class VideoCodec { kH264, kVp8, kHevc, kVp9 };
+// VP8, AAC, Opus. Senders have to implement at least one codec from this
+// list for audio or video to start a session.
+// |kNotSpecified| is used in remoting to indicate that the stream is being
+// remoted and is not specified as part of the OFFER message (indicated as
+// "REMOTE_AUDIO" or "REMOTE_VIDEO").
+enum class AudioCodec { kAac, kOpus, kNotSpecified };
+enum class VideoCodec { kH264, kVp8, kHevc, kVp9, kNotSpecified };
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc b/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc
index f199ab8d539..9eb40bf3746 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/message_fields.cc
@@ -14,14 +14,17 @@ namespace openscreen {
namespace cast {
namespace {
-constexpr EnumNameTable<AudioCodec, 2> kAudioCodecNames{
- {{"aac", AudioCodec::kAac}, {"opus", AudioCodec::kOpus}}};
+constexpr EnumNameTable<AudioCodec, 3> kAudioCodecNames{
+ {{"aac", AudioCodec::kAac},
+ {"opus", AudioCodec::kOpus},
+ {"REMOTE_AUDIO", AudioCodec::kNotSpecified}}};
-constexpr EnumNameTable<VideoCodec, 4> kVideoCodecNames{
+constexpr EnumNameTable<VideoCodec, 5> kVideoCodecNames{
{{"h264", VideoCodec::kH264},
{"vp8", VideoCodec::kVp8},
{"hevc", VideoCodec::kHevc},
- {"vp9", VideoCodec::kVp9}}};
+ {"vp9", VideoCodec::kVp9},
+ {"REMOTE_VIDEO", VideoCodec::kNotSpecified}}};
} // namespace
diff --git a/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc b/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
index dfc5a15ebb4..cea500cd8e7 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/offer_messages.cc
@@ -120,12 +120,10 @@ ErrorOr<Stream> ParseStream(const Json::Value& value, Stream::Type type) {
return ssrc.error();
}
auto aes_key = ParseAesHexBytes(value, "aesKey");
- if (!aes_key) {
- return aes_key.error();
- }
auto aes_iv_mask = ParseAesHexBytes(value, "aesIvMask");
- if (!aes_iv_mask) {
- return aes_iv_mask.error();
+ if (!aes_key || !aes_iv_mask) {
+ return Error(Error::Code::kUnencryptedOffer,
+ "Offer stream must have both a valid aesKey and aesIvMask");
}
auto rtp_timebase = ParseRtpTimebase(value, "timeBase");
if (!rtp_timebase) {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/offer_messages_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/offer_messages_unittest.cc
index 3976d46b3e9..a2117f671c9 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/offer_messages_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/offer_messages_unittest.cc
@@ -86,10 +86,16 @@ constexpr char kValidOffer[] = R"({
]
})";
-void ExpectFailureOnParse(absl::string_view body) {
+void ExpectFailureOnParse(
+ absl::string_view body,
+ absl::optional<Error::Code> expected = absl::nullopt) {
ErrorOr<Json::Value> root = json::Parse(body);
ASSERT_TRUE(root.is_value()) << root.error();
- EXPECT_TRUE(Offer::Parse(std::move(root.value())).is_error());
+ ErrorOr<Offer> error_or_offer = Offer::Parse(std::move(root.value()));
+ EXPECT_TRUE(error_or_offer.is_error());
+ if (expected) {
+ EXPECT_EQ(expected, error_or_offer.error().code());
+ }
}
void ExpectEqualsValidOffer(const Offer& offer) {
@@ -183,8 +189,8 @@ TEST(OfferTest, ErrorOnEmptyOffer) {
}
TEST(OfferTest, ErrorOnMissingMandatoryFields) {
- // It's okay if castMode is omitted, but if supportedStreams isanne //
- // omitted we should fail here.
+ // It's okay if castMode is omitted, but if supportedStreams is omitted we
+ // should fail here.
ExpectFailureOnParse(R"({
"castMode": "mirroring"
})");
@@ -493,5 +499,96 @@ TEST(OfferTest, ToJsonFailsWithInvalidStreams) {
EXPECT_TRUE(video_stream_invalid.ToJson().is_error());
}
+TEST(OfferTest, FailsIfUnencrypted) {
+ // Video stream missing AES fields.
+ ExpectFailureOnParse(R"({
+ "castMode": "mirroring",
+ "supportedStreams": [{
+ "index": 2,
+ "type": "video_source",
+ "codecName": "vp8",
+ "rtpProfile": "cast",
+ "rtpPayloadType": 100,
+ "ssrc": 19088743,
+ "timeBase": "1/48000",
+ "resolutions": [],
+ "maxBitRate": 10000,
+ "aesIvMask": "7f12a19be62a36c04ae4116caaeff6d1"
+ }]
+ })",
+ Error::Code::kUnencryptedOffer);
+
+ ExpectFailureOnParse(R"({
+ "castMode": "mirroring",
+ "supportedStreams": [{
+ "index": 2,
+ "type": "video_source",
+ "codecName": "vp8",
+ "rtpProfile": "cast",
+ "rtpPayloadType": 100,
+ "ssrc": 19088743,
+ "timeBase": "1/48000",
+ "resolutions": [],
+ "maxBitRate": 10000,
+ "aesKey": "51027e4e2347cbcb49d57ef10177aebc"
+ }]
+ })",
+ Error::Code::kUnencryptedOffer);
+
+ // Audio stream missing AES fields.
+ ExpectFailureOnParse(R"({
+ "castMode": "mirroring",
+ "supportedStreams": [{
+ "index": 2,
+ "type": "audio_source",
+ "codecName": "opus",
+ "rtpProfile": "cast",
+ "rtpPayloadType": 96,
+ "ssrc": 19088743,
+ "bitRate": 124000,
+ "timeBase": "1/48000",
+ "channels": 2,
+ "aesIvMask": "7f12a19be62a36c04ae4116caaeff6d1"
+ }]
+ })",
+ Error::Code::kUnencryptedOffer);
+
+ ExpectFailureOnParse(R"({
+ "castMode": "mirroring",
+ "supportedStreams": [{
+ "index": 2,
+ "type": "audio_source",
+ "codecName": "opus",
+ "rtpProfile": "cast",
+ "rtpPayloadType": 96,
+ "ssrc": 19088743,
+ "bitRate": 124000,
+ "timeBase": "1/48000",
+ "channels": 2,
+ "aesKey": "51027e4e2347cbcb49d57ef10177aebc"
+ }]
+ })",
+ Error::Code::kUnencryptedOffer);
+
+ // And finally, fields provided but not properly formatted.
+ ExpectFailureOnParse(R"({
+ "castMode": "mirroring",
+ "supportedStreams": [{
+ "index": 2,
+ "type": "audio_source",
+ "codecName": "opus",
+ "rtpProfile": "cast",
+ "rtpPayloadType": 96,
+ "ssrc": 19088743,
+ "bitRate": 124000,
+ "timeBase": "1/48000",
+ "channels": 2,
+ "aesKey": "51027e4e2347$bcb49d57ef10177aebc",
+ "aesIvMask": "7f12a19be62a36c04ae4116caaeff6d1"
+ }]
+ })",
+ Error::Code::kUnencryptedOffer);
+}
+
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver_message.cc b/chromium/third_party/openscreen/src/cast/streaming/receiver_message.cc
index e2739220184..1ce675b753c 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver_message.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver_message.cc
@@ -27,6 +27,18 @@ EnumNameTable<ReceiverMessage::Type, 5> kMessageTypeNames{
{"CAPABILITIES_RESPONSE", ReceiverMessage::Type::kCapabilitiesResponse},
{"RPC", ReceiverMessage::Type::kRpc}}};
+EnumNameTable<MediaCapability, 9> kMediaCapabilityNames{{
+ {"audio", MediaCapability::kAudio},
+ {"aac", MediaCapability::kAac},
+ {"opus", MediaCapability::kOpus},
+ {"video", MediaCapability::kVideo},
+ {"4k", MediaCapability::k4k},
+ {"h264", MediaCapability::kH264},
+ {"vp8", MediaCapability::kVp8},
+ {"vp9", MediaCapability::kVp9},
+ {"hevc", MediaCapability::kHevc},
+}};
+
ReceiverMessage::Type GetMessageType(const Json::Value& root) {
std::string type;
if (!json::ParseAndValidateString(root[kMessageType], &type)) {
@@ -39,6 +51,22 @@ ReceiverMessage::Type GetMessageType(const Json::Value& root) {
return parsed.value(ReceiverMessage::Type::kUnknown);
}
+bool ParseAndValidateCapability(const Json::Value& value,
+ MediaCapability* out) {
+ std::string c;
+ if (!json::ParseAndValidateString(value, &c)) {
+ return false;
+ }
+
+ const ErrorOr<MediaCapability> capability = GetEnum(kMediaCapabilityNames, c);
+ if (capability.is_error()) {
+ return false;
+ }
+
+ *out = capability.value();
+ return true;
+}
+
} // namespace
// static
@@ -77,14 +105,14 @@ ErrorOr<ReceiverCapability> ReceiverCapability::Parse(
remoting_version = ReceiverCapability::kRemotingVersionUnknown;
}
- std::vector<std::string> media_capabilities;
- if (!json::ParseAndValidateStringArray(value["mediaCaps"],
- &media_capabilities)) {
+ std::vector<MediaCapability> capabilities;
+ if (!json::ParseAndValidateArray<MediaCapability>(
+ value["mediaCaps"], ParseAndValidateCapability, &capabilities)) {
return Error(Error::Code::kJsonParseError,
"Failed to parse media capabilities");
}
- return ReceiverCapability{remoting_version, std::move(media_capabilities)};
+ return ReceiverCapability{remoting_version, std::move(capabilities)};
}
Json::Value ReceiverCapability::ToJson() const {
@@ -92,7 +120,7 @@ Json::Value ReceiverCapability::ToJson() const {
root["remoting"] = remoting_version;
Json::Value capabilities(Json::ValueType::arrayValue);
for (const auto& capability : media_capabilities) {
- capabilities.append(capability);
+ capabilities.append(GetEnumName(kMediaCapabilityNames, capability).value());
}
root["mediaCaps"] = std::move(capabilities);
return root;
@@ -181,9 +209,10 @@ ErrorOr<ReceiverMessage> ReceiverMessage::Parse(const Json::Value& value) {
} break;
case Type::kRpc: {
- std::string rpc;
- if (json::ParseAndValidateString(value[kRpcMessageBody], &rpc) &&
- base64::Decode(rpc, &rpc)) {
+ std::string encoded_rpc;
+ std::vector<uint8_t> rpc;
+ if (json::ParseAndValidateString(value[kRpcMessageBody], &encoded_rpc) &&
+ base64::Decode(encoded_rpc, &rpc)) {
message.body = std::move(rpc);
message.valid = true;
}
@@ -232,7 +261,8 @@ ErrorOr<Json::Value> ReceiverMessage::ToJson() const {
// NOTE: RPC messages do NOT have a result field.
case ReceiverMessage::Type::kRpc:
- root[kRpcMessageBody] = base64::Encode(absl::get<std::string>(body));
+ root[kRpcMessageBody] =
+ base64::Encode(absl::get<std::vector<uint8_t>>(body));
break;
default:
diff --git a/chromium/third_party/openscreen/src/cast/streaming/receiver_message.h b/chromium/third_party/openscreen/src/cast/streaming/receiver_message.h
index 59aa9750c49..b231149a745 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/receiver_message.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/receiver_message.h
@@ -29,6 +29,18 @@ struct ReceiverWifiStatus {
std::vector<int32_t> wifi_speed;
};
+enum class MediaCapability {
+ kAudio,
+ kAac,
+ kOpus,
+ kVideo,
+ k4k,
+ kH264,
+ kVp8,
+ kVp9,
+ kHevc
+};
+
struct ReceiverCapability {
static constexpr int kRemotingVersionUnknown = -1;
@@ -39,7 +51,7 @@ struct ReceiverCapability {
int remoting_version = kRemotingVersionUnknown;
// Set of capabilities (e.g., ac3, 4k, hevc, vp9, dolby_vision, etc.).
- std::vector<std::string> media_capabilities;
+ std::vector<MediaCapability> media_capabilities;
};
struct ReceiverError {
@@ -84,7 +96,7 @@ struct ReceiverMessage {
absl::variant<absl::monostate,
Answer,
- std::string,
+ std::vector<uint8_t>, // Binary-encoded RPC message.
ReceiverWifiStatus,
ReceiverCapability,
ReceiverError>
diff --git a/chromium/third_party/openscreen/src/cast/streaming/remoting.proto b/chromium/third_party/openscreen/src/cast/streaming/remoting.proto
index 0ce73012fba..bd00dd5ce6d 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/remoting.proto
+++ b/chromium/third_party/openscreen/src/cast/streaming/remoting.proto
@@ -238,10 +238,15 @@ message VideoDecoderConfig {
optional bytes extra_data = 9;
}
-message PipelineDecoderInfo {
+message AudioDecoderInfo {
reserved 3;
- reserved "has_decrypting_demuxer_stream";
- optional string decoder_name = 1;
+ optional int64 decoder_type = 1;
+ optional bool is_platform_decoder = 2;
+};
+
+message VideoDecoderInfo {
+ reserved 3;
+ optional int64 decoder_type = 1;
optional bool is_platform_decoder = 2;
};
@@ -253,8 +258,8 @@ message PipelineStatistics {
optional int64 audio_memory_usage = 5;
optional int64 video_memory_usage = 6;
optional int64 video_frame_duration_average_usec = 7;
- optional PipelineDecoderInfo audio_decoder_info = 8;
- optional PipelineDecoderInfo video_decoder_info = 9;
+ optional AudioDecoderInfo audio_decoder_info = 8;
+ optional VideoDecoderInfo video_decoder_info = 9;
};
message AcquireDemuxer {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/remoting_capabilities.h b/chromium/third_party/openscreen/src/cast/streaming/remoting_capabilities.h
new file mode 100644
index 00000000000..6957028ffc1
--- /dev/null
+++ b/chromium/third_party/openscreen/src/cast/streaming/remoting_capabilities.h
@@ -0,0 +1,60 @@
+// Copyright 2021 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 CAST_STREAMING_REMOTING_CAPABILITIES_H_
+#define CAST_STREAMING_REMOTING_CAPABILITIES_H_
+
+#include <string>
+#include <vector>
+
+namespace openscreen {
+namespace cast {
+
+// Audio capabilities are how receivers indicate support for remoting codecs--
+// as remoting does not include the actual codec in the OFFER message.
+enum class AudioCapability {
+ // The "baseline set" is used in Chrome to check support for a wide
+ // variety of audio codecs in media/remoting/renderer_controller.cc, including
+ // but not limited to MP3, PCM, Ogg Vorbis, and FLAC.
+ kBaselineSet,
+ kAac,
+ kOpus,
+};
+
+// Similar to audio capabilities, video capabilities are how the receiver
+// indicates support for certain video codecs, as well as support for streaming
+// 4k content. It is assumed by the sender that the receiver can support 4k
+// on all supported codecs.
+enum class VideoCapability {
+ // |kSupports4k| indicates that the receiver wants and can support 4k remoting
+ // content--both decoding/rendering and either a native 4k display or
+ // downscaling to the display's native resolution.
+ // TODO(issuetracker.google.com/184429130): |kSupports4k| is not super helpful
+ // for enabling 4k support, as receivers may not support 4k for all types of
+ // content.
+ kSupports4k,
+ kH264,
+ kVp8,
+ kVp9,
+ kHevc
+};
+
+// This class is similar to the RemotingSinkMetadata in Chrome, however
+// it is focused around our needs and is not mojom-based. This contains
+// a rough set of capabilities of the receiver to give the sender an idea of
+// what features are suppported for remoting.
+// TODO(issuetracker.google.com/184189100): this object should be expanded to
+// allow more specific constraint tracking.
+struct RemotingCapabilities {
+ // Receiver audio-specific capabilities.
+ std::vector<AudioCapability> audio;
+
+ // Receiver video-specific capabilities.
+ std::vector<VideoCapability> video;
+};
+
+} // namespace cast
+} // namespace openscreen
+
+#endif // CAST_STREAMING_REMOTING_CAPABILITIES_H_
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.cc b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.cc
index 6e79a4dd687..58379d79593 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.cc
@@ -4,6 +4,8 @@
#include "cast/streaming/rpc_broker.h"
+#include <memory>
+#include <string>
#include <utility>
#include "util/osp_logging.h"
@@ -35,6 +37,11 @@ std::ostream& operator<<(std::ostream& out, const RpcMessage& message) {
} // namespace
+constexpr RpcBroker::Handle RpcBroker::kInvalidHandle;
+constexpr RpcBroker::Handle RpcBroker::kAcquireRendererHandle;
+constexpr RpcBroker::Handle RpcBroker::kAcquireDemuxerHandle;
+constexpr RpcBroker::Handle RpcBroker::kFirstHandle;
+
RpcBroker::RpcBroker(SendMessageCallback send_message_cb)
: next_handle_(kFirstHandle),
send_message_cb_(std::move(send_message_cb)) {}
@@ -61,22 +68,29 @@ void RpcBroker::UnregisterMessageReceiverCallback(RpcBroker::Handle handle) {
receive_callbacks_.erase_key(handle);
}
-void RpcBroker::ProcessMessageFromRemote(const RpcMessage& message) {
- OSP_DVLOG << "received message: " << message;
- const auto entry = receive_callbacks_.find(message.handle());
+void RpcBroker::ProcessMessageFromRemote(const uint8_t* message,
+ std::size_t message_len) {
+ auto rpc = std::make_unique<RpcMessage>();
+ if (!rpc->ParseFromArray(message, message_len)) {
+ OSP_LOG_WARN << "Failed to parse RPC message from remote: " << message;
+ return;
+ }
+ OSP_DVLOG << "Received RPC message: " << *rpc;
+
+ const auto entry = receive_callbacks_.find(rpc->handle());
if (entry == receive_callbacks_.end()) {
- OSP_DVLOG << "unregistered handle: " << message.handle();
+ OSP_DVLOG << "Dropping message due to unregistered handle: "
+ << rpc->handle();
return;
}
- entry->second(message);
+ entry->second(std::move(rpc));
}
-void RpcBroker::SendMessageToRemote(const RpcMessage& message) {
- OSP_DVLOG << "sending message message: " << message;
- std::vector<uint8_t> serialized_message(message.ByteSizeLong());
- OSP_CHECK(message.SerializeToArray(serialized_message.data(),
- serialized_message.size()));
- send_message_cb_(std::move(serialized_message));
+void RpcBroker::SendMessageToRemote(const RpcMessage& rpc) {
+ OSP_DVLOG << "Sending RPC message: " << rpc;
+ std::vector<uint8_t> message(rpc.ByteSizeLong());
+ rpc.SerializeToArray(message.data(), message.size());
+ send_message_cb_(std::move(message));
}
bool RpcBroker::IsRegisteredForTesting(RpcBroker::Handle handle) {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.h b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.h
index 596aba1387f..5865a86bf3a 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker.h
@@ -5,6 +5,9 @@
#ifndef CAST_STREAMING_RPC_BROKER_H_
#define CAST_STREAMING_RPC_BROKER_H_
+#include <memory>
+#include <string>
+#include <utility>
#include <vector>
#include "cast/streaming/remoting.pb.h"
@@ -28,7 +31,8 @@ namespace cast {
class RpcBroker {
public:
using Handle = int;
- using ReceiveMessageCallback = std::function<void(const RpcMessage&)>;
+ using ReceiveMessageCallback =
+ std::function<void(std::unique_ptr<RpcMessage>)>;
using SendMessageCallback = std::function<void(std::vector<uint8_t>)>;
explicit RpcBroker(SendMessageCallback send_message_cb);
@@ -53,14 +57,23 @@ class RpcBroker {
void UnregisterMessageReceiverCallback(Handle handle);
// Distributes an incoming RPC message to the registered (if any) component.
- void ProcessMessageFromRemote(const RpcMessage& message);
+ // The |serialized_message| should be already base64-decoded and ready for
+ // deserialization by protobuf.
+ void ProcessMessageFromRemote(const uint8_t* message,
+ std::size_t message_len);
- // Executes the |send_message_cb_| using |message|.
- void SendMessageToRemote(const RpcMessage& message);
+ // Executes the |send_message_cb_| using |rpc|.
+ void SendMessageToRemote(const RpcMessage& rpc);
// Checks if the handle is registered for receiving messages. Test-only.
bool IsRegisteredForTesting(Handle handle);
+ // Consumers of RPCBroker may set the send message callback post-hoc
+ // in order to simulate different scenarios.
+ void set_send_message_cb_for_testing(SendMessageCallback cb) {
+ send_message_cb_ = std::move(cb);
+ }
+
// Predefined invalid handle value for RPC message.
static constexpr Handle kInvalidHandle = -1;
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker_unittest.cc
index 5dacfbb2964..3f13f9eab51 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rpc_broker_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/rpc_broker_unittest.cc
@@ -5,6 +5,8 @@
#include "cast/streaming/rpc_broker.h"
#include <memory>
+#include <string>
+#include <utility>
#include <vector>
#include "cast/streaming/remoting.pb.h"
@@ -17,13 +19,12 @@ using testing::Return;
namespace openscreen {
namespace cast {
-
namespace {
class FakeMessager {
public:
- void OnReceivedRpc(const RpcMessage& message) {
- received_rpc_ = message;
+ void OnReceivedRpc(std::unique_ptr<RpcMessage> message) {
+ received_rpc_ = std::move(message);
received_count_++;
}
@@ -33,7 +34,7 @@ class FakeMessager {
}
int received_count() const { return received_count_; }
- const RpcMessage& received_rpc() const { return received_rpc_; }
+ const RpcMessage& received_rpc() const { return *received_rpc_; }
int sent_count() const { return sent_count_; }
const RpcMessage& sent_rpc() const { return sent_rpc_; }
@@ -42,7 +43,7 @@ class FakeMessager {
RpcBroker::Handle handle() { return handle_; }
private:
- RpcMessage received_rpc_;
+ std::unique_ptr<RpcMessage> received_rpc_;
int received_count_ = 0;
RpcMessage sent_rpc_;
@@ -67,11 +68,18 @@ class RpcBrokerTest : public testing::Test {
const auto handle = rpc_broker_->GetUniqueHandle();
fake_messager_->set_handle(handle);
rpc_broker_->RegisterMessageReceiverCallback(
- handle, [p = fake_messager_.get()](const RpcMessage& message) {
- p->OnReceivedRpc(message);
+ handle,
+ [p = fake_messager_.get()](std::unique_ptr<RpcMessage> message) {
+ p->OnReceivedRpc(std::move(message));
});
}
+ void ProcessMessage(const RpcMessage& rpc) {
+ std::vector<uint8_t> message(rpc.ByteSizeLong());
+ rpc.SerializeToArray(message.data(), message.size());
+ rpc_broker_->ProcessMessageFromRemote(message.data(), message.size());
+ }
+
std::unique_ptr<FakeMessager> fake_messager_;
std::unique_ptr<RpcBroker> rpc_broker_;
};
@@ -79,14 +87,14 @@ class RpcBrokerTest : public testing::Test {
TEST_F(RpcBrokerTest, TestProcessMessageFromRemoteRegistered) {
RpcMessage rpc;
rpc.set_handle(fake_messager_->handle());
- rpc_broker_->ProcessMessageFromRemote(rpc);
+ ProcessMessage(rpc);
ASSERT_EQ(1, fake_messager_->received_count());
}
TEST_F(RpcBrokerTest, TestProcessMessageFromRemoteUnregistered) {
RpcMessage rpc;
rpc_broker_->UnregisterMessageReceiverCallback(fake_messager_->handle());
- rpc_broker_->ProcessMessageFromRemote(rpc);
+ ProcessMessage(rpc);
ASSERT_EQ(0, fake_messager_->received_count());
}
@@ -119,7 +127,7 @@ TEST_F(RpcBrokerTest, ProcessMessageWithRegisteredHandle) {
sent_rpc.set_handle(fake_messager_->handle());
sent_rpc.set_proc(RpcMessage::RPC_R_SETVOLUME);
sent_rpc.set_double_value(3.4);
- rpc_broker_->ProcessMessageFromRemote(sent_rpc);
+ ProcessMessage(sent_rpc);
// Checks if received message is identical to the one sent earlier.
ASSERT_EQ(1, fake_messager_->received_count());
@@ -136,7 +144,7 @@ TEST_F(RpcBrokerTest, ProcessMessageWithUnregisteredHandle) {
sent_rpc.set_handle(different_handle);
sent_rpc.set_proc(RpcMessage::RPC_R_SETVOLUME);
sent_rpc.set_double_value(4.5);
- rpc_broker_->ProcessMessageFromRemote(sent_rpc);
+ ProcessMessage(sent_rpc);
// We shouldn't have gotten the message since the handle is different.
ASSERT_EQ(0, fake_messager_->received_count());
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
index d64773d5c34..e07b590f6d0 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.cc
@@ -4,15 +4,53 @@
#include "cast/streaming/rtp_defines.h"
+#include "util/osp_logging.h"
+
namespace openscreen {
namespace cast {
-RtpPayloadType GetPayloadType(AudioCodec codec) {
- return RtpPayloadType::kAudioHackForAndroidTV;
+RtpPayloadType GetPayloadType(AudioCodec codec, bool use_android_rtp_hack) {
+ if (use_android_rtp_hack) {
+ return codec == AudioCodec::kNotSpecified
+ ? RtpPayloadType::kAudioVarious
+ : RtpPayloadType::kAudioHackForAndroidTV;
+ }
+
+ switch (codec) {
+ case AudioCodec::kAac:
+ return RtpPayloadType::kAudioAac;
+ case AudioCodec::kOpus:
+ return RtpPayloadType::kAudioOpus;
+ case AudioCodec::kNotSpecified:
+ return RtpPayloadType::kAudioVarious;
+ default:
+ OSP_NOTREACHED();
+ }
}
-RtpPayloadType GetPayloadType(VideoCodec codec) {
- return RtpPayloadType::kVideoHackForAndroidTV;
+RtpPayloadType GetPayloadType(VideoCodec codec, bool use_android_rtp_hack) {
+ if (use_android_rtp_hack) {
+ return codec == VideoCodec::kNotSpecified
+ ? RtpPayloadType::kVideoVarious
+ : RtpPayloadType::kVideoHackForAndroidTV;
+ }
+ switch (codec) {
+ // VP8 and VP9 share the same payload type.
+ case VideoCodec::kVp9:
+ case VideoCodec::kVp8:
+ return RtpPayloadType::kVideoVp8;
+
+ // H264 and HEVC/H265 share the same payload type.
+ case VideoCodec::kHevc: // fallthrough
+ case VideoCodec::kH264:
+ return RtpPayloadType::kVideoH264;
+
+ case VideoCodec::kNotSpecified:
+ return RtpPayloadType::kVideoVarious;
+
+ default:
+ OSP_NOTREACHED();
+ }
}
bool IsRtpPayloadType(uint8_t raw_byte) {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
index 82c91c31a7d..1f9cc43fdce 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/rtp_defines.h
@@ -98,20 +98,17 @@ enum class RtpPayloadType : uint8_t {
// video to be 96; regardless of the codecs actually being used. This is
// definitely out-of-spec, and inconsistent with the audio versus video range
// of values, but must be taken into account for backwards-compatibility.
- // TODO(crbug.com/1127978): RTP payload types need to represent actual type,
- // as well as have options for new codecs like VP9.
kAudioHackForAndroidTV = 127,
kVideoHackForAndroidTV = 96,
};
-// NOTE: currently we match the legacy Chrome sender's behavior of always
-// sending the audio and video hacks for AndroidTV, however we should migrate
-// to using proper rtp payload types. New payload types for new codecs, such
-// as VP9, should also be defined.
-// TODO(crbug.com/1127978): RTP payload types need to represent actual type,
-// as well as have options for new codecs like VP9.
-RtpPayloadType GetPayloadType(AudioCodec codec);
-RtpPayloadType GetPayloadType(VideoCodec codec);
+// Setting |use_android_rtp_hack| to true means that we match the legacy Chrome
+// sender's behavior of always sending the audio and video hacks for AndroidTV,
+// as some legacy android receivers require these.
+// TODO(issuetracker.google.com/184438154): we need to figure out what receivers
+// need this still, if any. The hack should be removed when possible.
+RtpPayloadType GetPayloadType(AudioCodec codec, bool use_android_rtp_hack);
+RtpPayloadType GetPayloadType(VideoCodec codec, bool use_android_rtp_hack);
// Returns true if the |raw_byte| can be type-casted to a RtpPayloadType, and is
// also not RtpPayloadType::kNull. The caller should mask the byte, to select
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_message.cc b/chromium/third_party/openscreen/src/cast/streaming/sender_message.cc
index 9c2b538875f..2983aa2f480 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_message.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_message.cc
@@ -59,9 +59,10 @@ ErrorOr<SenderMessage> SenderMessage::Parse(const Json::Value& value) {
}
} else if (message.type == SenderMessage::Type::kRpc) {
std::string rpc_body;
+ std::vector<uint8_t> rpc;
if (json::ParseAndValidateString(value[kRpcMessageBody], &rpc_body) &&
- base64::Decode(rpc_body, &rpc_body)) {
- message.body = rpc_body;
+ base64::Decode(rpc_body, &rpc)) {
+ message.body = rpc;
message.valid = true;
}
} else if (message.type == SenderMessage::Type::kGetStatus ||
@@ -90,7 +91,8 @@ ErrorOr<Json::Value> SenderMessage::ToJson() const {
break;
case SenderMessage::Type::kRpc:
- root[kRpcMessageBody] = base64::Encode(absl::get<std::string>(body));
+ root[kRpcMessageBody] =
+ base64::Encode(absl::get<std::vector<uint8_t>>(body));
break;
case SenderMessage::Type::kGetCapabilities: // fallthrough
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_message.h b/chromium/third_party/openscreen/src/cast/streaming/sender_message.h
index c016b31c515..2c45032c66d 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_message.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_message.h
@@ -44,7 +44,11 @@ struct SenderMessage {
Type type = Type::kUnknown;
int32_t sequence_number = -1;
bool valid = false;
- absl::variant<absl::monostate, Offer, std::string> body;
+ absl::variant<absl::monostate,
+ std::vector<uint8_t>, // Binary-encoded RPC message.
+ Offer,
+ std::string>
+ body;
};
} // namespace cast
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_packet_router.h b/chromium/third_party/openscreen/src/cast/streaming/sender_packet_router.h
index a6c161a91f8..c86cb2a5e6e 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_packet_router.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_packet_router.h
@@ -146,7 +146,7 @@ class SenderPacketRouter : public BandwidthEstimator,
// a burst-send.
void ScheduleNextBurst();
- // Performs a burst-send of packets. This is called whevener the Alarm fires.
+ // Performs a burst-send of packets. This is called whenever the Alarm fires.
void SendBurstOfPackets();
// Send an RTCP packet from each Sender that has one ready, and return the
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc b/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc
index 7a54c7e1ffd..47782412a55 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session.cc
@@ -24,18 +24,23 @@
#include "util/json/json_helpers.h"
#include "util/json/json_serialization.h"
#include "util/osp_logging.h"
+#include "util/stringprintf.h"
namespace openscreen {
namespace cast {
namespace {
-AudioStream CreateStream(int index, const AudioCaptureConfig& config) {
+constexpr int kSupportedRemotingVersion = 3;
+
+AudioStream CreateStream(int index,
+ const AudioCaptureConfig& config,
+ bool use_android_rtp_hack) {
return AudioStream{
Stream{index,
Stream::Type::kAudioSource,
config.channels,
- GetPayloadType(config.codec),
+ GetPayloadType(config.codec, use_android_rtp_hack),
GenerateSsrc(true /*high_priority*/),
config.target_playout_delay,
GenerateRandomBytes16(),
@@ -53,7 +58,9 @@ Resolution ToResolution(const DisplayResolution& display_resolution) {
return Resolution{display_resolution.width, display_resolution.height};
}
-VideoStream CreateStream(int index, const VideoCaptureConfig& config) {
+VideoStream CreateStream(int index,
+ const VideoCaptureConfig& config,
+ bool use_android_rtp_hack) {
std::vector<Resolution> resolutions;
std::transform(config.resolutions.begin(), config.resolutions.end(),
std::back_inserter(resolutions), ToResolution);
@@ -63,7 +70,7 @@ VideoStream CreateStream(int index, const VideoCaptureConfig& config) {
Stream{index,
Stream::Type::kVideoSource,
kVideoStreamChannelCount,
- GetPayloadType(config.codec),
+ GetPayloadType(config.codec, use_android_rtp_hack),
GenerateSsrc(false /*high_priority*/),
config.target_playout_delay,
GenerateRandomBytes16(),
@@ -89,21 +96,50 @@ VideoStream CreateStream(int index, const VideoCaptureConfig& config) {
template <typename S, typename C>
void CreateStreamList(int offset_index,
const std::vector<C>& configs,
+ bool use_android_rtp_hack,
std::vector<S>* out) {
out->reserve(configs.size());
for (size_t i = 0; i < configs.size(); ++i) {
- out->emplace_back(CreateStream(i + offset_index, configs[i]));
+ out->emplace_back(
+ CreateStream(i + offset_index, configs[i], use_android_rtp_hack));
}
}
-Offer CreateOffer(const std::vector<AudioCaptureConfig>& audio_configs,
- const std::vector<VideoCaptureConfig>& video_configs) {
+Offer CreateMirroringOffer(const std::vector<AudioCaptureConfig>& audio_configs,
+ const std::vector<VideoCaptureConfig>& video_configs,
+ bool use_android_rtp_hack) {
Offer offer;
+ offer.cast_mode = CastMode::kMirroring;
// NOTE here: IDs will always follow the pattern:
// [0.. audio streams... N - 1][N.. video streams.. K]
- CreateStreamList(0, audio_configs, &offer.audio_streams);
- CreateStreamList(audio_configs.size(), video_configs, &offer.video_streams);
+ CreateStreamList(0, audio_configs, use_android_rtp_hack,
+ &offer.audio_streams);
+ CreateStreamList(audio_configs.size(), video_configs, use_android_rtp_hack,
+ &offer.video_streams);
+
+ return offer;
+}
+
+Offer CreateRemotingOffer(const AudioCaptureConfig& audio_config,
+ const VideoCaptureConfig& video_config,
+ bool use_android_rtp_hack) {
+ Offer offer;
+ offer.cast_mode = CastMode::kRemoting;
+
+ AudioStream audio_stream =
+ CreateStream(0, audio_config, use_android_rtp_hack);
+ audio_stream.codec = AudioCodec::kNotSpecified;
+ audio_stream.stream.rtp_payload_type =
+ GetPayloadType(AudioCodec::kNotSpecified, use_android_rtp_hack);
+ offer.audio_streams.push_back(std::move(audio_stream));
+
+ VideoStream video_stream =
+ CreateStream(1, video_config, use_android_rtp_hack);
+ video_stream.codec = VideoCodec::kNotSpecified;
+ video_stream.stream.rtp_payload_type =
+ GetPayloadType(VideoCodec::kNotSpecified, use_android_rtp_hack);
+ offer.video_streams.push_back(std::move(video_stream));
return offer;
}
@@ -136,31 +172,71 @@ bool AreAllValid(const std::vector<AudioCaptureConfig>& audio_configs,
IsValidVideoCaptureConfig);
}
+RemotingCapabilities ToCapabilities(const ReceiverCapability& capability) {
+ RemotingCapabilities out;
+ for (MediaCapability c : capability.media_capabilities) {
+ switch (c) {
+ case MediaCapability::kAudio:
+ out.audio.push_back(AudioCapability::kBaselineSet);
+ break;
+ case MediaCapability::kAac:
+ out.audio.push_back(AudioCapability::kAac);
+ break;
+ case MediaCapability::kOpus:
+ out.audio.push_back(AudioCapability::kOpus);
+ break;
+ case MediaCapability::k4k:
+ out.video.push_back(VideoCapability::kSupports4k);
+ break;
+ case MediaCapability::kH264:
+ out.video.push_back(VideoCapability::kH264);
+ break;
+ case MediaCapability::kVp8:
+ out.video.push_back(VideoCapability::kVp8);
+ break;
+ case MediaCapability::kVp9:
+ out.video.push_back(VideoCapability::kVp9);
+ break;
+ case MediaCapability::kHevc:
+ out.video.push_back(VideoCapability::kHevc);
+ break;
+ case MediaCapability::kVideo:
+ // noop, as "video" is ignored by Chrome remoting.
+ break;
+
+ default:
+ OSP_NOTREACHED();
+ }
+ }
+ return out;
+}
+
} // namespace
SenderSession::Client::~Client() = default;
-SenderSession::SenderSession(IPAddress remote_address,
- Client* const client,
- Environment* environment,
- MessagePort* message_port,
- std::string message_source_id,
- std::string message_destination_id)
- : remote_address_(remote_address),
- client_(client),
- environment_(environment),
+SenderSession::SenderSession(Configuration config)
+ : config_(config),
messager_(
- message_port,
- std::move(message_source_id),
- std::move(message_destination_id),
+ config_.message_port,
+ config_.message_source_id,
+ config_.message_destination_id,
[this](Error error) {
OSP_DLOG_WARN << "SenderSession message port error: " << error;
- client_->OnError(this, error);
+ config_.client->OnError(this, error);
},
- environment->task_runner()),
- packet_router_(environment_) {
- OSP_DCHECK(client_);
- OSP_DCHECK(environment_);
+ config_.environment->task_runner()),
+ packet_router_(config_.environment) {
+ OSP_DCHECK(config_.client);
+ OSP_DCHECK(config_.environment);
+
+ // We may or may not do remoting this session, however our RPC handler
+ // is not negotiation-specific and registering on construction here allows us
+ // to record any unexpected RPC messages.
+ messager_.SetHandler(ReceiverMessage::Type::kRpc,
+ [this](ReceiverMessage message) {
+ this->OnRpcMessage(std::move(message));
+ });
}
SenderSession::~SenderSession() = default;
@@ -176,9 +252,45 @@ Error SenderSession::Negotiate(std::vector<AudioCaptureConfig> audio_configs,
return Error(Error::Code::kParameterInvalid, "Invalid configs provided.");
}
- Offer offer = CreateOffer(audio_configs, video_configs);
- current_negotiation_ = std::unique_ptr<Negotiation>(new Negotiation{
- offer, std::move(audio_configs), std::move(video_configs)});
+ Offer offer = CreateMirroringOffer(audio_configs, video_configs,
+ config_.use_android_rtp_hack);
+ return StartNegotiation(std::move(audio_configs), std::move(video_configs),
+ std::move(offer));
+}
+
+Error SenderSession::NegotiateRemoting(AudioCaptureConfig audio_config,
+ VideoCaptureConfig video_config) {
+ // Remoting requires both an audio and a video configuration.
+ if (!IsValidAudioCaptureConfig(audio_config) ||
+ !IsValidVideoCaptureConfig(video_config)) {
+ return Error(Error::Code::kParameterInvalid,
+ "Passed invalid audio or video config.");
+ }
+
+ Offer offer = CreateRemotingOffer(audio_config, video_config,
+ config_.use_android_rtp_hack);
+ return StartNegotiation({audio_config}, {video_config}, std::move(offer));
+}
+
+int SenderSession::GetEstimatedNetworkBandwidth() const {
+ return packet_router_.ComputeNetworkBandwidth();
+}
+
+void SenderSession::ResetState() {
+ state_ = State::kIdle;
+ current_negotiation_.reset();
+ current_audio_sender_.reset();
+ current_video_sender_.reset();
+ broker_.reset();
+}
+
+Error SenderSession::StartNegotiation(
+ std::vector<AudioCaptureConfig> audio_configs,
+ std::vector<VideoCaptureConfig> video_configs,
+ Offer offer) {
+ current_negotiation_ =
+ std::unique_ptr<InProcessNegotiation>(new InProcessNegotiation{
+ offer, std::move(audio_configs), std::move(video_configs)});
return messager_.SendRequest(
SenderMessage{SenderMessage::Type::kOffer, ++current_sequence_number_,
@@ -188,28 +300,128 @@ Error SenderSession::Negotiate(std::vector<AudioCaptureConfig> audio_configs,
}
void SenderSession::OnAnswer(ReceiverMessage message) {
- OSP_LOG_WARN << "Message sn: " << message.sequence_number
- << ", current: " << current_sequence_number_;
if (!message.valid) {
- if (absl::holds_alternative<ReceiverError>(message.body)) {
- client_->OnError(
- this, Error(Error::Code::kParameterInvalid,
- absl::get<ReceiverError>(message.body).description));
- } else {
- client_->OnError(this, Error(Error::Code::kJsonParseError,
- "Received invalid answer message"));
- }
+ HandleErrorMessage(message, "Invalid answer response message");
return;
}
+ // There isn't an obvious way to tell from the Answer whether it is mirroring
+ // or remoting specific--the only clues are in the original offer message.
const Answer& answer = absl::get<Answer>(message.body);
- ConfiguredSenders senders = SpawnSenders(answer);
+ if (current_negotiation_->offer.cast_mode == CastMode::kMirroring) {
+ ConfiguredSenders senders = SpawnSenders(answer);
+ // If we didn't select any senders, the negotiation was unsuccessful.
+ if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
+ return;
+ }
+
+ state_ = State::kMirroring;
+ config_.client->OnNegotiated(
+ this, std::move(senders),
+ capture_recommendations::GetRecommendations(answer));
+ } else {
+ state_ = State::kRemoting;
+
+ // We don't want to spawn senders yet, since we don't know what the
+ // receiver's capabilities are. So, we cache the Answer until the
+ // capabilites request is completed.
+ current_negotiation_->answer = answer;
+ const Error result = messager_.SendRequest(
+ SenderMessage{SenderMessage::Type::kGetCapabilities,
+ ++current_sequence_number_, true},
+ ReceiverMessage::Type::kCapabilitiesResponse,
+ [this](ReceiverMessage message) { OnCapabilitiesResponse(message); });
+ if (!result.ok()) {
+ config_.client->OnError(
+ this, Error(Error::Code::kNegotiationFailure,
+ "Failed to set a GET_CAPABILITIES request"));
+ }
+ }
+}
+
+void SenderSession::OnCapabilitiesResponse(ReceiverMessage message) {
+ if (!current_negotiation_ || !current_negotiation_->answer.IsValid()) {
+ OSP_LOG_INFO
+ << "Received a capabilities response, but not negotiating anything.";
+ return;
+ }
+
+ if (!message.valid) {
+ HandleErrorMessage(
+ message,
+ "Bad CAPABILITIES_RESPONSE, assuming remoting is not supported");
+ return;
+ }
+
+ const ReceiverCapability& caps = absl::get<ReceiverCapability>(message.body);
+ int remoting_version = caps.remoting_version;
+ // If not set, we assume it is version 1.
+ if (remoting_version == ReceiverCapability::kRemotingVersionUnknown) {
+ remoting_version = 1;
+ }
+
+ if (remoting_version > kSupportedRemotingVersion) {
+ std::string message = StringPrintf(
+ "Receiver is using too new of a version for remoting (%d > %d)",
+ remoting_version, kSupportedRemotingVersion);
+ config_.client->OnError(
+ this, Error(Error::Code::kRemotingNotSupported, std::move(message)));
+ return;
+ }
+
+ ConfiguredSenders senders = SpawnSenders(current_negotiation_->answer);
// If we didn't select any senders, the negotiation was unsuccessful.
if (senders.audio_sender == nullptr && senders.video_sender == nullptr) {
+ config_.client->OnError(this,
+ Error(Error::Code::kNegotiationFailure,
+ "Failed to negotiate a remoting session."));
return;
}
- client_->OnNegotiated(this, std::move(senders),
- capture_recommendations::GetRecommendations(answer));
+ broker_ = std::make_unique<RpcBroker>([this](std::vector<uint8_t> message) {
+ Error error = this->messager_.SendOutboundMessage(SenderMessage{
+ SenderMessage::Type::kRpc, ++(this->current_sequence_number_), true,
+ std::move(message)});
+
+ if (!error.ok()) {
+ OSP_LOG_WARN << "Failed to send RPC message: " << error;
+ }
+ });
+
+ config_.client->OnRemotingNegotiated(
+ this, RemotingNegotiation{std::move(senders), ToCapabilities(caps),
+ broker_.get()});
+}
+
+void SenderSession::OnRpcMessage(ReceiverMessage message) {
+ if (!broker_) {
+ OSP_LOG_INFO << "Received an RPC message without having an RPCBroker.";
+ return;
+ }
+
+ if (!message.valid) {
+ HandleErrorMessage(
+ message,
+ "Bad RPC message. This may or may not represent a serious problem");
+ return;
+ }
+
+ const auto& body = absl::get<std::vector<uint8_t>>(message.body);
+ broker_->ProcessMessageFromRemote(body.data(), body.size());
+}
+
+void SenderSession::HandleErrorMessage(ReceiverMessage message,
+ const std::string& text) {
+ OSP_DCHECK(!message.valid);
+ if (absl::holds_alternative<ReceiverError>(message.body)) {
+ const ReceiverError& error = absl::get<ReceiverError>(message.body);
+ std::string error_text =
+ StringPrintf("%s. Error code: %d, description: %s", text.c_str(),
+ error.code, error.description.c_str());
+ config_.client->OnError(
+ this, Error(Error::Code::kParameterInvalid, std::move(error_text)));
+ } else {
+ config_.client->OnError(this, Error(Error::Code::kJsonParseError, text));
+ }
}
std::unique_ptr<Sender> SenderSession::CreateSender(Ssrc receiver_ssrc,
@@ -225,7 +437,7 @@ std::unique_ptr<Sender> SenderSession::CreateSender(Ssrc receiver_ssrc,
stream.aes_iv_mask,
/* is_pli_enabled*/ true};
- return std::make_unique<Sender>(environment_, &packet_router_,
+ return std::make_unique<Sender>(config_.environment, &packet_router_,
std::move(config), type);
}
@@ -235,7 +447,8 @@ void SenderSession::SpawnAudioSender(ConfiguredSenders* senders,
int config_index) {
const AudioCaptureConfig& config =
current_negotiation_->audio_configs[config_index];
- const RtpPayloadType payload_type = GetPayloadType(config.codec);
+ const RtpPayloadType payload_type =
+ GetPayloadType(config.codec, config_.use_android_rtp_hack);
for (const AudioStream& stream : current_negotiation_->offer.audio_streams) {
if (stream.stream.index == send_index) {
current_audio_sender_ =
@@ -253,7 +466,8 @@ void SenderSession::SpawnVideoSender(ConfiguredSenders* senders,
int config_index) {
const VideoCaptureConfig& config =
current_negotiation_->video_configs[config_index];
- const RtpPayloadType payload_type = GetPayloadType(config.codec);
+ const RtpPayloadType payload_type =
+ GetPayloadType(config.codec, config_.use_android_rtp_hack);
for (const VideoStream& stream : current_negotiation_->offer.video_streams) {
if (stream.stream.index == send_index) {
current_video_sender_ =
@@ -272,8 +486,10 @@ SenderSession::ConfiguredSenders SenderSession::SpawnSenders(
// Although we already have a message port set up with the TLS
// address of the receiver, we don't know where to send the separate UDP
// stream until we get the ANSWER message here.
- environment_->set_remote_endpoint(
- IPEndpoint{remote_address_, static_cast<uint16_t>(answer.udp_port)});
+ config_.environment->set_remote_endpoint(IPEndpoint{
+ config_.remote_address, static_cast<uint16_t>(answer.udp_port)});
+ OSP_LOG_INFO << "Streaming to " << config_.environment->remote_endpoint()
+ << "...";
ConfiguredSenders senders;
for (size_t i = 0; i < answer.send_indexes.size(); ++i) {
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session.h b/chromium/third_party/openscreen/src/cast/streaming/sender_session.h
index 86ab4d5a649..5865668a31d 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_session.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session.h
@@ -13,7 +13,10 @@
#include "cast/common/public/message_port.h"
#include "cast/streaming/answer_messages.h"
#include "cast/streaming/capture_configs.h"
+#include "cast/streaming/capture_recommendations.h"
#include "cast/streaming/offer_messages.h"
+#include "cast/streaming/remoting_capabilities.h"
+#include "cast/streaming/rpc_broker.h"
#include "cast/streaming/sender.h"
#include "cast/streaming/sender_packet_router.h"
#include "cast/streaming/session_config.h"
@@ -24,10 +27,6 @@
namespace openscreen {
namespace cast {
-namespace capture_recommendations {
-struct Recommendations;
-}
-
class Environment;
class Sender;
@@ -49,8 +48,28 @@ class SenderSession final {
VideoCaptureConfig video_config;
};
- // The embedder should provide a client for handling the negotiation.
- // When the negotiation is complete, the OnNegotiated callback is called.
+ // This struct contains all of the information necessary to begin remoting
+ // after we receive the capabilities from the receiver.
+ // TODO(issuetracker.google.com/184189241): capture recommendations should be
+ // exposed as part of the remoting negotiation.
+ struct RemotingNegotiation {
+ ConfiguredSenders senders;
+
+ // The capabilities reported by the connected receiver. NOTE: SenderSession
+ // reports the capabilities as-is from the Receiver, so clients concerned
+ // about legacy devices, such as pre-1.27 Earth receivers should do
+ // a version check when using these capabilities to offer remoting.
+ RemotingCapabilities capabilities;
+
+ // The RPC broker to be used for subscribing to remoting proto messages.
+ RpcBroker* broker;
+ };
+
+ // The embedder should provide a client for handling negotiation events.
+ // The client is required to implement a mirorring handler, and may choose
+ // to provide a remoting negotiation if it supports remoting.
+ // When the negotiation is complete, the appropriate |On*Negotiated| handler
+ // is called.
class Client {
public:
// Called when a new set of senders has been negotiated. This may be
@@ -63,6 +82,12 @@ class SenderSession final {
ConfiguredSenders senders,
capture_recommendations::Recommendations capture_recommendations) = 0;
+ // Called when a new set of remoting senders has been negotiated. Since
+ // remoting is an optional feature, the default behavior here is to leave
+ // this method unhandled.
+ virtual void OnRemotingNegotiated(const SenderSession* session,
+ RemotingNegotiation negotiation) {}
+
// Called whenever an error occurs. Ends the ongoing session, and the caller
// must call Negotiate() again if they wish to re-establish streaming.
virtual void OnError(const SenderSession* session, Error error) = 0;
@@ -71,6 +96,35 @@ class SenderSession final {
virtual ~Client();
};
+ // The configuration information required to set up the session.
+ struct Configuration {
+ // The remote address of the receiver to connect to. NOTE: we do eventually
+ // set the remote endpoint on the |environment| object, but only after
+ // getting the port information from a successful ANSWER message.
+ IPAddress remote_address;
+
+ // The client for notifying of successful negotiations and errors. Required.
+ Client* const client;
+
+ // The cast environment used to access operating system resources, such
+ // as the UDP socket for RTP/RTCP messaging. Required.
+ Environment* environment;
+
+ // The message port used to send streaming control protocol messages.
+ MessagePort* message_port;
+
+ // The message source identifier (e.g. this sender).
+ std::string message_source_id;
+
+ // The message destination identifier (e.g. the receiver we are connected
+ // to).
+ std::string message_destination_id;
+
+ // Whether or not the android RTP value hack should be used (for legacy
+ // android devices).
+ bool use_android_rtp_hack = true;
+ };
+
// The SenderSession assumes that the passed in client, environment, and
// message port persist for at least the lifetime of the SenderSession. If
// one of these classes needs to be reset, a new SenderSession should be
@@ -80,37 +134,80 @@ class SenderSession final {
// ID, respectively, to use when sending or receiving control messages (e.g.,
// OFFERs or ANSWERs) over the |message_port|. |message_port|'s SetClient()
// method will be called.
- SenderSession(IPAddress remote_address,
- Client* const client,
- Environment* environment,
- MessagePort* message_port,
- std::string message_source_id,
- std::string message_destination_id);
+ explicit SenderSession(Configuration config);
SenderSession(const SenderSession&) = delete;
SenderSession(SenderSession&&) noexcept = delete;
SenderSession& operator=(const SenderSession&) = delete;
SenderSession& operator=(SenderSession&&) = delete;
~SenderSession();
- // Starts an OFFER/ANSWER exchange with the already configured receiver
- // over the message port. The caller should assume any configured senders
- // become invalid when calling this method.
+ // Starts a mirroring OFFER/ANSWER exchange with the already configured
+ // receiver over the message port. The caller should assume any configured
+ // senders become invalid when calling this method.
Error Negotiate(std::vector<AudioCaptureConfig> audio_configs,
std::vector<VideoCaptureConfig> video_configs);
+ // Remoting negotiation is actually very similar to mirroring negotiation--
+ // an OFFER/ANSWER exchange still occurs, however only one audio and video
+ // codec should be presented based on the encoding of the media element that
+ // should be remoted. Note: the codec fields in |audio_config| and
+ // |video_config| are ignored in favor of |kRemote|.
+ Error NegotiateRemoting(AudioCaptureConfig audio_config,
+ VideoCaptureConfig video_config);
+
+ // Get the current network usage (in bits per second). This includes all
+ // senders managed by this session, and is a best guess based on receiver
+ // feedback. Embedders may use this information to throttle capture devices.
+ int GetEstimatedNetworkBandwidth() const;
+
private:
// We store the current negotiation, so that when we get an answer from the
// receiver we can line up the selected streams with the original
// configuration.
- struct Negotiation {
+ struct InProcessNegotiation {
+ // The offer, which should always be valid if we have an in process
+ // negotiation.
Offer offer;
+ // The configs used to derive the offer.
std::vector<AudioCaptureConfig> audio_configs;
std::vector<VideoCaptureConfig> video_configs;
+
+ // The answer message for this negotiation, which may be invalid if we
+ // haven't received an answer yet.
+ Answer answer;
+ };
+
+ // The state of the session.
+ enum class State {
+ // Not sending content--may be in the middle of negotiation, or just
+ // waiting.
+ kIdle,
+
+ // Currently mirroring content to a receiver.
+ kMirroring,
+
+ // Currently remoting content to a receiver.
+ kRemoting
};
+ // Reset the state and tear down the current negotiation/negotiated mirroring
+ // or remoting session. After reset, the SenderSession is still connected to
+ // the same |remote_address_|, and the |packet_router_| and sequence number
+ // will be unchanged.
+ void ResetState();
+
+ // Uses the passed in configs and offer to send an OFFER/ANSWER negotiation
+ // and cache the new InProcessNavigation.
+ Error StartNegotiation(std::vector<AudioCaptureConfig> audio_configs,
+ std::vector<VideoCaptureConfig> video_configs,
+ Offer offer);
+
// Specific message type handler methods.
void OnAnswer(ReceiverMessage message);
+ void OnCapabilitiesResponse(ReceiverMessage message);
+ void OnRpcMessage(ReceiverMessage message);
+ void HandleErrorMessage(ReceiverMessage message, const std::string& text);
// Used by SpawnSenders to generate a sender for a specific stream.
std::unique_ptr<Sender> CreateSender(Ssrc receiver_ssrc,
@@ -130,18 +227,15 @@ class SenderSession final {
// Spawn a set of configured senders from the currently stored negotiation.
ConfiguredSenders SpawnSenders(const Answer& answer);
- // The remote address of the receiver we are communicating with. Used
- // for both TLS and UDP traffic.
- const IPAddress remote_address_;
+ // This session's configuration.
+ Configuration config_;
- // The embedder is expected to provide us a client for notifications about
- // negotiations and errors, a valid cast environment, and a messaging
- // port for communicating to the Receiver over TLS.
- Client* const client_;
- Environment* const environment_;
+ // The session messager, which uses the message port for sending control
+ // messages. For message formats, see
+ // cast/protocol/castv2/streaming_schema.json.
SenderSessionMessager messager_;
- // The packet router used for messaging across all senders.
+ // The packet router used for RTP/RTCP messaging across all senders.
SenderPacketRouter packet_router_;
// Each negotiation has its own sequence number, and the receiver replies
@@ -151,12 +245,22 @@ class SenderSession final {
// The current negotiation. If present, we are expected an ANSWER from
// the receiver. If not present, any provided ANSWERS are rejected.
- std::unique_ptr<Negotiation> current_negotiation_;
+ std::unique_ptr<InProcessNegotiation> current_negotiation_;
+
+ // The current state of the session. Note that the state is intentionally
+ // limited. |kMirroring| or |kRemoting| means that we are either starting
+ // a negotiation or actively sending to a receiver.
+ State state_ = State::kIdle;
// If the negotiation has succeeded, we store the current audio and video
// senders used for this session. Either or both may be nullptr.
std::unique_ptr<Sender> current_audio_sender_;
std::unique_ptr<Sender> current_video_sender_;
+
+ // If remoting, we store the RpcBroker used by the embedder to send RPC
+ // messages from the remoting protobuf specification. For more information,
+ // see //cast/streaming/remoting.proto.
+ std::unique_ptr<RpcBroker> broker_;
}; // namespace cast
} // namespace cast
diff --git a/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc
index 2ea2073b1cb..f8d4f24ed94 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/sender_session_unittest.cc
@@ -96,6 +96,15 @@ constexpr char kErrorAnswerMessage[] = R"({
}
})";
+constexpr char kCapabilitiesResponse[] = R"({
+ "seqNum": 2,
+ "result": "ok",
+ "type": "CAPABILITIES_RESPONSE",
+ "capabilities": {
+ "mediaCaps": ["video", "vp8", "audio", "aac"]
+ }
+})";
+
const AudioCaptureConfig kAudioCaptureConfigInvalidChannels{
AudioCodec::kAac, -1 /* channels */, 44000 /* bit_rate */,
96000 /* sample_rate */
@@ -132,6 +141,10 @@ class FakeClient : public SenderSession::Client {
SenderSession::ConfiguredSenders,
capture_recommendations::Recommendations),
(override));
+ MOCK_METHOD(void,
+ OnRemotingNegotiated,
+ (const SenderSession*, SenderSession::RemotingNegotiation),
+ (override));
MOCK_METHOD(void, OnError, (const SenderSession*, Error error), (override));
};
@@ -153,19 +166,32 @@ class SenderSessionTest : public ::testing::Test {
void SetUp() {
message_port_ = std::make_unique<SimpleMessagePort>("receiver-12345");
environment_ = MakeEnvironment();
- session_ = std::make_unique<SenderSession>(
- IPAddress::kV4LoopbackAddress(), &client_, environment_.get(),
- message_port_.get(), "sender-12345", "receiver-12345");
+
+ SenderSession::Configuration config{IPAddress::kV4LoopbackAddress(),
+ &client_,
+ environment_.get(),
+ message_port_.get(),
+ "sender-12345",
+ "receiver-12345",
+ /* use_android_rtp_hack */ true};
+ session_ = std::make_unique<SenderSession>(std::move(config));
}
- std::string NegotiateOfferAndConstructAnswer() {
+ void NegotiateMirroringWithValidConfigs() {
const Error error = session_->Negotiate(
std::vector<AudioCaptureConfig>{kAudioCaptureConfigValid},
std::vector<VideoCaptureConfig>{kVideoCaptureConfigValid});
- if (!error.ok()) {
- return {};
- }
+ ASSERT_TRUE(error.ok());
+ }
+
+ void NegotiateRemotingWithValidConfigs() {
+ const Error error = session_->NegotiateRemoting(kAudioCaptureConfigValid,
+ kVideoCaptureConfigValid);
+ ASSERT_TRUE(error.ok());
+ }
+ // Answers require specific fields from the original offer to be valid.
+ std::string ConstructAnswerFromOffer(CastMode mode) {
const auto& messages = message_port_->posted_messages();
if (messages.size() != 1) {
return {};
@@ -200,14 +226,16 @@ class SenderSessionTest : public ::testing::Test {
"seqNum": %d,
"result": "ok",
"answer": {
- "castMode": "mirroring",
+ "castMode": "%s",
"udpPort": 1234,
"sendIndexes": [%d, %d],
"ssrcs": [%d, %d]
}
})";
- return StringPrintf(kAnswerTemplate, offer["seqNum"].asInt(), audio_index,
- video_index, audio_ssrc + 1, video_ssrc + 1);
+ return StringPrintf(kAnswerTemplate, offer["seqNum"].asInt(),
+ mode == CastMode::kMirroring ? "mirroring" : "remoting",
+ audio_index, video_index, audio_ssrc + 1,
+ video_ssrc + 1);
}
protected:
@@ -344,14 +372,16 @@ TEST_F(SenderSessionTest, SendsOfferMessage) {
}
TEST_F(SenderSessionTest, HandlesValidAnswer) {
- std::string answer = NegotiateOfferAndConstructAnswer();
+ NegotiateMirroringWithValidConfigs();
+ std::string answer = ConstructAnswerFromOffer(CastMode::kMirroring);
EXPECT_CALL(client_, OnNegotiated(session_.get(), _, _));
message_port_->ReceiveMessage(answer);
}
TEST_F(SenderSessionTest, HandlesInvalidNamespace) {
- std::string answer = NegotiateOfferAndConstructAnswer();
+ NegotiateMirroringWithValidConfigs();
+ std::string answer = ConstructAnswerFromOffer(CastMode::kMirroring);
message_port_->ReceiveMessage("random-namespace", answer);
}
@@ -454,5 +484,66 @@ TEST_F(SenderSessionTest, DoesNotCrashOnMessagePortError) {
message_port_->ReceiveError(Error(Error::Code::kUnknownError));
}
+TEST_F(SenderSessionTest, ReportsZeroBandwidthWhenNoPacketsSent) {
+ // TODO(issuetracker.google.com/183996645): As part of end to end testing,
+ // we need to ensure that we are providing reasonable network bandwidth
+ // measurements.
+ EXPECT_EQ(0, session_->GetEstimatedNetworkBandwidth());
+}
+
+TEST_F(SenderSessionTest, ComplainsIfInvalidAudioCaptureConfigRemoting) {
+ const Error error = session_->NegotiateRemoting(
+ kAudioCaptureConfigInvalidChannels, kVideoCaptureConfigValid);
+
+ EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
+}
+
+TEST_F(SenderSessionTest, ComplainsIfInvalidVideoCaptureConfigRemoting) {
+ const Error error = session_->NegotiateRemoting(kAudioCaptureConfigValid,
+ kVideoCaptureConfigInvalid);
+ EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
+}
+
+TEST_F(SenderSessionTest, ComplainsIfMissingResolutionsRemoting) {
+ const Error error = session_->NegotiateRemoting(
+ kAudioCaptureConfigValid, kVideoCaptureConfigMissingResolutions);
+ EXPECT_EQ(error.code(), Error::Code::kParameterInvalid);
+}
+
+TEST_F(SenderSessionTest, HandlesValidAnswerRemoting) {
+ NegotiateRemotingWithValidConfigs();
+ std::string answer = ConstructAnswerFromOffer(CastMode::kRemoting);
+
+ EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _));
+ message_port_->ReceiveMessage(answer);
+ message_port_->ReceiveMessage(kCapabilitiesResponse);
+}
+
+TEST_F(SenderSessionTest, SuccessfulRemotingNegotiationYieldsValidObject) {
+ NegotiateRemotingWithValidConfigs();
+ std::string answer = ConstructAnswerFromOffer(CastMode::kRemoting);
+
+ SenderSession::RemotingNegotiation negotiation;
+ EXPECT_CALL(client_, OnRemotingNegotiated(session_.get(), _))
+ .WillOnce(testing::SaveArg<1>(&negotiation));
+ message_port_->ReceiveMessage(answer);
+ message_port_->ReceiveMessage(kCapabilitiesResponse);
+
+ // The capabilities should match the values in |kCapabilitiesResponse|.
+ EXPECT_THAT(negotiation.capabilities.audio,
+ testing::ElementsAre(AudioCapability::kBaselineSet,
+ AudioCapability::kAac));
+
+ // The "video" capability is ignored since it means nothing.
+ EXPECT_THAT(negotiation.capabilities.video,
+ testing::ElementsAre(VideoCapability::kVp8));
+
+ // The broker is tested elsewhere, but we can sanity check that we got a valid
+ // one here.
+ EXPECT_TRUE(negotiation.broker);
+ const RpcBroker::Handle handle = negotiation.broker->GetUniqueHandle();
+ EXPECT_NE(RpcBroker::kInvalidHandle, handle);
+}
+
} // namespace cast
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/cast/streaming/session_messager.cc b/chromium/third_party/openscreen/src/cast/streaming/session_messager.cc
index 31e634d9561..126f721857f 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/session_messager.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/session_messager.cc
@@ -21,8 +21,7 @@ void ReplyIfTimedOut(
ReceiverMessage::Type reply_type,
std::vector<std::pair<int, SenderSessionMessager::ReplyCallback>>*
replies) {
- auto it = replies->begin();
- for (; it != replies->end(); ++it) {
+ for (auto it = replies->begin(); it != replies->end(); ++it) {
if (it->first == sequence_number) {
OSP_DVLOG
<< "Replying with empty message due to timeout for sequence number: "
@@ -108,6 +107,8 @@ Error SenderSessionMessager::SendRequest(SenderMessage message,
return error;
}
+ OSP_DCHECK(awaiting_replies_.find(message.sequence_number) ==
+ awaiting_replies_.end());
awaiting_replies_.emplace_back(message.sequence_number, std::move(cb));
task_runner_->PostTaskWithDelay(
[self = weak_factory_.GetWeakPtr(), reply_type,
@@ -179,8 +180,12 @@ void SenderSessionMessager::OnMessage(const std::string& source_id,
return;
}
- it->second(receiver_message.value({}));
- awaiting_replies_.erase(it);
+ it->second(std::move(receiver_message.value({})));
+
+ // Calling the function callback may result in the checksum of the pointed
+ // to object to change, so calling erase() on the iterator after executing
+ // second() may result in a segfault.
+ awaiting_replies_.erase_key(sequence_number);
}
}
@@ -202,7 +207,7 @@ void ReceiverSessionMessager::SetHandler(SenderMessage::Type type,
Error ReceiverSessionMessager::SendMessage(ReceiverMessage message) {
if (sender_session_id_.empty()) {
return Error(Error::Code::kInitializationFailure,
- "Tried to send a message without receving one first");
+ "Tried to send a message without receiving one first");
}
const auto namespace_ = (message.type == ReceiverMessage::Type::kRpc)
diff --git a/chromium/third_party/openscreen/src/cast/streaming/session_messager.h b/chromium/third_party/openscreen/src/cast/streaming/session_messager.h
index 99b458ff56b..044ff794a64 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/session_messager.h
+++ b/chromium/third_party/openscreen/src/cast/streaming/session_messager.h
@@ -38,9 +38,9 @@ class SessionMessager : public MessagePort::Client {
protected:
// Barebones message sending method shared by both children.
- Error SendMessage(const std::string& destination_id,
- const std::string& namespace_,
- const Json::Value& message_root);
+ [[nodiscard]] Error SendMessage(const std::string& destination_id,
+ const std::string& namespace_,
+ const Json::Value& message_root);
// Used to report errors in subclasses.
void ReportError(Error error);
diff --git a/chromium/third_party/openscreen/src/cast/streaming/session_messager_unittest.cc b/chromium/third_party/openscreen/src/cast/streaming/session_messager_unittest.cc
index 6f5dd3eaca2..21d702809c1 100644
--- a/chromium/third_party/openscreen/src/cast/streaming/session_messager_unittest.cc
+++ b/chromium/third_party/openscreen/src/cast/streaming/session_messager_unittest.cc
@@ -125,24 +125,26 @@ class SessionMessagerTest : public ::testing::Test {
};
TEST_F(SessionMessagerTest, RpcMessaging) {
- ASSERT_TRUE(sender_messager_
- .SendOutboundMessage(SenderMessage{
- SenderMessage::Type::kRpc, 123, true /* valid */,
- std::string("all your base are belong to us")})
- .ok());
+ static const std::vector<uint8_t> kSenderMessage{1, 2, 3, 4, 5};
+ static const std::vector<uint8_t> kReceiverResponse{6, 7, 8, 9};
+ ASSERT_TRUE(
+ sender_messager_
+ .SendOutboundMessage(SenderMessage{SenderMessage::Type::kRpc, 123,
+ true /* valid */, kSenderMessage})
+ .ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kRpc, message_store_.sender_messages[0].type);
ASSERT_TRUE(message_store_.sender_messages[0].valid);
- EXPECT_EQ("all your base are belong to us",
- absl::get<std::string>(message_store_.sender_messages[0].body));
+ EXPECT_EQ(kSenderMessage, absl::get<std::vector<uint8_t>>(
+ message_store_.sender_messages[0].body));
message_store_.sender_messages.clear();
ASSERT_TRUE(
receiver_messager_
.SendMessage(ReceiverMessage{ReceiverMessage::Type::kRpc, 123,
- true /* valid */, std::string("nuh uh")})
+ true /* valid */, kReceiverResponse})
.ok());
ASSERT_TRUE(message_store_.sender_messages.empty());
@@ -150,8 +152,8 @@ TEST_F(SessionMessagerTest, RpcMessaging) {
EXPECT_EQ(ReceiverMessage::Type::kRpc,
message_store_.receiver_messages[0].type);
EXPECT_TRUE(message_store_.receiver_messages[0].valid);
- EXPECT_EQ("nuh uh",
- absl::get<std::string>(message_store_.receiver_messages[0].body));
+ EXPECT_EQ(kReceiverResponse, absl::get<std::vector<uint8_t>>(
+ message_store_.receiver_messages[0].body));
}
TEST_F(SessionMessagerTest, StatusMessaging) {
@@ -207,7 +209,9 @@ TEST_F(SessionMessagerTest, CapabilitiesMessaging) {
ASSERT_TRUE(receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kCapabilitiesResponse, 1337,
- true /* valid */, ReceiverCapability{47, {"ac3", "4k"}}})
+ true /* valid */,
+ ReceiverCapability{
+ 47, {MediaCapability::kAac, MediaCapability::k4k}}})
.ok());
ASSERT_TRUE(message_store_.sender_messages.empty());
@@ -219,7 +223,8 @@ TEST_F(SessionMessagerTest, CapabilitiesMessaging) {
const auto& capability =
absl::get<ReceiverCapability>(message_store_.receiver_messages[0].body);
EXPECT_EQ(47, capability.remoting_version);
- EXPECT_THAT(capability.media_capabilities, ElementsAre("ac3", "4k"));
+ EXPECT_THAT(capability.media_capabilities,
+ ElementsAre(MediaCapability::kAac, MediaCapability::k4k));
}
TEST_F(SessionMessagerTest, OfferAnswerMessaging) {
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
index 9e6f166ed33..079dbf7d79f 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph.cc
@@ -252,7 +252,10 @@ Error DnsDataGraphImpl::Node::ApplyDataRecordChange(MdnsRecord record,
if (record.dns_type() == DnsType::kPTR) {
child_name = absl::get<PtrRecordRdata>(record.rdata()).ptr_domain();
- it = std::find(records_.begin(), records_.end(), record);
+ it = std::find_if(records_.begin(), records_.end(),
+ [record](const MdnsRecord& rhs) {
+ return record.IsReannouncementOf(rhs);
+ });
} else {
if (record.dns_type() == DnsType::kSRV) {
child_name = absl::get<SrvRecordRdata>(record.rdata()).target();
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph_unittest.cc b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph_unittest.cc
index 0af3aa19dbb..a32b942c240 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph_unittest.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/impl/dns_data_graph_unittest.cc
@@ -236,6 +236,21 @@ TEST_F(DnsDataGraphTests, DeleteFailsForNonExistingRecord) {
EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{2});
}
+TEST_F(DnsDataGraphTests, DeleteSucceedsForRecordWithDifferentTtl) {
+ const MdnsRecord ptr = GetFakePtrRecord(primary_domain_);
+ TriggerRecordCreationWithCallback(ptr, primary_domain_);
+
+ EXPECT_CALL(callbacks_, OnStopTracking(primary_domain_));
+ const MdnsRecord new_ptr(ptr.name(), ptr.dns_type(), ptr.dns_class(),
+ ptr.record_type(),
+ ptr.ttl() + std::chrono::seconds(10), ptr.rdata());
+ const auto result =
+ ApplyDataRecordChange(new_ptr, RecordChangedEvent::kExpired);
+
+ EXPECT_TRUE(result.ok());
+ EXPECT_EQ(graph_->GetTrackedDomainCount(), size_t{1});
+}
+
TEST_F(DnsDataGraphTests, UpdateEndpointsWorksAsExpected) {
auto ptr = GetFakePtrRecord(primary_domain_);
auto srv = GetFakeSrvRecord(primary_domain_, secondary_domain_);
diff --git a/chromium/third_party/openscreen/src/discovery/dnssd/impl/service_instance.cc b/chromium/third_party/openscreen/src/discovery/dnssd/impl/service_instance.cc
index e241e473506..7d4b014fd7e 100644
--- a/chromium/third_party/openscreen/src/discovery/dnssd/impl/service_instance.cc
+++ b/chromium/third_party/openscreen/src/discovery/dnssd/impl/service_instance.cc
@@ -23,8 +23,14 @@ ServiceInstance::ServiceInstance(TaskRunner* task_runner,
config,
network_info)),
network_config_(network_info.interface.index,
- network_info.interface.GetIpAddressV4(),
- network_info.interface.GetIpAddressV6()) {
+ (network_info.supported_address_families &
+ Config::NetworkInfo::kUseIpV4)
+ ? network_info.interface.GetIpAddressV4()
+ : IPAddress{},
+ (network_info.supported_address_families &
+ Config::NetworkInfo::kUseIpV6)
+ ? network_info.interface.GetIpAddressV6()
+ : IPAddress{}) {
const Config::NetworkInfo::AddressFamilies supported_address_families =
network_info.supported_address_families;
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
index 4768e2e4fc8..1b7b441b228 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.cc
@@ -606,9 +606,7 @@ bool MdnsRecord::IsValidConfig(const DomainName& name,
}
bool MdnsRecord::operator==(const MdnsRecord& rhs) const {
- return dns_type_ == rhs.dns_type_ && dns_class_ == rhs.dns_class_ &&
- record_type_ == rhs.record_type_ && ttl_ == rhs.ttl_ &&
- name_ == rhs.name_ && rdata_ == rhs.rdata_;
+ return IsReannouncementOf(rhs) && ttl_ == rhs.ttl_;
}
bool MdnsRecord::operator!=(const MdnsRecord& rhs) const {
@@ -654,6 +652,12 @@ bool MdnsRecord::operator>=(const MdnsRecord& rhs) const {
return !(*this < rhs);
}
+bool MdnsRecord::IsReannouncementOf(const MdnsRecord& rhs) const {
+ return dns_type_ == rhs.dns_type_ && dns_class_ == rhs.dns_class_ &&
+ record_type_ == rhs.record_type_ && name_ == rhs.name_ &&
+ rdata_ == rhs.rdata_;
+}
+
size_t MdnsRecord::MaxWireSize() const {
auto wire_size_visitor = [](auto&& arg) { return arg.MaxWireSize(); };
// NAME size, 2-byte TYPE, 2-byte CLASS, 4-byte TTL, RDATA size
diff --git a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.h b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.h
index de37932ce01..ce1be4f6571 100644
--- a/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.h
+++ b/chromium/third_party/openscreen/src/discovery/mdns/mdns_records.h
@@ -475,6 +475,9 @@ class MdnsRecord {
bool operator<=(const MdnsRecord& other) const;
bool operator>=(const MdnsRecord& other) const;
+ // While not being "equivalent", a record could be said to be an update of
+ // a different record if it is the same, excepting TTL.
+ bool IsReannouncementOf(const MdnsRecord& other) const;
size_t MaxWireSize() const;
const DomainName& name() const { return name_; }
DnsType dns_type() const { return dns_type_; }
diff --git a/chromium/third_party/openscreen/src/osp/demo/osp_demo.cc b/chromium/third_party/openscreen/src/osp/demo/osp_demo.cc
index 443536f3340..952a925f46d 100644
--- a/chromium/third_party/openscreen/src/osp/demo/osp_demo.cc
+++ b/chromium/third_party/openscreen/src/osp/demo/osp_demo.cc
@@ -644,8 +644,7 @@ int main(int argc, char** argv) {
// TODO(jophba): Mac on Mojave hangs on this command forever.
openscreen::SetLogFifoOrDie(log_filename);
- PlatformClientPosix::Create(std::chrono::milliseconds(50),
- std::chrono::milliseconds(50));
+ PlatformClientPosix::Create(std::chrono::milliseconds(50));
if (is_receiver_demo) {
OSP_LOG_INFO << "Running publisher demo...";
diff --git a/chromium/third_party/openscreen/src/osp/impl/discovery/mdns/mdns_demo.cc b/chromium/third_party/openscreen/src/osp/impl/discovery/mdns/mdns_demo.cc
index 628609957e6..1fc1513ec8c 100644
--- a/chromium/third_party/openscreen/src/osp/impl/discovery/mdns/mdns_demo.cc
+++ b/chromium/third_party/openscreen/src/osp/impl/discovery/mdns/mdns_demo.cc
@@ -361,8 +361,7 @@ int main(int argc, char** argv) {
openscreen::osp::ServiceMap services;
openscreen::osp::g_services = &services;
- PlatformClientPosix::Create(std::chrono::milliseconds(50),
- std::chrono::milliseconds(50));
+ PlatformClientPosix::Create(std::chrono::milliseconds(50));
openscreen::osp::BrowseDemo(
PlatformClientPosix::GetInstance()->GetTaskRunner(), labels[0], labels[1],
diff --git a/chromium/third_party/openscreen/src/platform/base/error.cc b/chromium/third_party/openscreen/src/platform/base/error.cc
index 58d81e76dd3..fa891335c5f 100644
--- a/chromium/third_party/openscreen/src/platform/base/error.cc
+++ b/chromium/third_party/openscreen/src/platform/base/error.cc
@@ -256,6 +256,12 @@ std::ostream& operator<<(std::ostream& os, const Error::Code& code) {
return os << "UnknownCodec";
case Error::Code::kSocketFailure:
return os << "SocketFailure";
+ case Error::Code::kUnencryptedOffer:
+ return os << "UnencryptedOffer";
+ case Error::Code::kRemotingNotSupported:
+ return os << "RemotingNotSupported";
+ case Error::Code::kNegotiationFailure:
+ return os << "NegotiationFailure";
case Error::Code::kNone:
break;
}
diff --git a/chromium/third_party/openscreen/src/platform/base/error.h b/chromium/third_party/openscreen/src/platform/base/error.h
index dc4c3a7f874..69a8a89ec40 100644
--- a/chromium/third_party/openscreen/src/platform/base/error.h
+++ b/chromium/third_party/openscreen/src/platform/base/error.h
@@ -186,7 +186,13 @@ class Error {
// Cast streaming errors
kTypeError,
kUnknownCodec,
- kSocketFailure
+ kSocketFailure,
+ kUnencryptedOffer,
+ kRemotingNotSupported,
+
+ // A negotiation failure means that the current negotiation must be
+ // restarted by the sender.
+ kNegotiationFailure,
};
Error();
diff --git a/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.cc b/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.cc
index d1415258bd7..328b8bfa8eb 100644
--- a/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.cc
+++ b/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.cc
@@ -5,6 +5,7 @@
#include "platform/impl/platform_client_posix.h"
#include <functional>
+#include <utility>
#include <vector>
#include "platform/impl/udp_socket_reader_posix.h"
@@ -16,18 +17,14 @@ PlatformClientPosix* PlatformClientPosix::instance_ = nullptr;
// static
void PlatformClientPosix::Create(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval,
std::unique_ptr<TaskRunnerImpl> task_runner) {
SetInstance(new PlatformClientPosix(networking_operation_timeout,
- networking_loop_interval,
std::move(task_runner)));
}
// static
-void PlatformClientPosix::Create(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval) {
- SetInstance(new PlatformClientPosix(networking_operation_timeout,
- networking_loop_interval));
+void PlatformClientPosix::Create(Clock::duration networking_operation_timeout) {
+ SetInstance(new PlatformClientPosix(networking_operation_timeout));
}
// static
@@ -67,7 +64,7 @@ PlatformClientPosix::~PlatformClientPosix() {
}
OSP_DVLOG << "Shutting down network operations...";
- networking_loop_.RequestStopSoon();
+ networking_loop_running_.store(false);
networking_loop_thread_.join();
OSP_DVLOG << "\tNetwork operation shutdown complete!";
}
@@ -79,27 +76,21 @@ void PlatformClientPosix::SetInstance(PlatformClientPosix* instance) {
}
PlatformClientPosix::PlatformClientPosix(
- Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval)
- : networking_loop_(networking_operations(),
- networking_operation_timeout,
- networking_loop_interval),
- task_runner_(new TaskRunnerImpl(Clock::now)),
- networking_loop_thread_(&OperationLoop::RunUntilStopped,
- &networking_loop_),
+ Clock::duration networking_operation_timeout)
+ : task_runner_(new TaskRunnerImpl(Clock::now)),
+ networking_loop_timeout_(networking_operation_timeout),
+ networking_loop_thread_(&PlatformClientPosix::RunNetworkLoopUntilStopped,
+ this),
task_runner_thread_(
std::thread(&TaskRunnerImpl::RunUntilStopped, task_runner_.get())) {}
PlatformClientPosix::PlatformClientPosix(
Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval,
std::unique_ptr<TaskRunnerImpl> task_runner)
- : networking_loop_(networking_operations(),
- networking_operation_timeout,
- networking_loop_interval),
- task_runner_(std::move(task_runner)),
- networking_loop_thread_(&OperationLoop::RunUntilStopped,
- &networking_loop_) {}
+ : task_runner_(std::move(task_runner)),
+ networking_loop_timeout_(networking_operation_timeout),
+ networking_loop_thread_(&PlatformClientPosix::RunNetworkLoopUntilStopped,
+ this) {}
SocketHandleWaiterPosix* PlatformClientPosix::socket_handle_waiter() {
std::call_once(waiter_initialization_, [this]() {
@@ -109,20 +100,14 @@ SocketHandleWaiterPosix* PlatformClientPosix::socket_handle_waiter() {
return waiter_.get();
}
-void PlatformClientPosix::PerformSocketHandleWaiterActions(
- Clock::duration timeout) {
- if (!waiter_created_.load()) {
- return;
+void PlatformClientPosix::RunNetworkLoopUntilStopped() {
+ while (networking_loop_running_.load()) {
+ if (!waiter_created_.load()) {
+ std::this_thread::sleep_for(networking_loop_timeout_);
+ continue;
+ }
+ socket_handle_waiter()->ProcessHandles(networking_loop_timeout_);
}
-
- socket_handle_waiter()->ProcessHandles(timeout);
-}
-
-std::vector<std::function<void(Clock::duration)>>
-PlatformClientPosix::networking_operations() {
- return {[this](Clock::duration timeout) {
- PerformSocketHandleWaiterActions(timeout);
- }};
}
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.h b/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.h
index 6bda424b168..bb320f553b2 100644
--- a/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.h
+++ b/chromium/third_party/openscreen/src/platform/impl/platform_client_posix.h
@@ -9,6 +9,7 @@
#include <memory>
#include <mutex>
#include <thread>
+#include <vector>
#include "absl/types/optional.h"
#include "platform/api/time.h"
@@ -16,7 +17,6 @@
#include "platform/impl/socket_handle_waiter_posix.h"
#include "platform/impl/task_runner.h"
#include "platform/impl/tls_data_router_posix.h"
-#include "util/operation_loop.h"
namespace openscreen {
@@ -41,20 +41,19 @@ class PlatformClientPosix {
// |networking_loop_interval| sets the minimum amount of time that should pass
// between iterations of the loop used to handle networking operations. Higher
// values will result in less time being spent on these operations, but also
- // potentially less performant networking operations.
+ // less performant networking operations. Be careful setting values larger
+ // than a few hundred microseconds.
//
// |networking_operation_timeout| sets how much time may be spent on a
// single networking operation type.
//
// |task_runner| is a client-provided TaskRunner implementation.
static void Create(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval,
std::unique_ptr<TaskRunnerImpl> task_runner);
// Initializes the platform implementation and creates a new TaskRunner (which
// starts a new thread).
- static void Create(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval);
+ static void Create(Clock::duration networking_operation_timeout);
// Shuts down and deletes the PlatformClient instance currently stored as a
// singleton. This method is expected to be called before program exit. After
@@ -83,25 +82,15 @@ class PlatformClientPosix {
static void SetInstance(PlatformClientPosix* client);
private:
- PlatformClientPosix(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval);
+ explicit PlatformClientPosix(Clock::duration networking_operation_timeout);
PlatformClientPosix(Clock::duration networking_operation_timeout,
- Clock::duration networking_loop_interval,
std::unique_ptr<TaskRunnerImpl> task_runner);
// This method is thread-safe.
SocketHandleWaiterPosix* socket_handle_waiter();
- // Helper functions to use when creating and calling the OperationLoop used
- // for the networking thread.
- void PerformSocketHandleWaiterActions(Clock::duration timeout);
- void PerformTlsDataRouterActions(Clock::duration timeout);
- std::vector<std::function<void(Clock::duration)>> networking_operations();
-
- // Instance objects with threads are created at object-creation time.
- // NOTE: Delayed instantiation of networking_loop_ may be useful in future.
- OperationLoop networking_loop_;
+ void RunNetworkLoopUntilStopped();
std::unique_ptr<TaskRunnerImpl> task_runner_;
@@ -109,6 +98,10 @@ class PlatformClientPosix {
std::atomic_bool waiter_created_{false};
std::atomic_bool tls_data_router_created_{false};
+ // Parameters for networking loop.
+ std::atomic_bool networking_loop_running_{true};
+ Clock::duration networking_loop_timeout_;
+
// Flags used to ensure that initialization of below instance objects occurs
// only once across all threads.
std::once_flag waiter_initialization_;
diff --git a/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated.gni b/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated.gni
index f96352f79b7..aee38c2ea0a 100644
--- a/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated.gni
+++ b/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated.gni
@@ -49,6 +49,7 @@ crypto_sources = [
"src/crypto/bio/printf.c",
"src/crypto/bio/socket.c",
"src/crypto/bio/socket_helper.c",
+ "src/crypto/blake2/blake2.c",
"src/crypto/bn_extra/bn_asn1.c",
"src/crypto/bn_extra/convert.c",
"src/crypto/buf/buf.c",
@@ -78,20 +79,23 @@ crypto_sources = [
"src/crypto/conf/internal.h",
"src/crypto/cpu-aarch64-fuchsia.c",
"src/crypto/cpu-aarch64-linux.c",
+ "src/crypto/cpu-aarch64-win.c",
"src/crypto/cpu-arm-linux.c",
"src/crypto/cpu-arm-linux.h",
"src/crypto/cpu-arm.c",
"src/crypto/cpu-intel.c",
"src/crypto/cpu-ppc64le.c",
"src/crypto/crypto.c",
+ "src/crypto/curve25519/curve25519.c",
+ "src/crypto/curve25519/curve25519_tables.h",
+ "src/crypto/curve25519/internal.h",
"src/crypto/curve25519/spake25519.c",
- "src/crypto/dh/check.c",
- "src/crypto/dh/dh.c",
- "src/crypto/dh/dh_asn1.c",
- "src/crypto/dh/params.c",
+ "src/crypto/dh_extra/dh_asn1.c",
+ "src/crypto/dh_extra/params.c",
"src/crypto/digest_extra/digest_extra.c",
"src/crypto/dsa/dsa.c",
"src/crypto/dsa/dsa_asn1.c",
+ "src/crypto/dsa/internal.h",
"src/crypto/ec_extra/ec_asn1.c",
"src/crypto/ec_extra/ec_derive.c",
"src/crypto/ec_extra/hash_to_curve.c",
@@ -132,16 +136,20 @@ crypto_sources = [
"src/crypto/fipsmodule/ec/internal.h",
"src/crypto/fipsmodule/ec/p256-x86_64-table.h",
"src/crypto/fipsmodule/ec/p256-x86_64.h",
+ "src/crypto/fipsmodule/ec/p256_table.h",
"src/crypto/fipsmodule/fips_shared_support.c",
"src/crypto/fipsmodule/is_fips.c",
"src/crypto/fipsmodule/md5/internal.h",
"src/crypto/fipsmodule/modes/internal.h",
+ "src/crypto/fipsmodule/rand/fork_detect.h",
"src/crypto/fipsmodule/rand/getrandom_fillin.h",
"src/crypto/fipsmodule/rand/internal.h",
"src/crypto/fipsmodule/rsa/internal.h",
"src/crypto/fipsmodule/sha/internal.h",
"src/crypto/fipsmodule/tls/internal.h",
"src/crypto/hkdf/hkdf.c",
+ "src/crypto/hpke/hpke.c",
+ "src/crypto/hpke/internal.h",
"src/crypto/hrss/hrss.c",
"src/crypto/hrss/internal.h",
"src/crypto/internal.h",
@@ -174,6 +182,7 @@ crypto_sources = [
"src/crypto/rand_extra/deterministic.c",
"src/crypto/rand_extra/forkunsafe.c",
"src/crypto/rand_extra/fuchsia.c",
+ "src/crypto/rand_extra/passive.c",
"src/crypto/rand_extra/rand_extra.c",
"src/crypto/rand_extra/windows.c",
"src/crypto/rc4/rc4.c",
@@ -190,6 +199,7 @@ crypto_sources = [
"src/crypto/trust_token/internal.h",
"src/crypto/trust_token/pmbtoken.c",
"src/crypto/trust_token/trust_token.c",
+ "src/crypto/trust_token/voprf.c",
"src/crypto/x509/a_digest.c",
"src/crypto/x509/a_sign.c",
"src/crypto/x509/a_strex.c",
@@ -271,18 +281,13 @@ crypto_sources = [
"src/crypto/x509v3/v3_pci.c",
"src/crypto/x509v3/v3_pcia.c",
"src/crypto/x509v3/v3_pcons.c",
- "src/crypto/x509v3/v3_pku.c",
"src/crypto/x509v3/v3_pmaps.c",
"src/crypto/x509v3/v3_prn.c",
"src/crypto/x509v3/v3_purp.c",
"src/crypto/x509v3/v3_skey.c",
- "src/crypto/x509v3/v3_sxnet.c",
"src/crypto/x509v3/v3_utl.c",
- "src/third_party/fiat/curve25519.c",
"src/third_party/fiat/curve25519_32.h",
"src/third_party/fiat/curve25519_64.h",
- "src/third_party/fiat/curve25519_tables.h",
- "src/third_party/fiat/internal.h",
"src/third_party/fiat/p256_32.h",
"src/third_party/fiat/p256_64.h",
]
@@ -297,6 +302,7 @@ crypto_headers = [
"src/include/openssl/base.h",
"src/include/openssl/base64.h",
"src/include/openssl/bio.h",
+ "src/include/openssl/blake2.h",
"src/include/openssl/blowfish.h",
"src/include/openssl/bn.h",
"src/include/openssl/buf.h",
@@ -409,6 +415,27 @@ ssl_headers = [
"src/include/openssl/tls1.h",
]
+tool_sources = [
+ "src/tool/args.cc",
+ "src/tool/ciphers.cc",
+ "src/tool/client.cc",
+ "src/tool/const.cc",
+ "src/tool/digest.cc",
+ "src/tool/fd.cc",
+ "src/tool/file.cc",
+ "src/tool/generate_ed25519.cc",
+ "src/tool/genrsa.cc",
+ "src/tool/internal.h",
+ "src/tool/pkcs12.cc",
+ "src/tool/rand.cc",
+ "src/tool/server.cc",
+ "src/tool/sign.cc",
+ "src/tool/speed.cc",
+ "src/tool/tool.cc",
+ "src/tool/transport_common.cc",
+ "src/tool/transport_common.h",
+]
+
crypto_sources_ios_aarch64 = [
"ios-aarch64/crypto/chacha/chacha-armv8.S",
"ios-aarch64/crypto/fipsmodule/aesv8-armx64.S",
@@ -548,6 +575,19 @@ crypto_sources_mac_x86_64 = [
"mac-x86_64/crypto/test/trampoline-x86_64.S",
]
+crypto_sources_win_aarch64 = [
+ "win-aarch64/crypto/chacha/chacha-armv8.S",
+ "win-aarch64/crypto/fipsmodule/aesv8-armx64.S",
+ "win-aarch64/crypto/fipsmodule/armv8-mont.S",
+ "win-aarch64/crypto/fipsmodule/ghash-neon-armv8.S",
+ "win-aarch64/crypto/fipsmodule/ghashv8-armx64.S",
+ "win-aarch64/crypto/fipsmodule/sha1-armv8.S",
+ "win-aarch64/crypto/fipsmodule/sha256-armv8.S",
+ "win-aarch64/crypto/fipsmodule/sha512-armv8.S",
+ "win-aarch64/crypto/fipsmodule/vpaes-armv8.S",
+ "win-aarch64/crypto/test/trampoline-armv8.S",
+]
+
crypto_sources_win_x86 = [
"win-x86/crypto/chacha/chacha-x86.asm",
"win-x86/crypto/fipsmodule/aesni-x86.asm",
diff --git a/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated_tests.gni b/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated_tests.gni
index 3e8ff75219c..29fc7c071f3 100644
--- a/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated_tests.gni
+++ b/chromium/third_party/openscreen/src/third_party/boringssl/BUILD.generated_tests.gni
@@ -31,6 +31,7 @@ crypto_test_sources = [
"src/crypto/asn1/asn1_test.cc",
"src/crypto/base64/base64_test.cc",
"src/crypto/bio/bio_test.cc",
+ "src/crypto/blake2/blake2_test.cc",
"src/crypto/buf/buf_test.cc",
"src/crypto/bytestring/bytestring_test.cc",
"src/crypto/chacha/chacha_test.cc",
@@ -40,10 +41,11 @@ crypto_test_sources = [
"src/crypto/compiler_test.cc",
"src/crypto/constant_time_test.cc",
"src/crypto/cpu-arm-linux_test.cc",
+ "src/crypto/crypto_test.cc",
"src/crypto/curve25519/ed25519_test.cc",
"src/crypto/curve25519/spake25519_test.cc",
"src/crypto/curve25519/x25519_test.cc",
- "src/crypto/dh/dh_test.cc",
+ "src/crypto/dh_extra/dh_test.cc",
"src/crypto/digest_extra/digest_test.cc",
"src/crypto/dsa/dsa_test.cc",
"src/crypto/ecdh_extra/ecdh_test.cc",
@@ -60,9 +62,11 @@ crypto_test_sources = [
"src/crypto/fipsmodule/md5/md5_test.cc",
"src/crypto/fipsmodule/modes/gcm_test.cc",
"src/crypto/fipsmodule/rand/ctrdrbg_test.cc",
+ "src/crypto/fipsmodule/rand/fork_detect_test.cc",
"src/crypto/fipsmodule/sha/sha_test.cc",
"src/crypto/hkdf/hkdf_test.cc",
"src/crypto/hmac_extra/hmac_test.cc",
+ "src/crypto/hpke/hpke_test.cc",
"src/crypto/hrss/hrss_test.cc",
"src/crypto/impl_dispatch_test.cc",
"src/crypto/lhash/lhash_test.cc",
@@ -91,12 +95,14 @@ crypto_test_sources = [
]
crypto_test_data = [
+ "src/crypto/blake2/blake2b256_tests.txt",
"src/crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt",
"src/crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt",
"src/crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt",
"src/crypto/cipher_extra/test/aes_128_ccm_bluetooth_8_tests.txt",
"src/crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt",
"src/crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt",
+ "src/crypto/cipher_extra/test/aes_128_gcm_randnonce_tests.txt",
"src/crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt",
"src/crypto/cipher_extra/test/aes_128_gcm_tests.txt",
"src/crypto/cipher_extra/test/aes_192_gcm_tests.txt",
@@ -105,6 +111,7 @@ crypto_test_data = [
"src/crypto/cipher_extra/test/aes_256_cbc_sha256_tls_tests.txt",
"src/crypto/cipher_extra/test/aes_256_cbc_sha384_tls_tests.txt",
"src/crypto/cipher_extra/test/aes_256_ctr_hmac_sha256.txt",
+ "src/crypto/cipher_extra/test/aes_256_gcm_randnonce_tests.txt",
"src/crypto/cipher_extra/test/aes_256_gcm_siv_tests.txt",
"src/crypto/cipher_extra/test/aes_256_gcm_tests.txt",
"src/crypto/cipher_extra/test/chacha20_poly1305_tests.txt",
@@ -140,15 +147,46 @@ crypto_test_data = [
"src/crypto/fipsmodule/modes/gcm_tests.txt",
"src/crypto/fipsmodule/rand/ctrdrbg_vectors.txt",
"src/crypto/hmac_extra/hmac_tests.txt",
+ "src/crypto/hpke/hpke_test_vectors.txt",
"src/crypto/poly1305/poly1305_tests.txt",
"src/crypto/siphash/siphash_tests.txt",
- "src/crypto/x509/many_constraints.pem",
- "src/crypto/x509/many_names1.pem",
- "src/crypto/x509/many_names2.pem",
- "src/crypto/x509/many_names3.pem",
- "src/crypto/x509/some_names1.pem",
- "src/crypto/x509/some_names2.pem",
- "src/crypto/x509/some_names3.pem",
+ "src/crypto/x509/test/basic_constraints_ca.pem",
+ "src/crypto/x509/test/basic_constraints_ca_pathlen_0.pem",
+ "src/crypto/x509/test/basic_constraints_ca_pathlen_1.pem",
+ "src/crypto/x509/test/basic_constraints_ca_pathlen_10.pem",
+ "src/crypto/x509/test/basic_constraints_leaf.pem",
+ "src/crypto/x509/test/basic_constraints_none.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_authority_key_identifier.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_basic_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_ext_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_name_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_subject_alt_name.pem",
+ "src/crypto/x509/test/invalid_extension_intermediate_subject_key_identifier.pem",
+ "src/crypto/x509/test/invalid_extension_leaf.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_authority_key_identifier.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_basic_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_ext_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_name_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_subject_alt_name.pem",
+ "src/crypto/x509/test/invalid_extension_leaf_subject_key_identifier.pem",
+ "src/crypto/x509/test/invalid_extension_root.pem",
+ "src/crypto/x509/test/invalid_extension_root_authority_key_identifier.pem",
+ "src/crypto/x509/test/invalid_extension_root_basic_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_root_ext_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_root_key_usage.pem",
+ "src/crypto/x509/test/invalid_extension_root_name_constraints.pem",
+ "src/crypto/x509/test/invalid_extension_root_subject_alt_name.pem",
+ "src/crypto/x509/test/invalid_extension_root_subject_key_identifier.pem",
+ "src/crypto/x509/test/many_constraints.pem",
+ "src/crypto/x509/test/many_names1.pem",
+ "src/crypto/x509/test/many_names2.pem",
+ "src/crypto/x509/test/many_names3.pem",
+ "src/crypto/x509/test/some_names1.pem",
+ "src/crypto/x509/test/some_names2.pem",
+ "src/crypto/x509/test/some_names3.pem",
"src/third_party/wycheproof_testvectors/aes_cbc_pkcs5_test.txt",
"src/third_party/wycheproof_testvectors/aes_cmac_test.txt",
"src/third_party/wycheproof_testvectors/aes_gcm_siv_test.txt",
diff --git a/chromium/third_party/openscreen/src/util/BUILD.gn b/chromium/third_party/openscreen/src/util/BUILD.gn
index 3e915eb93c9..3f97e09e334 100644
--- a/chromium/third_party/openscreen/src/util/BUILD.gn
+++ b/chromium/third_party/openscreen/src/util/BUILD.gn
@@ -51,8 +51,6 @@ source_set("util") {
"json/json_serialization.h",
"json/json_value.cc",
"json/json_value.h",
- "operation_loop.cc",
- "operation_loop.h",
"osp_logging.h",
"saturate_cast.h",
"simple_fraction.cc",
@@ -101,6 +99,7 @@ source_set("unittests") {
"alarm_unittest.cc",
"base64_unittest.cc",
"big_endian_unittest.cc",
+ "crypto/certificate_utils_unittest.cc",
"crypto/random_bytes_unittest.cc",
"crypto/rsa_private_key_unittest.cc",
"crypto/secure_hash_unittest.cc",
@@ -111,7 +110,6 @@ source_set("unittests") {
"json/json_helpers_unittest.cc",
"json/json_serialization_unittest.cc",
"json/json_value_unittest.cc",
- "operation_loop_unittest.cc",
"saturate_cast_unittest.cc",
"simple_fraction_unittest.cc",
"stringprintf_unittest.cc",
@@ -127,12 +125,6 @@ source_set("unittests") {
sources += [ "trace_logging_unittest.cc" ]
}
- # TODO(http://issuetracker.google.com/159955844): test fails on fieldtrial
- # bot, needs to be diagnosed and reenabled in Chrome.
- if (!build_with_chromium) {
- sources += [ "crypto/certificate_utils_unittest.cc" ]
- }
-
deps = [
":util",
"../platform:test",
diff --git a/chromium/third_party/openscreen/src/util/base64.cc b/chromium/third_party/openscreen/src/util/base64.cc
index 06e120e06d2..64e34175c7d 100644
--- a/chromium/third_party/openscreen/src/util/base64.cc
+++ b/chromium/third_party/openscreen/src/util/base64.cc
@@ -6,6 +6,10 @@
#include <stddef.h>
+#include <string>
+#include <utility>
+#include <vector>
+
#include "third_party/modp_b64/modp_b64.h"
#include "util/osp_logging.h"
#include "util/std_util.h"
@@ -33,20 +37,18 @@ std::string Encode(absl::string_view input) {
return out;
}
-bool Decode(absl::string_view input, std::string* output) {
- std::string out;
- out.resize(modp_b64_decode_len(input.size()));
+bool Decode(absl::string_view input, std::vector<uint8_t>* output) {
+ std::vector<uint8_t> out(modp_b64_decode_len(input.size()));
- // We don't null terminate the result since it is binary data.
- const size_t output_size =
- modp_b64_decode(data(out), input.data(), input.size());
+ const size_t output_size = modp_b64_decode(
+ reinterpret_cast<char*>(out.data()), input.data(), input.size());
if (output_size == MODP_B64_ERROR) {
return false;
}
// The output size from decode_len is generally larger than needed.
out.resize(output_size);
- output->swap(out);
+ *output = std::move(out);
return true;
}
diff --git a/chromium/third_party/openscreen/src/util/base64.h b/chromium/third_party/openscreen/src/util/base64.h
index b24c3b3fc47..a7af9ecaa2b 100644
--- a/chromium/third_party/openscreen/src/util/base64.h
+++ b/chromium/third_party/openscreen/src/util/base64.h
@@ -6,6 +6,7 @@
#define UTIL_BASE64_H_
#include <string>
+#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
@@ -23,7 +24,7 @@ std::string Encode(absl::string_view input);
// Decodes the base64 input string. Returns true if successful and false
// otherwise. The output string is only modified if successful. The decoding can
// be done in-place.
-bool Decode(absl::string_view input, std::string* output);
+bool Decode(absl::string_view input, std::vector<uint8_t>* output);
} // namespace base64
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/base64_unittest.cc b/chromium/third_party/openscreen/src/util/base64_unittest.cc
index 28d4fb1dee2..873b5656e48 100644
--- a/chromium/third_party/openscreen/src/util/base64_unittest.cc
+++ b/chromium/third_party/openscreen/src/util/base64_unittest.cc
@@ -4,6 +4,9 @@
#include "util/base64.h"
+#include <string>
+#include <vector>
+
#include "gtest/gtest.h"
namespace openscreen {
@@ -14,13 +17,21 @@ namespace {
constexpr char kText[] = "hello world";
constexpr char kBase64Text[] = "aGVsbG8gd29ybGQ=";
+// More sophisticated comparisons here, such as EXPECT_STREQ, may
+// cause memory failures on some platforms (e.g. ASAN) due to mismatched
+// lengths.
+void CheckEquals(const char* expected, const std::vector<uint8_t>& actual) {
+ EXPECT_EQ(0, std::memcmp(actual.data(), expected, actual.size()));
+}
+
void CheckEncodeDecode(const char* to_encode, const char* encode_expected) {
std::string encoded = Encode(to_encode);
EXPECT_EQ(encode_expected, encoded);
- std::string decoded;
+ std::vector<uint8_t> decoded;
EXPECT_TRUE(Decode(encoded, &decoded));
- EXPECT_EQ(to_encode, decoded);
+
+ CheckEquals(to_encode, decoded);
}
} // namespace
@@ -52,8 +63,9 @@ TEST(Base64Test, InPlace) {
text = Encode(text);
EXPECT_EQ(kBase64Text, text);
- EXPECT_TRUE(Decode(text, &text));
- EXPECT_EQ(text, kText);
+ std::vector<uint8_t> out;
+ EXPECT_TRUE(Decode(text, &out));
+ CheckEquals(kText, out);
}
} // namespace base64
diff --git a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc
index a9b7d9adb0c..f5018042c98 100644
--- a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc
+++ b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.cc
@@ -218,25 +218,28 @@ ErrorOr<bssl::UniquePtr<EVP_PKEY>> ImportRSAPrivateKey(
}
std::string GetSpkiTlv(X509* cert) {
- int len = i2d_X509_PUBKEY(cert->cert_info->key, nullptr);
+ X509_PUBKEY* key = X509_get_X509_PUBKEY(cert);
+ int len = i2d_X509_PUBKEY(key, nullptr);
if (len <= 0) {
return {};
}
std::string x(len, 0);
uint8_t* data = reinterpret_cast<uint8_t*>(&x[0]);
- if (!i2d_X509_PUBKEY(cert->cert_info->key, &data)) {
+ if (!i2d_X509_PUBKEY(key, &data)) {
return {};
}
return x;
}
-ErrorOr<uint64_t> ParseDerUint64(ASN1_INTEGER* asn1int) {
- if (asn1int->length > 8 || asn1int->length == 0) {
+ErrorOr<uint64_t> ParseDerUint64(const ASN1_INTEGER* asn1int) {
+ const uint8_t* data = ASN1_STRING_get0_data(asn1int);
+ int length = ASN1_STRING_length(asn1int);
+ if (length > 8 || length <= 0) {
return Error::Code::kParameterInvalid;
}
uint64_t result = 0;
- for (int i = 0; i < asn1int->length; ++i) {
- result = (result << 8) | asn1int->data[i];
+ for (int i = 0; i < length; ++i) {
+ result = (result << 8) | data[i];
}
return result;
}
diff --git a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h
index 22da0330a0b..6d9a08fd35e 100644
--- a/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h
+++ b/chromium/third_party/openscreen/src/util/crypto/certificate_utils.h
@@ -52,7 +52,7 @@ ErrorOr<bssl::UniquePtr<EVP_PKEY>> ImportRSAPrivateKey(
std::string GetSpkiTlv(X509* cert);
-ErrorOr<uint64_t> ParseDerUint64(ASN1_INTEGER* asn1int);
+ErrorOr<uint64_t> ParseDerUint64(const ASN1_INTEGER* asn1int);
} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/operation_loop.cc b/chromium/third_party/openscreen/src/util/operation_loop.cc
deleted file mode 100644
index a20f1447c23..00000000000
--- a/chromium/third_party/openscreen/src/util/operation_loop.cc
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 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 "util/operation_loop.h"
-
-#include <algorithm>
-
-#include "util/osp_logging.h"
-
-namespace openscreen {
-
-OperationLoop::OperationLoop(std::vector<OperationWithTimeout> operations,
- Clock::duration timeout,
- Clock::duration min_loop_execution_time)
- : perform_all_operations_min_execution_time_(min_loop_execution_time),
- operation_timeout_(timeout),
- operations_(operations) {
- OSP_DCHECK(operations_.size());
-}
-
-void OperationLoop::RunUntilStopped() {
- OSP_CHECK(!is_running_.exchange(true));
-
- while (is_running_.load()) {
- PerformAllOperations();
- }
-}
-
-void OperationLoop::RequestStopSoon() {
- {
- std::unique_lock<std::mutex> lock(wait_mutex_);
- is_running_.store(false);
- }
-
- perform_all_operations_waiter_.notify_all();
-}
-
-void OperationLoop::PerformAllOperations() {
- auto start_time = Clock::now();
-
- for (OperationWithTimeout operation : operations_) {
- if (is_running_.load()) {
- operation(operation_timeout_);
- }
- }
-
- const auto duration = Clock::now() - start_time;
- const auto remaining_duration =
- perform_all_operations_min_execution_time_ - duration;
- if (remaining_duration > Clock::duration{0} && is_running_.load()) {
- std::unique_lock<std::mutex> lock(wait_mutex_);
- perform_all_operations_waiter_.wait_for(
- lock, remaining_duration, [this]() { return !is_running_.load(); });
- }
-}
-
-} // namespace openscreen
diff --git a/chromium/third_party/openscreen/src/util/operation_loop.h b/chromium/third_party/openscreen/src/util/operation_loop.h
deleted file mode 100644
index ddb7846f4be..00000000000
--- a/chromium/third_party/openscreen/src/util/operation_loop.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2019 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 UTIL_OPERATION_LOOP_H_
-#define UTIL_OPERATION_LOOP_H_
-
-#include <atomic>
-#include <condition_variable>
-#include <functional>
-#include <vector>
-
-#include "platform/api/time.h"
-#include "platform/base/macros.h"
-
-namespace openscreen {
-
-class OperationLoop {
- public:
- using OperationWithTimeout = std::function<void(Clock::duration)>;
-
- // Creates a new OperationLoop from a variable number of operations. The
- // provided functions will be called repeatedly, at a minimum interval equal
- // to min_loop_execution_time, and are expected to exit after the time period
- // provided to their call has passed. This is because some operations may not
- // be safe to be interrupted from this class.
- // NOTE: If n operations are provided with operation timeout T, each iteration
- // of the operation loop may take as long as n * T, and will not exit after
- // min_loop_execution_time has elapsed. In order to avoid this behavior, the
- // caller can set min_loop_execution_time = n * T.
- //
- // operations = Functions to execute repeatedly. All functions are expected to
- // be valid the duration of this object's lifetime.
- // timeout = Timeout for each individual function above.
- // min_loop_execution_time = Minimum time that OperationLoop should wait
- // before successive calls to members of the
- // provided operations vector.
- OperationLoop(std::vector<OperationWithTimeout> operations,
- Clock::duration timeout,
- Clock::duration min_loop_execution_time);
-
- // Runs the PerformAllOperations function in a loop until the below
- // RequestStopSoon function is called.
- void RunUntilStopped();
-
- // Signals for the RunUntilStopped loop to cease running.
- void RequestStopSoon();
-
- OSP_DISALLOW_COPY_AND_ASSIGN(OperationLoop);
-
- private:
- // Performs all operations which have been provided to this instance.
- void PerformAllOperations();
-
- const Clock::duration perform_all_operations_min_execution_time_;
-
- const Clock::duration operation_timeout_;
-
- // Used to wait in PerformAllOperations() if not enough time has elapsed.
- std::condition_variable perform_all_operations_waiter_;
-
- // Mutex used by the above condition_variable.
- std::mutex wait_mutex_;
-
- // Represents whether this instance is currently "running".
- std::atomic_bool is_running_{false};
-
- // Operations currently being run by this object.
- const std::vector<OperationWithTimeout> operations_;
-};
-
-} // namespace openscreen
-
-#endif // UTIL_OPERATION_LOOP_H_
diff --git a/chromium/third_party/openscreen/src/util/operation_loop_unittest.cc b/chromium/third_party/openscreen/src/util/operation_loop_unittest.cc
deleted file mode 100644
index 4b4ea5df671..00000000000
--- a/chromium/third_party/openscreen/src/util/operation_loop_unittest.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2019 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 "util/operation_loop.h"
-
-#include <atomic>
-#include <chrono>
-#include <thread>
-
-#include "gtest/gtest.h"
-
-namespace openscreen {
-
-TEST(OperationsLoopTest, PerformAllOperationsWaits) {
- constexpr Clock::duration kTimeout{0};
- constexpr Clock::duration kMinRuntime{500};
-
- const auto start_time = Clock::now();
- std::atomic<Clock::time_point> last_run{start_time};
- std::atomic<Clock::time_point> current_run{start_time};
- std::function<void(Clock::duration)> test_function =
- [last = &last_run, current = &current_run](Clock::duration timeout) {
- last->store(current->load());
- current->store(Clock::now());
- };
- OperationLoop loop({test_function}, kTimeout, kMinRuntime);
-
- std::thread run_loop([&loop]() { loop.RunUntilStopped(); });
-
- while (last_run.load() == start_time) {
- }
-
- loop.RequestStopSoon();
- run_loop.join();
-
- EXPECT_GE(
- std::chrono::nanoseconds(current_run.load() - last_run.load()).count(),
- std::chrono::nanoseconds(kMinRuntime).count());
-}
-
-} // namespace openscreen