aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cast/standalone_sender/BUILD.gn1
-rw-r--r--cast/standalone_sender/connection_settings.h48
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.cc8
-rw-r--r--cast/standalone_sender/looping_file_cast_agent.h24
-rw-r--r--cast/standalone_sender/looping_file_sender.cc37
-rw-r--r--cast/standalone_sender/looping_file_sender.h15
-rw-r--r--cast/standalone_sender/main.cc15
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;