xref: /aosp_15_r20/external/openscreen/cast/standalone_sender/receiver_chooser.cc (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #include "cast/standalone_sender/receiver_chooser.h"
6*3f982cf4SFabien Sanglard 
7*3f982cf4SFabien Sanglard #include <cstdint>
8*3f982cf4SFabien Sanglard #include <iostream>
9*3f982cf4SFabien Sanglard #include <string>
10*3f982cf4SFabien Sanglard #include <utility>
11*3f982cf4SFabien Sanglard 
12*3f982cf4SFabien Sanglard #include "discovery/common/config.h"
13*3f982cf4SFabien Sanglard #include "platform/api/time.h"
14*3f982cf4SFabien Sanglard #include "util/osp_logging.h"
15*3f982cf4SFabien Sanglard 
16*3f982cf4SFabien Sanglard namespace openscreen {
17*3f982cf4SFabien Sanglard namespace cast {
18*3f982cf4SFabien Sanglard 
19*3f982cf4SFabien Sanglard // NOTE: the compile requires a definition as well as the declaration
20*3f982cf4SFabien Sanglard // in the header.
21*3f982cf4SFabien Sanglard // TODO(issuetracker.google.com/174081818): move to inline C++17 feature.
22*3f982cf4SFabien Sanglard constexpr decltype(ReceiverChooser::kWaitForStragglersDelay)
23*3f982cf4SFabien Sanglard     ReceiverChooser::kWaitForStragglersDelay;
24*3f982cf4SFabien Sanglard 
ReceiverChooser(const InterfaceInfo & interface,TaskRunner * task_runner,ResultCallback result_callback)25*3f982cf4SFabien Sanglard ReceiverChooser::ReceiverChooser(const InterfaceInfo& interface,
26*3f982cf4SFabien Sanglard                                  TaskRunner* task_runner,
27*3f982cf4SFabien Sanglard                                  ResultCallback result_callback)
28*3f982cf4SFabien Sanglard     : result_callback_(std::move(result_callback)),
29*3f982cf4SFabien Sanglard       menu_alarm_(&Clock::now, task_runner) {
30*3f982cf4SFabien Sanglard   discovery::Config config{.network_info = {interface},
31*3f982cf4SFabien Sanglard                            .enable_publication = false,
32*3f982cf4SFabien Sanglard                            .enable_querying = true};
33*3f982cf4SFabien Sanglard   discovery::CreateDnsSdService(task_runner, this, std::move(config));
34*3f982cf4SFabien Sanglard 
35*3f982cf4SFabien Sanglard   watcher_ = std::make_unique<discovery::DnsSdServiceWatcher<ReceiverInfo>>(
36*3f982cf4SFabien Sanglard       service_.get(), kCastV2ServiceId, DnsSdInstanceEndpointToReceiverInfo,
37*3f982cf4SFabien Sanglard       [this](std::vector<std::reference_wrapper<const ReceiverInfo>> all) {
38*3f982cf4SFabien Sanglard         OnDnsWatcherUpdate(std::move(all));
39*3f982cf4SFabien Sanglard       });
40*3f982cf4SFabien Sanglard 
41*3f982cf4SFabien Sanglard   OSP_LOG_INFO << "Starting discovery. Note that it can take dozens of seconds "
42*3f982cf4SFabien Sanglard                   "to detect anything on some networks!";
43*3f982cf4SFabien Sanglard   task_runner->PostTask([this] { watcher_->StartDiscovery(); });
44*3f982cf4SFabien Sanglard }
45*3f982cf4SFabien Sanglard 
46*3f982cf4SFabien Sanglard ReceiverChooser::~ReceiverChooser() = default;
47*3f982cf4SFabien Sanglard 
OnFatalError(Error error)48*3f982cf4SFabien Sanglard void ReceiverChooser::OnFatalError(Error error) {
49*3f982cf4SFabien Sanglard   OSP_LOG_FATAL << "Fatal error: " << error;
50*3f982cf4SFabien Sanglard }
51*3f982cf4SFabien Sanglard 
OnRecoverableError(Error error)52*3f982cf4SFabien Sanglard void ReceiverChooser::OnRecoverableError(Error error) {
53*3f982cf4SFabien Sanglard   OSP_VLOG << "Recoverable error: " << error;
54*3f982cf4SFabien Sanglard }
55*3f982cf4SFabien Sanglard 
OnDnsWatcherUpdate(std::vector<std::reference_wrapper<const ReceiverInfo>> all)56*3f982cf4SFabien Sanglard void ReceiverChooser::OnDnsWatcherUpdate(
57*3f982cf4SFabien Sanglard     std::vector<std::reference_wrapper<const ReceiverInfo>> all) {
58*3f982cf4SFabien Sanglard   bool added_some = false;
59*3f982cf4SFabien Sanglard   for (const ReceiverInfo& info : all) {
60*3f982cf4SFabien Sanglard     if (!info.IsValid() || (!info.v4_address && !info.v6_address)) {
61*3f982cf4SFabien Sanglard       continue;
62*3f982cf4SFabien Sanglard     }
63*3f982cf4SFabien Sanglard     const std::string& instance_id = info.GetInstanceId();
64*3f982cf4SFabien Sanglard     if (std::any_of(discovered_receivers_.begin(), discovered_receivers_.end(),
65*3f982cf4SFabien Sanglard                     [&](const ReceiverInfo& known) {
66*3f982cf4SFabien Sanglard                       return known.GetInstanceId() == instance_id;
67*3f982cf4SFabien Sanglard                     })) {
68*3f982cf4SFabien Sanglard       continue;
69*3f982cf4SFabien Sanglard     }
70*3f982cf4SFabien Sanglard 
71*3f982cf4SFabien Sanglard     OSP_LOG_INFO << "Discovered: " << info.friendly_name
72*3f982cf4SFabien Sanglard                  << " (id: " << instance_id << ')';
73*3f982cf4SFabien Sanglard     discovered_receivers_.push_back(info);
74*3f982cf4SFabien Sanglard     added_some = true;
75*3f982cf4SFabien Sanglard   }
76*3f982cf4SFabien Sanglard 
77*3f982cf4SFabien Sanglard   if (added_some) {
78*3f982cf4SFabien Sanglard     menu_alarm_.ScheduleFromNow([this] { PrintMenuAndHandleChoice(); },
79*3f982cf4SFabien Sanglard                                 kWaitForStragglersDelay);
80*3f982cf4SFabien Sanglard   }
81*3f982cf4SFabien Sanglard }
82*3f982cf4SFabien Sanglard 
PrintMenuAndHandleChoice()83*3f982cf4SFabien Sanglard void ReceiverChooser::PrintMenuAndHandleChoice() {
84*3f982cf4SFabien Sanglard   if (!result_callback_) {
85*3f982cf4SFabien Sanglard     return;  // A choice has already been made.
86*3f982cf4SFabien Sanglard   }
87*3f982cf4SFabien Sanglard 
88*3f982cf4SFabien Sanglard   std::cout << '\n';
89*3f982cf4SFabien Sanglard   for (size_t i = 0; i < discovered_receivers_.size(); ++i) {
90*3f982cf4SFabien Sanglard     const ReceiverInfo& info = discovered_receivers_[i];
91*3f982cf4SFabien Sanglard     std::cout << '[' << i << "]: " << info.friendly_name << " @ ";
92*3f982cf4SFabien Sanglard     if (info.v6_address) {
93*3f982cf4SFabien Sanglard       std::cout << info.v6_address;
94*3f982cf4SFabien Sanglard     } else {
95*3f982cf4SFabien Sanglard       OSP_DCHECK(info.v4_address);
96*3f982cf4SFabien Sanglard       std::cout << info.v4_address;
97*3f982cf4SFabien Sanglard     }
98*3f982cf4SFabien Sanglard     std::cout << ':' << info.port << '\n';
99*3f982cf4SFabien Sanglard   }
100*3f982cf4SFabien Sanglard   std::cout << "\nEnter choice, or 'n' to wait longer: " << std::flush;
101*3f982cf4SFabien Sanglard 
102*3f982cf4SFabien Sanglard   int menu_choice = -1;
103*3f982cf4SFabien Sanglard   if (std::cin >> menu_choice || std::cin.eof()) {
104*3f982cf4SFabien Sanglard     const auto callback_on_stack = std::move(result_callback_);
105*3f982cf4SFabien Sanglard     if (menu_choice >= 0 &&
106*3f982cf4SFabien Sanglard         menu_choice < static_cast<int>(discovered_receivers_.size())) {
107*3f982cf4SFabien Sanglard       const ReceiverInfo& choice = discovered_receivers_[menu_choice];
108*3f982cf4SFabien Sanglard       if (choice.v6_address) {
109*3f982cf4SFabien Sanglard         callback_on_stack(IPEndpoint{choice.v6_address, choice.port});
110*3f982cf4SFabien Sanglard       } else {
111*3f982cf4SFabien Sanglard         callback_on_stack(IPEndpoint{choice.v4_address, choice.port});
112*3f982cf4SFabien Sanglard       }
113*3f982cf4SFabien Sanglard     } else {
114*3f982cf4SFabien Sanglard       callback_on_stack(IPEndpoint{});  // Signal "bad choice" or EOF.
115*3f982cf4SFabien Sanglard     }
116*3f982cf4SFabien Sanglard     return;
117*3f982cf4SFabien Sanglard   }
118*3f982cf4SFabien Sanglard 
119*3f982cf4SFabien Sanglard   // Clear bad input flag, and skip past what the user entered.
120*3f982cf4SFabien Sanglard   std::cin.clear();
121*3f982cf4SFabien Sanglard   std::string garbage;
122*3f982cf4SFabien Sanglard   std::getline(std::cin, garbage);
123*3f982cf4SFabien Sanglard }
124*3f982cf4SFabien Sanglard 
125*3f982cf4SFabien Sanglard }  // namespace cast
126*3f982cf4SFabien Sanglard }  // namespace openscreen
127