5#ifndef SKYWAY_GLOBAL_UTIL_HPP_
6#define SKYWAY_GLOBAL_UTIL_HPP_
9#include <boost/archive/iterators/binary_from_base64.hpp>
10#include <boost/archive/iterators/transform_width.hpp>
11#include <boost/lexical_cast.hpp>
12#include <boost/uuid/uuid.hpp>
13#include <boost/uuid/uuid_generators.hpp>
14#include <boost/uuid/uuid_io.hpp>
15#include <condition_variable>
23#include "skyway/global/config.hpp"
24#include "skyway/model/domain.hpp"
31enum class SleepIntervalMs :
int {
32 kLocal = config::kLocalSleepIntervalMs,
33 kNetwork = config::kNetworkSleepIntervalMs,
36bool WaitUntilWithTimeoutMs(std::function<
bool()> release_condition,
40bool WaitUntilWithTimeoutMs(std::function<
bool()> release_condition,
41 SleepIntervalMs interval,
44bool WaitUntilWithTimeoutMs(std::atomic<bool>& release_condition_boolean,
48bool WaitUntilWithTimeoutMs(std::atomic<bool>& release_condition_boolean,
49 SleepIntervalMs interval,
55 explicit ScopeExit(std::function<
void()> on_exit) : on_exit_(on_exit) {}
63 std::function<void()> on_exit_;
71inline bool SpinLockWithTimeoutMs(std::function<
bool()> release_condition,
int timeout_ms) {
72 std::condition_variable cv;
74 std::unique_ptr<std::thread> observer_thread =
nullptr;
75 bool is_succeeded =
false;
77 std::unique_lock<std::mutex> lock(mtx);
79 auto is_notified = std::make_shared<bool>(
false);
80 auto result_returned = std::make_shared<std::atomic<bool>>(
false);
81 observer_thread = std::make_unique<std::thread>([&, result_returned, is_notified] {
82 while (!release_condition()) {
84 if (result_returned->load()) {
88 std::lock_guard<std::mutex> lk(mtx);
93 cv.wait_for(lock, std::chrono::milliseconds(timeout_ms), [&] {
return *is_notified; });
94 result_returned->store(
true);
96 observer_thread->join();
101inline bool SpinLockWithTimeoutMs(std::atomic<bool>& release_condition,
int timeout_ms) {
102 std::function<bool()> f = [&] {
return release_condition.load(); };
103 return SpinLockWithTimeoutMs(f, timeout_ms);
111inline bool SpinLockWithTimeout(std::function<
bool()> release_condition,
112 int timeout_sec = config::kDefaultTimeoutSec) {
113 return SpinLockWithTimeoutMs(release_condition, timeout_sec * 1000);
116inline bool SpinLockWithTimeout(std::atomic<bool>& release_condition,
117 int timeout_sec = config::kDefaultTimeoutSec) {
118 return SpinLockWithTimeoutMs(release_condition, timeout_sec * 1000);
121inline std::string Uuid() {
122 auto id = boost::uuids::random_generator()();
123 std::string result = boost::lexical_cast<std::string>(
id);
135inline std::vector<std::string> Split(
const std::string& s,
const std::string& delimiter) {
136 size_t pos_start = 0, pos_end, delim_len = delimiter.length();
138 std::vector<std::string> res;
140 while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) {
141 token = s.substr(pos_start, pos_end - pos_start);
142 pos_start = pos_end + delim_len;
143 res.push_back(token);
146 res.push_back(s.substr(pos_start));
150inline std::string DecodeBase64Token(
const std::string& token) {
151 using InputItr = std::istreambuf_iterator<char>;
152 using OutputItr = std::ostream_iterator<char>;
153 using DecodeItr = boost::archive::iterators::
154 transform_width<boost::archive::iterators::binary_from_base64<InputItr>, 8, 6,
char>;
156 std::stringstream input_stream, output_stream;
157 input_stream << token;
158 copy(DecodeItr(InputItr(input_stream)), DecodeItr(InputItr()), OutputItr(output_stream));
160 output_stream >> res;
164inline void SetEncodingIndexToIdIfNeeded(std::vector<model::Encoding>& encodings) {
165 for (
int i = 0; i < encodings.size(); i++) {
166 if (!encodings[i].
id) {
167 encodings[i].id = std::to_string(i);
172inline void SortEncodingsForMediaSoup(std::vector<model::Encoding>& encodings) {
173 if (encodings.empty())
return;
174 auto encoding = encodings[0];
175 if (encoding.max_bitrate) {
176 std::sort(encodings.begin(),
178 [](
const model::Encoding& lhs,
const model::Encoding& rhs) {
179 if (lhs.max_bitrate == std::nullopt || rhs.max_bitrate == std::nullopt) {
182 return *lhs.max_bitrate < *rhs.max_bitrate;
184 }
else if (encoding.scale_resolution_down_by) {
185 std::sort(encodings.begin(),
187 [](
const model::Encoding& lhs,
const model::Encoding& rhs) {
188 if (lhs.scale_resolution_down_by == std::nullopt ||
189 rhs.scale_resolution_down_by == std::nullopt) {
192 return *lhs.scale_resolution_down_by > *rhs.scale_resolution_down_by;
194 }
else if (encoding.max_framerate) {
195 std::sort(encodings.begin(),
197 [](
const model::Encoding& lhs,
const model::Encoding& rhs) {
198 if (lhs.max_framerate == std::nullopt || rhs.max_framerate == std::nullopt) {
201 return *lhs.max_framerate < *rhs.max_framerate;
206inline const std::chrono::milliseconds CurrentUnixTimestampMs() {
207 return std::chrono::duration_cast<std::chrono::milliseconds>(
208 std::chrono::system_clock::now().time_since_epoch());