diff options
-rw-r--r-- | cast/standalone_sender/BUILD.gn | 1 | ||||
-rw-r--r-- | cast/standalone_sender/connection_settings.h | 48 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_cast_agent.cc | 8 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_cast_agent.h | 24 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_sender.cc | 37 | ||||
-rw-r--r-- | cast/standalone_sender/looping_file_sender.h | 15 | ||||
-rw-r--r-- | cast/standalone_sender/main.cc | 15 |
7 files changed, 99 insertions, 49 deletions
diff --git a/cast/standalone_sender/BUILD.gn b/cast/standalone_sender/BUILD.gn index d2d3619b..afa73d7d 100644 --- a/cast/standalone_sender/BUILD.gn +++ b/cast/standalone_sender/BUILD.gn @@ -40,6 +40,7 @@ if (!build_with_chromium) { libs = [] if (have_ffmpeg && have_libopus && have_libvpx) { sources += [ + "connection_settings.h", "ffmpeg_glue.cc", "ffmpeg_glue.h", "looping_file_cast_agent.cc", diff --git a/cast/standalone_sender/connection_settings.h b/cast/standalone_sender/connection_settings.h new file mode 100644 index 00000000..f42842c3 --- /dev/null +++ b/cast/standalone_sender/connection_settings.h @@ -0,0 +1,48 @@ +// 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_STANDALONE_SENDER_CONNECTION_SETTINGS_H_ +#define CAST_STANDALONE_SENDER_CONNECTION_SETTINGS_H_ + +#include <string> + +#include "platform/base/interface_info.h" + +namespace openscreen { +namespace cast { + +// The connection settings for a given standalone sender instance. These fields +// are used throughout the standalone sender component to initialize state from +// the command line parameters. +struct ConnectionSettings { + // The endpoint of the receiver we wish to connect to. + IPEndpoint receiver_endpoint; + + // The path to the file that we want to play. + std::string path_to_file; + + // The maximum bitrate. Default value means a reasonable default will be + // selected. + int max_bitrate = 0; + + // Whether the stream should include video, or just be audio only. + bool should_include_video = true; + + // Whether we should use the hacky RTP stream IDs for legacy android + // receivers, or if we should use the proper values. For more information, + // see https://issuetracker.google.com/184438154. + bool use_android_rtp_hack = true; + + // Whether we should use remoting for the video, instead of the default of + // mirroring. + bool use_remoting = false; + + // Whether we should loop the video when it is completed. + bool should_loop_video = true; +}; + +} // namespace cast +} // namespace openscreen + +#endif // CAST_STANDALONE_SENDER_CONNECTION_SETTINGS_H_ diff --git a/cast/standalone_sender/looping_file_cast_agent.cc b/cast/standalone_sender/looping_file_cast_agent.cc index 70d489de..ce9826de 100644 --- a/cast/standalone_sender/looping_file_cast_agent.cc +++ b/cast/standalone_sender/looping_file_cast_agent.cc @@ -291,8 +291,8 @@ void LoopingFileCastAgent::OnNegotiated( } file_sender_ = std::make_unique<LoopingFileSender>( - environment_.get(), connection_settings_->path_to_file.c_str(), session, - std::move(senders), connection_settings_->max_bitrate); + environment_.get(), connection_settings_.value(), session, + std::move(senders), [this]() { shutdown_callback_(); }); } void LoopingFileCastAgent::OnRemotingNegotiated( @@ -307,8 +307,8 @@ void LoopingFileCastAgent::OnRemotingNegotiated( } file_sender_ = std::make_unique<LoopingFileSender>( - environment_.get(), connection_settings_->path_to_file.c_str(), session, - std::move(negotiation.senders), connection_settings_->max_bitrate); + environment_.get(), connection_settings_.value(), session, + std::move(negotiation.senders), [this]() { shutdown_callback_(); }); } void LoopingFileCastAgent::OnError(const SenderSession* session, Error error) { diff --git a/cast/standalone_sender/looping_file_cast_agent.h b/cast/standalone_sender/looping_file_cast_agent.h index d1d6b6ce..cff0f6ba 100644 --- a/cast/standalone_sender/looping_file_cast_agent.h +++ b/cast/standalone_sender/looping_file_cast_agent.h @@ -19,6 +19,7 @@ #include "cast/common/channel/virtual_connection_router.h" #include "cast/common/public/cast_socket.h" #include "cast/sender/public/sender_socket_factory.h" +#include "cast/standalone_sender/connection_settings.h" #include "cast/standalone_sender/looping_file_sender.h" #include "cast/streaming/environment.h" #include "cast/streaming/sender_session.h" @@ -78,29 +79,6 @@ class LoopingFileCastAgent final ShutdownCallback shutdown_callback); ~LoopingFileCastAgent(); - struct ConnectionSettings { - // The endpoint of the receiver we wish to connect to. - IPEndpoint receiver_endpoint; - - // The path to the file that we want to play. - std::string path_to_file; - - // The maximum bitrate. Default value means a reasonable default will be - // selected. - int max_bitrate = 0; - - // Whether the stream should include video, or just be audio only. - bool should_include_video = true; - - // Whether we should use the hacky RTP stream IDs for legacy android - // receivers, or if we should use the proper values. - bool use_android_rtp_hack = true; - - // Whether we should use remoting for the video, instead of the default of - // mirroring. - bool use_remoting = false; - }; - // Connect to a Cast Receiver, and start the workflow to establish a // mirroring/streaming session. Destroy the LoopingFileCastAgent to shutdown // and disconnect. diff --git a/cast/standalone_sender/looping_file_sender.cc b/cast/standalone_sender/looping_file_sender.cc index c66722f5..1392c413 100644 --- a/cast/standalone_sender/looping_file_sender.cc +++ b/cast/standalone_sender/looping_file_sender.cc @@ -4,20 +4,22 @@ #include "cast/standalone_sender/looping_file_sender.h" +#include <utility> + #include "util/trace_logging.h" namespace openscreen { namespace cast { LoopingFileSender::LoopingFileSender(Environment* environment, - const char* path, + ConnectionSettings settings, const SenderSession* session, SenderSession::ConfiguredSenders senders, - int max_bitrate) + ShutdownCallback shutdown_callback) : env_(environment), - path_(path), + settings_(std::move(settings)), session_(session), - max_bitrate_(max_bitrate), + shutdown_callback_(std::move(shutdown_callback)), audio_encoder_(senders.audio_sender->config().channels, StreamingOpusEncoder::kDefaultCastAudioFramesPerSecond, senders.audio_sender), @@ -32,8 +34,8 @@ LoopingFileSender::LoopingFileSender(Environment* environment, OSP_CHECK(senders.audio_config.codec == AudioCodec::kOpus); OSP_CHECK(senders.video_config.codec == VideoCodec::kVp8); OSP_LOG_INFO << "Max allowed media bitrate (audio + video) will be " - << max_bitrate_; - bandwidth_being_utilized_ = max_bitrate_ / 2; + << settings_.max_bitrate; + bandwidth_being_utilized_ = settings_.max_bitrate / 2; UpdateEncoderBitrates(); next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately); @@ -72,7 +74,7 @@ void LoopingFileSender::ControlForNetworkCongestion() { // Repsect the user's maximum bitrate setting. bandwidth_being_utilized_ = - std::min(bandwidth_being_utilized_, max_bitrate_); + std::min(bandwidth_being_utilized_, settings_.max_bitrate); UpdateEncoderBitrates(); } else { @@ -84,16 +86,18 @@ void LoopingFileSender::ControlForNetworkCongestion() { } void LoopingFileSender::SendFileAgain() { - OSP_LOG_INFO << "Sending " << path_ << " (starts in one second)..."; + OSP_LOG_INFO << "Sending " << settings_.path_to_file + << " (starts in one second)..."; TRACE_DEFAULT_SCOPED(TraceCategory::kStandaloneSender); OSP_DCHECK_EQ(num_capturers_running_, 0); num_capturers_running_ = 2; capture_start_time_ = latest_frame_time_ = env_->now() + seconds(1); - audio_capturer_.emplace(env_, path_, audio_encoder_.num_channels(), - audio_encoder_.sample_rate(), capture_start_time_, - this); - video_capturer_.emplace(env_, path_, capture_start_time_, this); + audio_capturer_.emplace( + env_, settings_.path_to_file.c_str(), audio_encoder_.num_channels(), + audio_encoder_.sample_rate(), capture_start_time_, this); + video_capturer_.emplace(env_, settings_.path_to_file.c_str(), + capture_start_time_, this); next_task_.ScheduleFromNow([this] { ControlForNetworkCongestion(); }, kCongestionCheckInterval); @@ -156,7 +160,14 @@ void LoopingFileSender::OnEndOfFile(SimulatedCapturer* capturer) { --num_capturers_running_; if (num_capturers_running_ == 0) { console_update_task_.Cancel(); - next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately); + + if (settings_.should_loop_video) { + OSP_DLOG_INFO << "Starting the media stream over again."; + next_task_.Schedule([this] { SendFileAgain(); }, Alarm::kImmediately); + } else { + OSP_DLOG_INFO << "Video complete. Exiting..."; + shutdown_callback_(); + } } } diff --git a/cast/standalone_sender/looping_file_sender.h b/cast/standalone_sender/looping_file_sender.h index e55a4a7e..ef283dc3 100644 --- a/cast/standalone_sender/looping_file_sender.h +++ b/cast/standalone_sender/looping_file_sender.h @@ -8,6 +8,7 @@ #include <algorithm> #include <string> +#include "cast/standalone_sender/connection_settings.h" #include "cast/standalone_sender/constants.h" #include "cast/standalone_sender/simulated_capturer.h" #include "cast/standalone_sender/streaming_opus_encoder.h" @@ -22,11 +23,13 @@ namespace cast { class LoopingFileSender final : public SimulatedAudioCapturer::Client, public SimulatedVideoCapturer::Client { public: + using ShutdownCallback = std::function<void()>; + LoopingFileSender(Environment* environment, - const char* path, + ConnectionSettings settings, const SenderSession* session, SenderSession::ConfiguredSenders senders, - int max_bitrate); + ShutdownCallback shutdown_callback); ~LoopingFileSender() final; @@ -57,14 +60,14 @@ class LoopingFileSender final : public SimulatedAudioCapturer::Client, // the remote's Receivers. Environment* const env_; - // The path to the media file to stream over and over. - const char* const path_; + // The connection settings used for this session. + const ConnectionSettings settings_; // Session to query for bandwidth information. const SenderSession* session_; - // User provided maximum bitrate (from command line argument). - const int max_bitrate_; + // Callback for tearing down the sender process. + ShutdownCallback shutdown_callback_; int bandwidth_estimate_ = 0; int bandwidth_being_utilized_; diff --git a/cast/standalone_sender/main.cc b/cast/standalone_sender/main.cc index dd606c00..b7757d97 100644 --- a/cast/standalone_sender/main.cc +++ b/cast/standalone_sender/main.cc @@ -54,6 +54,10 @@ usage: %s <options> addr[:port] media_file Specifies the maximum bits per second for the media streams. Default if not set: %d + + -n, --no-looping + Disable looping the passed in video after it finishes playing. + )" #if defined(CAST_ALLOW_DEVELOPER_CERTIFICATE) R"( @@ -109,6 +113,7 @@ int StandaloneSenderMain(int argc, char* argv[]) { // standalone sender, osp demo, and test_main argument options. const struct option kArgumentOptions[] = { {"max-bitrate", required_argument, nullptr, 'm'}, + {"no-looping", no_argument, nullptr, 'n'}, #if defined(CAST_ALLOW_DEVELOPER_CERTIFICATE) {"developer-certificate", required_argument, nullptr, 'd'}, #endif @@ -120,14 +125,15 @@ int StandaloneSenderMain(int argc, char* argv[]) { {nullptr, 0, nullptr, 0} }; - bool is_verbose = false; + int max_bitrate = kDefaultMaxBitrate; + bool should_loop_video = true; std::string developer_certificate_path; bool use_android_rtp_hack = false; bool use_remoting = false; - int max_bitrate = kDefaultMaxBitrate; + bool is_verbose = false; std::unique_ptr<TextTraceLoggingPlatform> trace_logger; int ch = -1; - while ((ch = getopt_long(argc, argv, "m:d:artvh", kArgumentOptions, + while ((ch = getopt_long(argc, argv, "m:nd:artvh", kArgumentOptions, nullptr)) != -1) { switch (ch) { case 'm': @@ -139,6 +145,9 @@ int StandaloneSenderMain(int argc, char* argv[]) { return 1; } break; + case 'n': + should_loop_video = false; + break; #if defined(CAST_ALLOW_DEVELOPER_CERTIFICATE) case 'd': developer_certificate_path = optarg; |