 Chromium Code Reviews
 Chromium Code Reviews Issue 2113783002:
  Refactoring: Merge VideoSenderConfig and AudioSenderConfig.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 2113783002:
  Refactoring: Merge VideoSenderConfig and AudioSenderConfig.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| Index: chrome/renderer/media/cast_rtp_stream.cc | 
| diff --git a/chrome/renderer/media/cast_rtp_stream.cc b/chrome/renderer/media/cast_rtp_stream.cc | 
| index 53e46fea9317cf48b27548e929179d6bc0afb74b..81609f7e7abed41fe127559080cf867fdf8f45bc 100644 | 
| --- a/chrome/renderer/media/cast_rtp_stream.cc | 
| +++ b/chrome/renderer/media/cast_rtp_stream.cc | 
| @@ -19,7 +19,6 @@ | 
| #include "base/memory/ref_counted.h" | 
| #include "base/memory/weak_ptr.h" | 
| #include "base/strings/stringprintf.h" | 
| -#include "base/sys_info.h" | 
| #include "base/threading/thread_task_runner_handle.h" | 
| #include "base/timer/timer.h" | 
| #include "base/trace_event/trace_event.h" | 
| @@ -44,18 +43,10 @@ | 
| #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" | 
| #include "ui/gfx/geometry/size.h" | 
| -using media::cast::AudioSenderConfig; | 
| -using media::cast::VideoSenderConfig; | 
| +using media::cast::FrameSenderConfig; | 
| namespace { | 
| -const char kCodecNameOpus[] = "OPUS"; | 
| -const char kCodecNameVp8[] = "VP8"; | 
| -const char kCodecNameH264[] = "H264"; | 
| - | 
| -// To convert from kilobits per second to bits to per second. | 
| -const int kBitrateMultiplier = 1000; | 
| - | 
| // The maximum number of milliseconds that should elapse since the last video | 
| // frame was received from the video source, before requesting refresh frames. | 
| const int kRefreshIntervalMilliseconds = 250; | 
| @@ -64,253 +55,75 @@ const int kRefreshIntervalMilliseconds = 250; | 
| // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made. | 
| const int kMaxConsecutiveRefreshFrames = 60; | 
| -CastRtpPayloadParams DefaultOpusPayload() { | 
| - CastRtpPayloadParams payload; | 
| - payload.payload_type = media::cast::kDefaultRtpAudioPayloadType; | 
| - payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 
| - payload.ssrc = 1; | 
| - payload.feedback_ssrc = 2; | 
| - payload.clock_rate = media::cast::kDefaultAudioSamplingRate; | 
| +FrameSenderConfig DefaultOpusConfig() { | 
| + FrameSenderConfig config; | 
| + config.rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; | 
| + config.max_playout_delay = | 
| + base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); | 
| + config.sender_ssrc = 1; | 
| + config.receiver_ssrc = 2; | 
| + config.frequency = media::cast::kDefaultAudioSamplingRate; | 
| // The value is 0 which means VBR. | 
| - payload.min_bitrate = payload.max_bitrate = | 
| + config.min_bitrate = config.max_bitrate = | 
| 
miu
2016/06/30 21:59:43
and start_bitrate (per comment in cast_config.h)
 
xjz
2016/07/01 23:52:09
Done.
 | 
| media::cast::kDefaultAudioEncoderBitrate; | 
| - payload.channels = 2; | 
| - payload.max_frame_rate = 100; // 10 ms audio frames | 
| - payload.codec_name = kCodecNameOpus; | 
| - return payload; | 
| -} | 
| - | 
| -CastRtpPayloadParams DefaultVp8Payload() { | 
| - CastRtpPayloadParams payload; | 
| - payload.payload_type = media::cast::kDefaultRtpVideoPayloadType; | 
| - payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 
| - payload.ssrc = 11; | 
| - payload.feedback_ssrc = 12; | 
| - payload.clock_rate = media::cast::kVideoFrequency; | 
| - payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 
| - payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 
| - payload.channels = 1; | 
| - payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 
| - payload.codec_name = kCodecNameVp8; | 
| - return payload; | 
| -} | 
| - | 
| -CastRtpPayloadParams DefaultH264Payload() { | 
| - CastRtpPayloadParams payload; | 
| - payload.payload_type = 96; | 
| - payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; | 
| - payload.ssrc = 11; | 
| - payload.feedback_ssrc = 12; | 
| - payload.clock_rate = media::cast::kVideoFrequency; | 
| - payload.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 
| - payload.min_bitrate = media::cast::kDefaultMinVideoKbps; | 
| - payload.channels = 1; | 
| - payload.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 
| - payload.codec_name = kCodecNameH264; | 
| - return payload; | 
| -} | 
| - | 
| -bool IsHardwareVP8EncodingSupported() { | 
| - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 
| - if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 
| - DVLOG(1) << "Disabled hardware VP8 support for Cast Streaming."; | 
| - return false; | 
| - } | 
| - | 
| - // Query for hardware VP8 encoder support. | 
| - const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 
| - vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | 
| - for (const auto& vea_profile : vea_profiles) { | 
| - if (vea_profile.profile >= media::VP8PROFILE_MIN && | 
| - vea_profile.profile <= media::VP8PROFILE_MAX) { | 
| - return true; | 
| - } | 
| - } | 
| - return false; | 
| + config.channels = 2; | 
| + config.max_frame_rate = 100; // 10 ms audio frames | 
| + config.codec = media::cast::CODEC_AUDIO_OPUS; | 
| + return config; | 
| } | 
| -bool IsHardwareH264EncodingSupported() { | 
| - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 
| - if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 
| - DVLOG(1) << "Disabled hardware h264 support for Cast Streaming."; | 
| - return false; | 
| - } | 
| - | 
| - // Query for hardware H.264 encoder support. | 
| - // | 
| - // TODO(miu): Look into why H.264 hardware encoder on MacOS is broken. | 
| - // http://crbug.com/596674 | 
| -#if !defined(OS_MACOSX) | 
| - const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 
| - vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | 
| - for (const auto& vea_profile : vea_profiles) { | 
| - if (vea_profile.profile >= media::H264PROFILE_MIN && | 
| - vea_profile.profile <= media::H264PROFILE_MAX) { | 
| - return true; | 
| - } | 
| - } | 
| -#endif // !defined(OS_MACOSX) | 
| - return false; | 
| +FrameSenderConfig DefaultVp8Config() { | 
| + FrameSenderConfig config; | 
| + config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; | 
| + config.max_playout_delay = | 
| 
miu
2016/06/30 21:59:42
You could omit this, since we set this default in
 
xjz
2016/07/01 23:52:09
Done.
 | 
| + base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); | 
| + config.sender_ssrc = 11; | 
| + config.receiver_ssrc = 12; | 
| + config.frequency = media::cast::kVideoFrequency; | 
| + config.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 
| + config.min_bitrate = media::cast::kDefaultMinVideoKbps; | 
| + config.channels = 1; | 
| 
miu
2016/06/30 21:59:43
nit: Can you move this to be just before max_bitra
 
xjz
2016/07/01 23:52:09
Done.
 | 
| + config.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 
| + config.codec = media::cast::CODEC_VIDEO_VP8; | 
| + return config; | 
| } | 
| -int NumberOfEncodeThreads() { | 
| - // Do not saturate CPU utilization just for encoding. On a lower-end system | 
| - // with only 1 or 2 cores, use only one thread for encoding. On systems with | 
| - // more cores, allow half of the cores to be used for encoding. | 
| - return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); | 
| +FrameSenderConfig DefaultH264Config() { | 
| + FrameSenderConfig config; | 
| + config.rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; | 
| + config.max_playout_delay = | 
| + base::TimeDelta::FromMilliseconds(media::cast::kDefaultRtpMaxDelayMs); | 
| + config.sender_ssrc = 11; | 
| + config.receiver_ssrc = 12; | 
| + config.frequency = media::cast::kVideoFrequency; | 
| + config.max_bitrate = media::cast::kDefaultMaxVideoKbps; | 
| + config.min_bitrate = media::cast::kDefaultMinVideoKbps; | 
| + config.channels = 1; | 
| + config.max_frame_rate = media::cast::kDefaultMaxFrameRate; | 
| + config.codec = media::cast::CODEC_VIDEO_H264; | 
| + return config; | 
| } | 
| -std::vector<CastRtpParams> SupportedAudioParams() { | 
| +std::vector<FrameSenderConfig> SupportedAudioConfigs() { | 
| // TODO(hclam): Fill in more codecs here. | 
| - return std::vector<CastRtpParams>(1, CastRtpParams(DefaultOpusPayload())); | 
| + return std::vector<FrameSenderConfig>(1, DefaultOpusConfig()); | 
| } | 
| -std::vector<CastRtpParams> SupportedVideoParams() { | 
| - std::vector<CastRtpParams> supported_params; | 
| +std::vector<FrameSenderConfig> SupportedVideoConfigs() { | 
| + std::vector<FrameSenderConfig> supported_configs; | 
| // Prefer VP8 over H.264 for hardware encoder. | 
| - if (IsHardwareVP8EncodingSupported()) | 
| - supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 
| - if (IsHardwareH264EncodingSupported()) | 
| - supported_params.push_back(CastRtpParams(DefaultH264Payload())); | 
| + if (CastRtpStream::IsHardwareVP8EncodingSupported()) | 
| + supported_configs.push_back(DefaultVp8Config()); | 
| + if (CastRtpStream::IsHardwareH264EncodingSupported()) | 
| + supported_configs.push_back(DefaultH264Config()); | 
| // Propose the default software VP8 encoder, if no hardware encoders are | 
| // available. | 
| - if (supported_params.empty()) | 
| - supported_params.push_back(CastRtpParams(DefaultVp8Payload())); | 
| + if (supported_configs.empty()) | 
| + supported_configs.push_back(DefaultVp8Config()); | 
| - return supported_params; | 
| -} | 
| - | 
| -bool ToAudioSenderConfig(const CastRtpParams& params, | 
| - AudioSenderConfig* config) { | 
| - config->ssrc = params.payload.ssrc; | 
| - config->receiver_ssrc = params.payload.feedback_ssrc; | 
| - if (config->ssrc == config->receiver_ssrc) { | 
| - DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc"; | 
| - return false; | 
| - } | 
| - config->min_playout_delay = base::TimeDelta::FromMilliseconds( | 
| - params.payload.min_latency_ms ? | 
| - params.payload.min_latency_ms : | 
| - params.payload.max_latency_ms); | 
| - config->max_playout_delay = | 
| - base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms); | 
| - config->animated_playout_delay = base::TimeDelta::FromMilliseconds( | 
| - params.payload.animated_latency_ms ? params.payload.animated_latency_ms | 
| - : params.payload.max_latency_ms); | 
| - if (config->min_playout_delay <= base::TimeDelta()) { | 
| - DVLOG(1) << "min_playout_delay " << config->min_playout_delay | 
| - << " is too small"; | 
| - return false; | 
| - } | 
| - if (config->min_playout_delay > config->max_playout_delay) { | 
| - DVLOG(1) << "min_playout_delay " << config->min_playout_delay | 
| - << " is too big"; | 
| - return false; | 
| - } | 
| - if (config->animated_playout_delay < config->min_playout_delay || | 
| - config->animated_playout_delay > config->max_playout_delay) { | 
| - DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay | 
| - << " is out of range"; | 
| - return false; | 
| - } | 
| - config->rtp_payload_type = params.payload.payload_type; | 
| - config->use_external_encoder = false; | 
| - config->frequency = params.payload.clock_rate; | 
| - // Sampling rate must be one of the Opus-supported values. | 
| - switch (config->frequency) { | 
| - case 48000: | 
| - case 24000: | 
| - case 16000: | 
| - case 12000: | 
| - case 8000: | 
| - break; | 
| - default: | 
| - DVLOG(1) << "frequency " << config->frequency << " is invalid"; | 
| - return false; | 
| - } | 
| - config->channels = params.payload.channels; | 
| - if (config->channels < 1) { | 
| - DVLOG(1) << "channels " << config->channels << " is invalid"; | 
| - return false; | 
| - } | 
| - config->bitrate = params.payload.max_bitrate * kBitrateMultiplier; | 
| - if (params.payload.codec_name == kCodecNameOpus) { | 
| - config->codec = media::cast::CODEC_AUDIO_OPUS; | 
| - } else { | 
| - DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid"; | 
| - return false; | 
| - } | 
| - config->aes_key = params.payload.aes_key; | 
| - config->aes_iv_mask = params.payload.aes_iv_mask; | 
| - return true; | 
| -} | 
| - | 
| -bool ToVideoSenderConfig(const CastRtpParams& params, | 
| - VideoSenderConfig* config) { | 
| - config->ssrc = params.payload.ssrc; | 
| - config->receiver_ssrc = params.payload.feedback_ssrc; | 
| - if (config->ssrc == config->receiver_ssrc) { | 
| - DVLOG(1) << "ssrc " << config->ssrc << " cannot be equal to receiver_ssrc"; | 
| - return false; | 
| - } | 
| - config->min_playout_delay = base::TimeDelta::FromMilliseconds( | 
| - params.payload.min_latency_ms ? | 
| - params.payload.min_latency_ms : | 
| - params.payload.max_latency_ms); | 
| - config->max_playout_delay = | 
| - base::TimeDelta::FromMilliseconds(params.payload.max_latency_ms); | 
| - config->animated_playout_delay = base::TimeDelta::FromMilliseconds( | 
| - params.payload.animated_latency_ms ? params.payload.animated_latency_ms | 
| - : params.payload.max_latency_ms); | 
| - if (config->min_playout_delay <= base::TimeDelta()) { | 
| - DVLOG(1) << "min_playout_delay " << config->min_playout_delay | 
| - << " is too small"; | 
| - return false; | 
| - } | 
| - if (config->min_playout_delay > config->max_playout_delay) { | 
| - DVLOG(1) << "min_playout_delay " << config->min_playout_delay | 
| - << " is too big"; | 
| - return false; | 
| - } | 
| - if (config->animated_playout_delay < config->min_playout_delay || | 
| - config->animated_playout_delay > config->max_playout_delay) { | 
| - DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay | 
| - << " is out of range"; | 
| - return false; | 
| - } | 
| - config->rtp_payload_type = params.payload.payload_type; | 
| - config->min_bitrate = config->start_bitrate = | 
| - params.payload.min_bitrate * kBitrateMultiplier; | 
| - config->max_bitrate = params.payload.max_bitrate * kBitrateMultiplier; | 
| - if (config->min_bitrate > config->max_bitrate) { | 
| - DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than " | 
| - << "max_bitrate " << config->max_bitrate; | 
| - return false; | 
| - } | 
| - config->start_bitrate = config->min_bitrate; | 
| - config->max_frame_rate = static_cast<int>( | 
| - std::max(1.0, params.payload.max_frame_rate) + 0.5); | 
| - if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) { | 
| - DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid"; | 
| - return false; | 
| - } | 
| - if (params.payload.codec_name == kCodecNameVp8) { | 
| - config->use_external_encoder = IsHardwareVP8EncodingSupported(); | 
| - config->codec = media::cast::CODEC_VIDEO_VP8; | 
| - } else if (params.payload.codec_name == kCodecNameH264) { | 
| - config->use_external_encoder = IsHardwareH264EncodingSupported(); | 
| - config->codec = media::cast::CODEC_VIDEO_H264; | 
| - } else { | 
| - DVLOG(1) << "codec_name " << params.payload.codec_name << " is invalid"; | 
| - return false; | 
| - } | 
| - if (!config->use_external_encoder) | 
| - config->number_of_encode_threads = NumberOfEncodeThreads(); | 
| - config->aes_key = params.payload.aes_key; | 
| - config->aes_iv_mask = params.payload.aes_iv_mask; | 
| - return true; | 
| + return supported_configs; | 
| } | 
| } // namespace | 
| @@ -595,36 +408,48 @@ class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, | 
| DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 
| }; | 
| -CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 
| - : payload(payload_params) {} | 
| - | 
| -CastCodecSpecificParams::CastCodecSpecificParams() {} | 
| - | 
| -CastCodecSpecificParams::~CastCodecSpecificParams() {} | 
| +bool CastRtpStream::IsHardwareVP8EncodingSupported() { | 
| + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 
| + if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 
| + DVLOG(1) << "Disabled hardware VP8 support for Cast Streaming."; | 
| + return false; | 
| + } | 
| -CastRtpPayloadParams::CastRtpPayloadParams() | 
| - : payload_type(0), | 
| - max_latency_ms(0), | 
| - min_latency_ms(0), | 
| - ssrc(0), | 
| - feedback_ssrc(0), | 
| - clock_rate(0), | 
| - max_bitrate(0), | 
| - min_bitrate(0), | 
| - channels(0), | 
| - max_frame_rate(0.0) { | 
| + // Query for hardware VP8 encoder support. | 
| + const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 
| + vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | 
| + for (const auto& vea_profile : vea_profiles) { | 
| + if (vea_profile.profile >= media::VP8PROFILE_MIN && | 
| + vea_profile.profile <= media::VP8PROFILE_MAX) { | 
| + return true; | 
| + } | 
| + } | 
| + return false; | 
| } | 
| -CastRtpPayloadParams::CastRtpPayloadParams(const CastRtpPayloadParams& other) = | 
| - default; | 
| - | 
| -CastRtpPayloadParams::~CastRtpPayloadParams() {} | 
| - | 
| -CastRtpParams::CastRtpParams() {} | 
| - | 
| -CastRtpParams::CastRtpParams(const CastRtpParams& other) = default; | 
| +bool CastRtpStream::IsHardwareH264EncodingSupported() { | 
| + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 
| + if (cmd_line->HasSwitch(switches::kDisableCastStreamingHWEncoding)) { | 
| + DVLOG(1) << "Disabled hardware h264 support for Cast Streaming."; | 
| + return false; | 
| + } | 
| -CastRtpParams::~CastRtpParams() {} | 
| +// Query for hardware H.264 encoder support. | 
| +// | 
| +// TODO(miu): Look into why H.264 hardware encoder on MacOS is broken. | 
| +// http://crbug.com/596674 | 
| +#if !defined(OS_MACOSX) | 
| + const std::vector<media::VideoEncodeAccelerator::SupportedProfile> | 
| + vea_profiles = content::GetSupportedVideoEncodeAcceleratorProfiles(); | 
| + for (const auto& vea_profile : vea_profiles) { | 
| + if (vea_profile.profile >= media::H264PROFILE_MIN && | 
| + vea_profile.profile <= media::H264PROFILE_MAX) { | 
| + return true; | 
| + } | 
| + } | 
| +#endif // !defined(OS_MACOSX) | 
| + return false; | 
| +} | 
| CastRtpStream::CastRtpStream(const blink::WebMediaStreamTrack& track, | 
| const scoped_refptr<CastSession>& session) | 
| @@ -634,16 +459,14 @@ CastRtpStream::~CastRtpStream() { | 
| Stop(); | 
| } | 
| -std::vector<CastRtpParams> CastRtpStream::GetSupportedParams() { | 
| +std::vector<FrameSenderConfig> CastRtpStream::GetSupportedConfigs() { | 
| if (IsAudio()) | 
| - return SupportedAudioParams(); | 
| + return SupportedAudioConfigs(); | 
| else | 
| - return SupportedVideoParams(); | 
| + return SupportedVideoConfigs(); | 
| } | 
| -CastRtpParams CastRtpStream::GetParams() { return params_; } | 
| - | 
| -void CastRtpStream::Start(const CastRtpParams& params, | 
| +void CastRtpStream::Start(const FrameSenderConfig& config, | 
| const base::Closure& start_callback, | 
| const base::Closure& stop_callback, | 
| const ErrorCallback& error_callback) { | 
| @@ -656,18 +479,10 @@ void CastRtpStream::Start(const CastRtpParams& params, | 
| error_callback_ = error_callback; | 
| if (IsAudio()) { | 
| - AudioSenderConfig config; | 
| - if (!ToAudioSenderConfig(params, &config)) { | 
| - DidEncounterError("Invalid parameters for audio."); | 
| - return; | 
| - } | 
| - | 
| // In case of error we have to go through DidEncounterError() to stop | 
| // the streaming after reporting the error. | 
| - audio_sink_.reset(new CastAudioSink( | 
| - track_, | 
| - params.payload.channels, | 
| - params.payload.clock_rate)); | 
| + audio_sink_.reset( | 
| + new CastAudioSink(track_, config.channels, config.frequency)); | 
| cast_session_->StartAudio( | 
| config, | 
| base::Bind(&CastAudioSink::AddToTrack, audio_sink_->AsWeakPtr()), | 
| @@ -675,11 +490,6 @@ void CastRtpStream::Start(const CastRtpParams& params, | 
| weak_factory_.GetWeakPtr())); | 
| start_callback.Run(); | 
| } else { | 
| - VideoSenderConfig config; | 
| - if (!ToVideoSenderConfig(params, &config)) { | 
| - DidEncounterError("Invalid parameters for video."); | 
| - return; | 
| - } | 
| // See the code for audio above for explanation of callbacks. | 
| video_sink_.reset(new CastVideoSink( | 
| track_, | 
| @@ -687,7 +497,7 @@ void CastRtpStream::Start(const CastRtpParams& params, | 
| weak_factory_.GetWeakPtr())))); | 
| cast_session_->StartVideo( | 
| config, base::Bind(&CastVideoSink::AddToTrack, video_sink_->AsWeakPtr(), | 
| - !params.payload.aes_key.empty()), | 
| + !config.aes_key.empty()), | 
| base::Bind(&CastRtpStream::DidEncounterError, | 
| weak_factory_.GetWeakPtr())); | 
| start_callback.Run(); |