diff --git a/basic_room/capture_utils.cpp b/basic_room/capture_utils.cpp index 08497b0..0a13925 100644 --- a/basic_room/capture_utils.cpp +++ b/basic_room/capture_utils.cpp @@ -29,8 +29,7 @@ using namespace livekit; // Test utils to run a capture loop to publish noisy audio frames to the room -void runNoiseCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag) { +void runNoiseCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag) { const int sample_rate = source->sample_rate(); const int num_channels = source->num_channels(); const int frame_ms = 10; @@ -44,16 +43,15 @@ void runNoiseCaptureLoop(const std::shared_ptr &source, auto next_deadline = Clock::now(); while (running_flag.load(std::memory_order_relaxed)) { - AudioFrame frame = - AudioFrame::create(sample_rate, num_channels, samples_per_channel); - auto &pcm = frame.data(); - for (auto &s : pcm) { + AudioFrame frame = AudioFrame::create(sample_rate, num_channels, samples_per_channel); + auto& pcm = frame.data(); + for (auto& s : pcm) { s = static_cast(dist(rng)); } try { source->captureFrame(frame); - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Error in captureFrame (noise): " << e.what() << std::endl; break; } @@ -70,38 +68,35 @@ void runNoiseCaptureLoop(const std::shared_ptr &source, } // Fake video source: solid color cycling -void runFakeVideoCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag) { +void runFakeVideoCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag) { auto frame = VideoFrame::create(1280, 720, VideoBufferType::RGBA); const double framerate = 1.0 / 30.0; while (running_flag.load(std::memory_order_relaxed)) { static auto start = std::chrono::high_resolution_clock::now(); - float t = std::chrono::duration( - std::chrono::high_resolution_clock::now() - start) - .count(); + float t = std::chrono::duration(std::chrono::high_resolution_clock::now() - start).count(); // Cycle every 4 seconds: 0=red, 1=green, 2=blue, 3=black int stage = static_cast(t) % 4; std::array rgb{}; switch (stage) { - case 0: // red - rgb = {255, 0, 0, 0}; - break; - case 1: // green - rgb = {0, 255, 0, 0}; - break; - case 2: // blue - rgb = {0, 0, 255, 0}; - break; - case 3: // black - default: - rgb = {0, 0, 0, 0}; - break; + case 0: // red + rgb = {255, 0, 0, 0}; + break; + case 1: // green + rgb = {0, 255, 0, 0}; + break; + case 2: // blue + rgb = {0, 0, 255, 0}; + break; + case 3: // black + default: + rgb = {0, 0, 0, 0}; + break; } // ARGB - uint8_t *data = frame.data(); + uint8_t* data = frame.data(); const size_t size = frame.dataSize(); for (size_t i = 0; i < size; i += 4) { data[i + 0] = 255; // A @@ -114,9 +109,8 @@ void runFakeVideoCaptureLoop(const std::shared_ptr &source, // If VideoSource is ARGB-capable, pass frame. // If it expects I420, pass i420 instead. source->captureFrame(frame, 0, VideoRotation::VIDEO_ROTATION_0); - } catch (const std::exception &e) { - std::cerr << "Error in captureFrame (fake video): " << e.what() - << std::endl; + } catch (const std::exception& e) { + std::cerr << "Error in captureFrame (fake video): " << e.what() << std::endl; break; } diff --git a/basic_room/capture_utils.h b/basic_room/capture_utils.h index e80b243..60a6ea7 100644 --- a/basic_room/capture_utils.h +++ b/basic_room/capture_utils.h @@ -24,9 +24,6 @@ class AudioSource; class VideoSource; } // namespace livekit -void runNoiseCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag); +void runNoiseCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag); -void runFakeVideoCaptureLoop( - const std::shared_ptr &source, - std::atomic &running_flag); +void runFakeVideoCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag); diff --git a/basic_room/main.cpp b/basic_room/main.cpp index bb5d221..8db1acb 100644 --- a/basic_room/main.cpp +++ b/basic_room/main.cpp @@ -34,66 +34,58 @@ std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } -void printUsage(const char *prog) { +void printUsage(const char* prog) { std::cerr << "Usage:\n" << " " << prog << " --url --token \n" << "Env fallbacks:\n" << " LIVEKIT_URL, LIVEKIT_TOKEN\n"; } -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, - bool &self_test) { +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token, bool& self_test) { for (int i = 1; i < argc; ++i) { const std::string a = argv[i]; - if (a == "-h" || a == "--help") - return false; + if (a == "-h" || a == "--help") return false; if (a == "--self-test") { self_test = true; return true; } - auto take = [&](std::string &out) -> bool { - if (i + 1 >= argc) - return false; + auto take = [&](std::string& out) -> bool { + if (i + 1 >= argc) return false; out = argv[++i]; return true; }; if (a == "--url") { - if (!take(url)) - return false; + if (!take(url)) return false; } else if (a.rfind("--url=", 0) == 0) { url = a.substr(std::string("--url=").size()); } else if (a == "--token") { - if (!take(token)) - return false; + if (!take(token)) return false; } else if (a.rfind("--token=", 0) == 0) { token = a.substr(std::string("--token=").size()); } } if (url.empty()) { - if (const char *e = std::getenv("LIVEKIT_URL")) - url = e; + if (const char* e = std::getenv("LIVEKIT_URL")) url = e; } if (token.empty()) { - if (const char *e = std::getenv("LIVEKIT_TOKEN")) - token = e; + if (const char* e = std::getenv("LIVEKIT_TOKEN")) token = e; } return !(url.empty() || token.empty()); } void print_livekit_version() { - std::cout << "LiveKit version: " << LIVEKIT_BUILD_VERSION_FULL << " (" - << LIVEKIT_BUILD_FLAVOR << ", commit " << LIVEKIT_BUILD_COMMIT - << ", built " << LIVEKIT_BUILD_DATE << ")" << std::endl; + std::cout << "LiveKit version: " << LIVEKIT_BUILD_VERSION_FULL << " (" << LIVEKIT_BUILD_FLAVOR << ", commit " + << LIVEKIT_BUILD_COMMIT << ", built " << LIVEKIT_BUILD_DATE << ")" << std::endl; } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { print_livekit_version(); std::string url, token; bool self_test = false; @@ -131,8 +123,7 @@ int main(int argc, char *argv[]) { // ---- Create & publish AUDIO (noise) ---- // Match your runNoiseCaptureLoop pacing: it assumes frame_ms=10. auto audioSource = std::make_shared(48000, 1, 10); - auto audioTrack = - LocalAudioTrack::createLocalAudioTrack("noise", audioSource); + auto audioTrack = LocalAudioTrack::createLocalAudioTrack("noise", audioSource); TrackPublishOptions audioOpts; audioOpts.source = TrackSource::SOURCE_MICROPHONE; @@ -144,7 +135,7 @@ int main(int argc, char *argv[]) { room->localParticipant()->publishTrack(audioTrack, audioOpts); audioPub = audioTrack->publication(); std::cout << "Published audio: sid=" << audioPub->sid() << "\n"; - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Failed to publish audio: " << e.what() << "\n"; } @@ -163,7 +154,7 @@ int main(int argc, char *argv[]) { room->localParticipant()->publishTrack(videoTrack, videoOpts); videoPub = videoTrack->publication(); std::cout << "Published video: sid=" << videoPub->sid() << "\n"; - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Failed to publish video: " << e.what() << "\n"; } @@ -171,10 +162,8 @@ int main(int argc, char *argv[]) { std::atomic audio_running{true}; std::atomic video_running{true}; - std::thread audioThread( - [&] { runNoiseCaptureLoop(audioSource, audio_running); }); - std::thread videoThread( - [&] { runFakeVideoCaptureLoop(videoSource, video_running); }); + std::thread audioThread([&] { runNoiseCaptureLoop(audioSource, audio_running); }); + std::thread videoThread([&] { runFakeVideoCaptureLoop(videoSource, video_running); }); // Keep alive until Ctrl-C while (g_running.load()) { @@ -185,17 +174,13 @@ int main(int argc, char *argv[]) { audio_running.store(false); video_running.store(false); - if (audioThread.joinable()) - audioThread.join(); - if (videoThread.joinable()) - videoThread.join(); + if (audioThread.joinable()) audioThread.join(); + if (videoThread.joinable()) videoThread.join(); // Best-effort unpublish try { - if (audioPub) - room->localParticipant()->unpublishTrack(audioPub->sid()); - if (videoPub) - room->localParticipant()->unpublishTrack(videoPub->sid()); + if (audioPub) room->localParticipant()->unpublishTrack(audioPub->sid()); + if (videoPub) room->localParticipant()->unpublishTrack(videoPub->sid()); } catch (...) { } diff --git a/hello_livekit_receiver/main.cpp b/hello_livekit_receiver/main.cpp index f379286..413a845 100644 --- a/hello_livekit_receiver/main.cpp +++ b/hello_livekit_receiver/main.cpp @@ -24,8 +24,6 @@ /// Or via environment variables: /// LIVEKIT_URL, LIVEKIT_RECEIVER_TOKEN, LIVEKIT_SENDER_IDENTITY -#include "livekit/livekit.h" - #include #include #include @@ -34,21 +32,23 @@ #include #include +#include "livekit/livekit.h" + using namespace livekit; -constexpr const char *kDataTrackName = "app-data"; -constexpr const char *kVideoTrackName = "camera0"; +constexpr const char* kDataTrackName = "app-data"; +constexpr const char* kVideoTrackName = "camera0"; std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } -std::string getenvOrEmpty(const char *name) { - const char *v = std::getenv(name); +std::string getenvOrEmpty(const char* name) { + const char* v = std::getenv(name); return v ? std::string(v) : std::string{}; } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url = getenvOrEmpty("LIVEKIT_URL"); std::string receiver_token = getenvOrEmpty("LIVEKIT_RECEIVER_TOKEN"); std::string sender_identity = getenvOrEmpty("LIVEKIT_SENDER_IDENTITY"); @@ -60,7 +60,8 @@ int main(int argc, char *argv[]) { } if (url.empty() || receiver_token.empty() || sender_identity.empty()) { - std::cerr << "[error] Usage: HelloLivekitReceiver \n or set LIVEKIT_URL, LIVEKIT_RECEIVER_TOKEN, LIVEKIT_SENDER_IDENTITY\n"; + std::cerr << "[error] Usage: HelloLivekitReceiver \n or set " + "LIVEKIT_URL, LIVEKIT_RECEIVER_TOKEN, LIVEKIT_SENDER_IDENTITY\n"; return 1; } @@ -82,35 +83,35 @@ int main(int argc, char *argv[]) { return 1; } - LocalParticipant *lp = room->localParticipant(); + LocalParticipant* lp = room->localParticipant(); assert(lp); - std::cout << "[info] [receiver] Connected as identity='" << lp->identity() << "' room='" << room->room_info().name << "'; subscribing to sender identity='" << sender_identity << "'\n"; + std::cout << "[info] [receiver] Connected as identity='" << lp->identity() << "' room='" << room->room_info().name + << "'; subscribing to sender identity='" << sender_identity << "'\n"; int video_frame_count = 0; - room->setOnVideoFrameCallback( - sender_identity, kVideoTrackName, - [&video_frame_count](const VideoFrame &frame, std::int64_t timestamp_us) { - const auto ts_ms = - std::chrono::duration(timestamp_us).count(); - const int n = video_frame_count++; - if (n % 10 == 0) { - std::cout << "[info] [receiver] Video frame #" << n << " " << frame.width() << "x" << frame.height() << " ts_ms=" << ts_ms << "\n"; - } - }); + room->setOnVideoFrameCallback(sender_identity, kVideoTrackName, + [&video_frame_count](const VideoFrame& frame, std::int64_t timestamp_us) { + const auto ts_ms = std::chrono::duration(timestamp_us).count(); + const int n = video_frame_count++; + if (n % 10 == 0) { + std::cout << "[info] [receiver] Video frame #" << n << " " << frame.width() << "x" + << frame.height() << " ts_ms=" << ts_ms << "\n"; + } + }); int data_frame_count = 0; room->addOnDataFrameCallback( sender_identity, kDataTrackName, - [&data_frame_count](const std::vector &payload, - std::optional user_ts) { + [&data_frame_count](const std::vector& payload, std::optional user_ts) { const int n = data_frame_count++; if (n % 10 == 0) { std::cout << "[info] [receiver] Data frame #" << n << "\n"; } }); - std::cout << "[info] [receiver] Listening for video track '" << kVideoTrackName << "' + data track '" << kDataTrackName << "'; Ctrl-C to exit\n"; + std::cout << "[info] [receiver] Listening for video track '" << kVideoTrackName << "' + data track '" + << kDataTrackName << "'; Ctrl-C to exit\n"; while (g_running.load()) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); diff --git a/hello_livekit_sender/main.cpp b/hello_livekit_sender/main.cpp index 713e729..780d2d8 100644 --- a/hello_livekit_sender/main.cpp +++ b/hello_livekit_sender/main.cpp @@ -23,35 +23,35 @@ /// Or via environment variables: /// LIVEKIT_URL, LIVEKIT_SENDER_TOKEN -#include "livekit/livekit.h" - #include #include #include #include #include #include +#include #include #include -#include + +#include "livekit/livekit.h" using namespace livekit; constexpr int kWidth = 640; constexpr int kHeight = 480; -constexpr const char *kVideoTrackName = "camera0"; -constexpr const char *kDataTrackName = "app-data"; +constexpr const char* kVideoTrackName = "camera0"; +constexpr const char* kDataTrackName = "app-data"; std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } -std::string getenvOrEmpty(const char *name) { - const char *v = std::getenv(name); +std::string getenvOrEmpty(const char* name) { + const char* v = std::getenv(name); return v ? std::string(v) : std::string{}; } -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url = getenvOrEmpty("LIVEKIT_URL"); std::string sender_token = getenvOrEmpty("LIVEKIT_SENDER_TOKEN"); @@ -61,7 +61,8 @@ int main(int argc, char *argv[]) { } if (url.empty() || sender_token.empty()) { - std::cerr << "[error] Usage: HelloLivekitSender \n or set LIVEKIT_URL, LIVEKIT_SENDER_TOKEN\n"; + std::cerr + << "[error] Usage: HelloLivekitSender \n or set LIVEKIT_URL, LIVEKIT_SENDER_TOKEN\n"; return 1; } @@ -83,20 +84,22 @@ int main(int argc, char *argv[]) { return 1; } - LocalParticipant *lp = room->localParticipant(); + LocalParticipant* lp = room->localParticipant(); assert(lp); - std::cout << "[info] [sender] Connected as identity='" << lp->identity() << "' room='" << room->room_info().name << "' — pass this identity to HelloLivekitReceiver\n"; + std::cout << "[info] [sender] Connected as identity='" << lp->identity() << "' room='" << room->room_info().name + << "' — pass this identity to HelloLivekitReceiver\n"; auto video_source = std::make_shared(kWidth, kHeight); - std::shared_ptr video_track = lp->publishVideoTrack( - kVideoTrackName, video_source, TrackSource::SOURCE_CAMERA); + std::shared_ptr video_track = + lp->publishVideoTrack(kVideoTrackName, video_source, TrackSource::SOURCE_CAMERA); auto publish_result = lp->publishDataTrack(kDataTrackName); if (!publish_result) { - const auto &error = publish_result.error(); - std::cerr << "[error] Failed to publish data track: code=" << static_cast(error.code) << " message=" << error.message << "\n"; + const auto& error = publish_result.error(); + std::cerr << "[error] Failed to publish data track: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; room.reset(); livekit::shutdown(); return 1; @@ -113,16 +116,15 @@ int main(int argc, char *argv[]) { video_source->captureFrame(std::move(vf)); const auto now = std::chrono::steady_clock::now(); - const double ms = - std::chrono::duration(now - t0).count(); + const double ms = std::chrono::duration(now - t0).count(); std::ostringstream oss; oss << std::fixed << std::setprecision(2) << ms << " ms, count: " << count; const std::string msg = oss.str(); - auto push_result = - data_track->tryPush(std::vector(msg.begin(), msg.end())); + auto push_result = data_track->tryPush(std::vector(msg.begin(), msg.end())); if (!push_result) { - const auto &error = push_result.error(); - std::cerr << "[warn] Failed to push data frame: code=" << static_cast(error.code) << " message=" << error.message << "\n"; + const auto& error = push_result.error(); + std::cerr << "[warn] Failed to push data frame: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; } ++count; diff --git a/logging_levels_basic_usage/main.cpp b/logging_levels_basic_usage/main.cpp index bdf5ada..52a7ead 100644 --- a/logging_levels_basic_usage/main.cpp +++ b/logging_levels_basic_usage/main.cpp @@ -29,49 +29,42 @@ /// If no argument is given, the example cycles through every level and then /// demonstrates the custom callback API. -#include "livekit/livekit.h" - #include #include #include +#include "livekit/livekit.h" + namespace { -const char *levelName(livekit::LogLevel level) { +const char* levelName(livekit::LogLevel level) { switch (level) { - case livekit::LogLevel::Trace: - return "TRACE"; - case livekit::LogLevel::Debug: - return "DEBUG"; - case livekit::LogLevel::Info: - return "INFO"; - case livekit::LogLevel::Warn: - return "WARN"; - case livekit::LogLevel::Error: - return "ERROR"; - case livekit::LogLevel::Critical: - return "CRITICAL"; - case livekit::LogLevel::Off: - return "OFF"; + case livekit::LogLevel::Trace: + return "TRACE"; + case livekit::LogLevel::Debug: + return "DEBUG"; + case livekit::LogLevel::Info: + return "INFO"; + case livekit::LogLevel::Warn: + return "WARN"; + case livekit::LogLevel::Error: + return "ERROR"; + case livekit::LogLevel::Critical: + return "CRITICAL"; + case livekit::LogLevel::Off: + return "OFF"; } return "UNKNOWN"; } -livekit::LogLevel parseLevel(const char *arg) { - if (std::strcmp(arg, "trace") == 0) - return livekit::LogLevel::Trace; - if (std::strcmp(arg, "debug") == 0) - return livekit::LogLevel::Debug; - if (std::strcmp(arg, "info") == 0) - return livekit::LogLevel::Info; - if (std::strcmp(arg, "warn") == 0) - return livekit::LogLevel::Warn; - if (std::strcmp(arg, "error") == 0) - return livekit::LogLevel::Error; - if (std::strcmp(arg, "critical") == 0) - return livekit::LogLevel::Critical; - if (std::strcmp(arg, "off") == 0) - return livekit::LogLevel::Off; +livekit::LogLevel parseLevel(const char* arg) { + if (std::strcmp(arg, "trace") == 0) return livekit::LogLevel::Trace; + if (std::strcmp(arg, "debug") == 0) return livekit::LogLevel::Debug; + if (std::strcmp(arg, "info") == 0) return livekit::LogLevel::Info; + if (std::strcmp(arg, "warn") == 0) return livekit::LogLevel::Warn; + if (std::strcmp(arg, "error") == 0) return livekit::LogLevel::Error; + if (std::strcmp(arg, "critical") == 0) return livekit::LogLevel::Critical; + if (std::strcmp(arg, "off") == 0) return livekit::LogLevel::Off; std::cerr << "Unknown level '" << arg << "', defaulting to Info.\n" << "Valid: trace, debug, info, warn, error, critical, off\n"; return livekit::LogLevel::Info; @@ -80,10 +73,8 @@ livekit::LogLevel parseLevel(const char *arg) { /// Demonstrate cycling through every log level. void runLevelCycleDemo() { const livekit::LogLevel levels[] = { - livekit::LogLevel::Trace, livekit::LogLevel::Debug, - livekit::LogLevel::Info, livekit::LogLevel::Warn, - livekit::LogLevel::Error, livekit::LogLevel::Critical, - livekit::LogLevel::Off, + livekit::LogLevel::Trace, livekit::LogLevel::Debug, livekit::LogLevel::Info, livekit::LogLevel::Warn, + livekit::LogLevel::Error, livekit::LogLevel::Critical, livekit::LogLevel::Off, }; for (auto level : levels) { @@ -91,8 +82,7 @@ void runLevelCycleDemo() { << " Setting log level to: " << levelName(level) << "\n" << "========================================\n"; livekit::setLogLevel(level); - std::cout << " Current SDK log level: " - << levelName(livekit::getLogLevel()) << "\n"; + std::cout << " Current SDK log level: " << levelName(livekit::getLogLevel()) << "\n"; } } @@ -104,11 +94,8 @@ void runCallbackDemo() { livekit::setLogLevel(livekit::LogLevel::Trace); - livekit::setLogCallback([](livekit::LogLevel level, - const std::string &logger_name, - const std::string &message) { - std::cout << "[CALLBACK] [" << levelName(level) << "] [" << logger_name - << "] " << message << "\n"; + livekit::setLogCallback([](livekit::LogLevel level, const std::string& logger_name, const std::string& message) { + std::cout << "[CALLBACK] [" << levelName(level) << "] [" << logger_name << "] " << message << "\n"; }); std::cout << "Installed custom callback. SDK log messages will now be " @@ -122,12 +109,11 @@ void runCallbackDemo() { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { livekit::initialize(); if (argc > 1) { - if (std::strcmp(argv[1], "-h") == 0 || - std::strcmp(argv[1], "--help") == 0) { + if (std::strcmp(argv[1], "-h") == 0 || std::strcmp(argv[1], "--help") == 0) { std::cout << "Usage: LoggingLevelsBasicUsage " "[trace|debug|info|warn|error|critical|off]\n"; livekit::shutdown(); @@ -136,8 +122,7 @@ int main(int argc, char *argv[]) { livekit::LogLevel level = parseLevel(argv[1]); std::cout << "Setting log level to: " << levelName(level) << "\n\n"; livekit::setLogLevel(level); - std::cout << "Current SDK log level: " - << levelName(livekit::getLogLevel()) << "\n"; + std::cout << "Current SDK log level: " << levelName(livekit::getLogLevel()) << "\n"; } else { runLevelCycleDemo(); runCallbackDemo(); diff --git a/logging_levels_custom_sinks/main.cpp b/logging_levels_custom_sinks/main.cpp index 40ddcb4..b59c597 100644 --- a/logging_levels_custom_sinks/main.cpp +++ b/logging_levels_custom_sinks/main.cpp @@ -34,8 +34,6 @@ /// /// If no argument is given, all three sinks are demonstrated in sequence. -#include "livekit/livekit.h" - #include #include #include @@ -43,28 +41,30 @@ #include #include +#include "livekit/livekit.h" + namespace { // --------------------------------------------------------------- // Helpers // --------------------------------------------------------------- -const char *levelTag(livekit::LogLevel level) { +const char* levelTag(livekit::LogLevel level) { switch (level) { - case livekit::LogLevel::Trace: - return "TRACE"; - case livekit::LogLevel::Debug: - return "DEBUG"; - case livekit::LogLevel::Info: - return "INFO"; - case livekit::LogLevel::Warn: - return "WARN"; - case livekit::LogLevel::Error: - return "ERROR"; - case livekit::LogLevel::Critical: - return "CRITICAL"; - case livekit::LogLevel::Off: - return "OFF"; + case livekit::LogLevel::Trace: + return "TRACE"; + case livekit::LogLevel::Debug: + return "DEBUG"; + case livekit::LogLevel::Info: + return "INFO"; + case livekit::LogLevel::Warn: + return "WARN"; + case livekit::LogLevel::Error: + return "ERROR"; + case livekit::LogLevel::Critical: + return "CRITICAL"; + case livekit::LogLevel::Off: + return "OFF"; } return "?"; } @@ -72,18 +72,15 @@ const char *levelTag(livekit::LogLevel level) { std::string nowISO8601() { auto now = std::chrono::system_clock::now(); auto tt = std::chrono::system_clock::to_time_t(now); - auto ms = std::chrono::duration_cast( - now.time_since_epoch()) % - 1000; + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; std::ostringstream ss; - ss << std::put_time(std::gmtime(&tt), "%FT%T") << '.' << std::setfill('0') - << std::setw(3) << ms.count() << 'Z'; + ss << std::put_time(std::gmtime(&tt), "%FT%T") << '.' << std::setfill('0') << std::setw(3) << ms.count() << 'Z'; return ss.str(); } struct SampleLog { livekit::LogLevel level; - const char *message; + const char* message; }; // Representative messages that the SDK would emit during normal operation. @@ -98,8 +95,8 @@ const SampleLog kSampleLogs[] = { {livekit::LogLevel::Critical, "out of memory allocating decode buffer"}, }; -void driveCallback(const livekit::LogCallback &cb) { - for (const auto &entry : kSampleLogs) { +void driveCallback(const livekit::LogCallback& cb) { + for (const auto& entry : kSampleLogs) { cb(entry.level, "livekit", entry.message); } } @@ -109,7 +106,7 @@ void driveCallback(const livekit::LogCallback &cb) { // --------------------------------------------------------------- void runFileSinkDemo() { - const char *path = "livekit.log"; + const char* path = "livekit.log"; std::cout << "\n=== File sink: writing SDK logs to '" << path << "' ===\n"; auto file = std::make_shared(path, std::ios::trunc); @@ -120,11 +117,9 @@ void runFileSinkDemo() { // The shared_ptr keeps the stream alive inside the lambda even if // the local variable goes out of scope before the callback fires. - livekit::LogCallback fileSink = [file](livekit::LogLevel level, - const std::string &logger_name, - const std::string &message) { - *file << nowISO8601() << " [" << levelTag(level) << "] [" << logger_name - << "] " << message << "\n"; + livekit::LogCallback fileSink = [file](livekit::LogLevel level, const std::string& logger_name, + const std::string& message) { + *file << nowISO8601() << " [" << levelTag(level) << "] [" << logger_name << "] " << message << "\n"; file->flush(); }; @@ -148,28 +143,28 @@ void runFileSinkDemo() { // 2. JSON structured logger // --------------------------------------------------------------- -std::string escapeJson(const std::string &s) { +std::string escapeJson(const std::string& s) { std::string out; out.reserve(s.size() + 8); for (char c : s) { switch (c) { - case '"': - out += "\\\""; - break; - case '\\': - out += "\\\\"; - break; - case '\n': - out += "\\n"; - break; - case '\r': - out += "\\r"; - break; - case '\t': - out += "\\t"; - break; - default: - out += c; + case '"': + out += "\\\""; + break; + case '\\': + out += "\\\\"; + break; + case '\n': + out += "\\n"; + break; + case '\r': + out += "\\r"; + break; + case '\t': + out += "\\t"; + break; + default: + out += c; } } return out; @@ -178,12 +173,10 @@ std::string escapeJson(const std::string &s) { void runJsonSinkDemo() { std::cout << "\n=== JSON sink: structured log lines to stdout ===\n\n"; - livekit::LogCallback jsonSink = [](livekit::LogLevel level, - const std::string &logger_name, - const std::string &message) { - std::cout << R"({"ts":")" << nowISO8601() << R"(","level":")" - << levelTag(level) << R"(","logger":")" << escapeJson(logger_name) - << R"(","msg":")" << escapeJson(message) << "\"}\n"; + livekit::LogCallback jsonSink = [](livekit::LogLevel level, const std::string& logger_name, + const std::string& message) { + std::cout << R"({"ts":")" << nowISO8601() << R"(","level":")" << levelTag(level) << R"(","logger":")" + << escapeJson(logger_name) << R"(","msg":")" << escapeJson(message) << "\"}\n"; }; livekit::setLogCallback(jsonSink); @@ -227,37 +220,33 @@ void runRos2SinkDemo() { const std::string node_name = "livekit_bridge_node"; - livekit::LogCallback ros2Sink = [&node_name](livekit::LogLevel level, - const std::string &logger_name, - const std::string &message) { - const char *ros_level; + livekit::LogCallback ros2Sink = [&node_name](livekit::LogLevel level, const std::string& logger_name, + const std::string& message) { + const char* ros_level; switch (level) { - case livekit::LogLevel::Trace: - case livekit::LogLevel::Debug: - ros_level = "DEBUG"; - break; - case livekit::LogLevel::Info: - ros_level = "INFO"; - break; - case livekit::LogLevel::Warn: - ros_level = "WARN"; - break; - case livekit::LogLevel::Error: - case livekit::LogLevel::Critical: - ros_level = "ERROR"; - break; - default: - ros_level = "INFO"; - break; + case livekit::LogLevel::Trace: + case livekit::LogLevel::Debug: + ros_level = "DEBUG"; + break; + case livekit::LogLevel::Info: + ros_level = "INFO"; + break; + case livekit::LogLevel::Warn: + ros_level = "WARN"; + break; + case livekit::LogLevel::Error: + case livekit::LogLevel::Critical: + ros_level = "ERROR"; + break; + default: + ros_level = "INFO"; + break; } // Mimic: [INFO] [1719500000.123] [livekit_bridge_node]: [livekit] msg - auto epoch_s = std::chrono::duration( - std::chrono::system_clock::now().time_since_epoch()) - .count(); - std::cout << "[" << ros_level << "] [" << std::fixed << std::setprecision(3) - << epoch_s << "] [" << node_name << "]: [" << logger_name << "] " - << message << "\n"; + auto epoch_s = std::chrono::duration(std::chrono::system_clock::now().time_since_epoch()).count(); + std::cout << "[" << ros_level << "] [" << std::fixed << std::setprecision(3) << epoch_s << "] [" << node_name + << "]: [" << logger_name << "] " << message << "\n"; }; livekit::setLogCallback(ros2Sink); @@ -267,7 +256,7 @@ void runRos2SinkDemo() { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { livekit::initialize(); if (argc > 1) { diff --git a/ping_pong_ping/json_converters.cpp b/ping_pong_ping/json_converters.cpp index 24f89b1..1943c0d 100644 --- a/ping_pong_ping/json_converters.cpp +++ b/ping_pong_ping/json_converters.cpp @@ -16,22 +16,21 @@ #include "json_converters.h" -#include "constants.h" - #include - #include +#include "constants.h" + namespace ping_pong { -std::string pingMessageToJson(const PingMessage &message) { +std::string pingMessageToJson(const PingMessage& message) { nlohmann::json json; json[kPingIdKey] = message.id; json[kTimestampKey] = message.ts_ns; return json.dump(); } -PingMessage pingMessageFromJson(const std::string &json_text) { +PingMessage pingMessageFromJson(const std::string& json_text) { try { const auto json = nlohmann::json::parse(json_text); @@ -39,20 +38,19 @@ PingMessage pingMessageFromJson(const std::string &json_text) { message.id = json.at(kPingIdKey).get(); message.ts_ns = json.at(kTimestampKey).get(); return message; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse ping JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse ping JSON: ") + e.what()); } } -std::string pongMessageToJson(const PongMessage &message) { +std::string pongMessageToJson(const PongMessage& message) { nlohmann::json json; json[kReceivedIdKey] = message.rec_id; json[kTimestampKey] = message.ts_ns; return json.dump(); } -PongMessage pongMessageFromJson(const std::string &json_text) { +PongMessage pongMessageFromJson(const std::string& json_text) { try { const auto json = nlohmann::json::parse(json_text); @@ -60,9 +58,8 @@ PongMessage pongMessageFromJson(const std::string &json_text) { message.rec_id = json.at(kReceivedIdKey).get(); message.ts_ns = json.at(kTimestampKey).get(); return message; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse pong JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse pong JSON: ") + e.what()); } } diff --git a/ping_pong_ping/json_converters.h b/ping_pong_ping/json_converters.h index 3491ef6..82e9daa 100644 --- a/ping_pong_ping/json_converters.h +++ b/ping_pong_ping/json_converters.h @@ -16,16 +16,16 @@ #pragma once -#include "messages.h" - #include +#include "messages.h" + namespace ping_pong { -std::string pingMessageToJson(const PingMessage &message); -PingMessage pingMessageFromJson(const std::string &json); +std::string pingMessageToJson(const PingMessage& message); +PingMessage pingMessageFromJson(const std::string& json); -std::string pongMessageToJson(const PongMessage &message); -PongMessage pongMessageFromJson(const std::string &json); +std::string pongMessageToJson(const PongMessage& message); +PongMessage pongMessageFromJson(const std::string& json); } // namespace ping_pong diff --git a/ping_pong_ping/main.cpp b/ping_pong_ping/main.cpp index ed63f7e..c2f6e62 100644 --- a/ping_pong_ping/main.cpp +++ b/ping_pong_ping/main.cpp @@ -18,12 +18,6 @@ /// and logs latency metrics for each matched response. Use a token whose /// identity is `ping`. -#include "constants.h" -#include "json_converters.h" -#include "livekit/livekit.h" -#include "messages.h" -#include "utils.h" - #include #include #include @@ -38,6 +32,12 @@ #include #include +#include "constants.h" +#include "json_converters.h" +#include "livekit/livekit.h" +#include "messages.h" +#include "utils.h" + using namespace livekit; namespace { @@ -46,34 +46,27 @@ std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } -ping_pong::LatencyMetrics -calculateLatencyMetrics(const ping_pong::PingMessage &ping_message, - const ping_pong::PongMessage &pong_message, - std::int64_t received_ts_ns) { +ping_pong::LatencyMetrics calculateLatencyMetrics(const ping_pong::PingMessage& ping_message, + const ping_pong::PongMessage& pong_message, + std::int64_t received_ts_ns) { ping_pong::LatencyMetrics metrics; metrics.id = ping_message.id; metrics.pong_sent_ts_ns = pong_message.ts_ns; metrics.ping_received_ts_ns = received_ts_ns; metrics.round_trip_time_ns = received_ts_ns - ping_message.ts_ns; metrics.pong_to_ping_time_ns = received_ts_ns - pong_message.ts_ns; - metrics.ping_to_pong_and_processing_ns = - pong_message.ts_ns - ping_message.ts_ns; - metrics.estimated_one_way_latency_ns = - static_cast(metrics.round_trip_time_ns) / 2.0; - metrics.round_trip_time_ms = - static_cast(metrics.round_trip_time_ns) / 1'000'000.0; - metrics.pong_to_ping_time_ms = - static_cast(metrics.pong_to_ping_time_ns) / 1'000'000.0; - metrics.ping_to_pong_and_processing_ms = - static_cast(metrics.ping_to_pong_and_processing_ns) / 1'000'000.0; - metrics.estimated_one_way_latency_ms = - metrics.estimated_one_way_latency_ns / 1'000'000.0; + metrics.ping_to_pong_and_processing_ns = pong_message.ts_ns - ping_message.ts_ns; + metrics.estimated_one_way_latency_ns = static_cast(metrics.round_trip_time_ns) / 2.0; + metrics.round_trip_time_ms = static_cast(metrics.round_trip_time_ns) / 1'000'000.0; + metrics.pong_to_ping_time_ms = static_cast(metrics.pong_to_ping_time_ns) / 1'000'000.0; + metrics.ping_to_pong_and_processing_ms = static_cast(metrics.ping_to_pong_and_processing_ns) / 1'000'000.0; + metrics.estimated_one_way_latency_ms = metrics.estimated_one_way_latency_ns / 1'000'000.0; return metrics; } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url = ping_pong::getenvOrEmpty("LIVEKIT_URL"); std::string token = ping_pong::getenvOrEmpty("LIVEKIT_TOKEN"); @@ -105,18 +98,17 @@ int main(int argc, char *argv[]) { return 1; } - LocalParticipant *local_participant = room->localParticipant(); + LocalParticipant* local_participant = room->localParticipant(); assert(local_participant); - std::cout << "[info] ping connected as identity='" << local_participant->identity() - << "' room='" << room->room_info().name << "'\n"; + std::cout << "[info] ping connected as identity='" << local_participant->identity() << "' room='" + << room->room_info().name << "'\n"; - auto publish_result = - local_participant->publishDataTrack(ping_pong::kPingTrackName); + auto publish_result = local_participant->publishDataTrack(ping_pong::kPingTrackName); if (!publish_result) { - const auto &error = publish_result.error(); - std::cerr << "[error] Failed to publish ping data track: code=" - << static_cast(error.code) << " message=" << error.message << "\n"; + const auto& error = publish_result.error(); + std::cerr << "[error] Failed to publish ping data track: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; room->setDelegate(nullptr); room.reset(); livekit::shutdown(); @@ -129,17 +121,15 @@ int main(int argc, char *argv[]) { const auto callback_id = room->addOnDataFrameCallback( ping_pong::kPongParticipantIdentity, ping_pong::kPongTrackName, - [&sent_messages, - &sent_messages_mutex](const std::vector &payload, - std::optional /*user_timestamp*/) { + [&sent_messages, &sent_messages_mutex](const std::vector& payload, + std::optional /*user_timestamp*/) { try { if (payload.empty()) { std::cout << "[debug] Ignoring empty pong payload\n"; return; } - const auto pong_message = - ping_pong::pongMessageFromJson(ping_pong::toString(payload)); + const auto pong_message = ping_pong::pongMessageFromJson(ping_pong::toString(payload)); const auto received_ts_ns = ping_pong::timeSinceEpochNs(); ping_pong::PingMessage ping_message; @@ -154,22 +144,19 @@ int main(int argc, char *argv[]) { sent_messages.erase(it); } - const auto metrics = calculateLatencyMetrics( - ping_message, pong_message, received_ts_ns); + const auto metrics = calculateLatencyMetrics(ping_message, pong_message, received_ts_ns); - std::cout << "[info] pong id=" << metrics.id - << " rtt_ms=" << metrics.round_trip_time_ms + std::cout << "[info] pong id=" << metrics.id << " rtt_ms=" << metrics.round_trip_time_ms << " pong_to_ping_ms=" << metrics.pong_to_ping_time_ms << " ping_to_pong_and_processing_ms=" << metrics.ping_to_pong_and_processing_ms << " estimated_one_way_latency_ms=" << metrics.estimated_one_way_latency_ms << "\n"; - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[warn] Failed to process pong payload: " << e.what() << "\n"; } }); - std::cout << "[info] published data track '" << ping_pong::kPingTrackName - << "' and listening for '" << ping_pong::kPongTrackName << "' from '" - << ping_pong::kPongParticipantIdentity << "'\n"; + std::cout << "[info] published data track '" << ping_pong::kPingTrackName << "' and listening for '" + << ping_pong::kPongTrackName << "' from '" << ping_pong::kPongParticipantIdentity << "'\n"; std::uint64_t next_id = 1; auto next_deadline = std::chrono::steady_clock::now(); @@ -182,16 +169,15 @@ int main(int argc, char *argv[]) { const std::string json = ping_pong::pingMessageToJson(ping_message); auto push_result = ping_track->tryPush(ping_pong::toPayload(json)); if (!push_result) { - const auto &error = push_result.error(); - std::cerr << "[warn] Failed to push ping data frame: code=" - << static_cast(error.code) << " message=" << error.message << "\n"; + const auto& error = push_result.error(); + std::cerr << "[warn] Failed to push ping data frame: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; } else { { std::lock_guard lock(sent_messages_mutex); sent_messages.emplace(ping_message.id, ping_message); } - std::cout << "[info] sent ping id=" << ping_message.id << " ts_ns=" << ping_message.ts_ns - << "\n"; + std::cout << "[info] sent ping id=" << ping_message.id << " ts_ns=" << ping_message.ts_ns << "\n"; } next_deadline += ping_pong::kPingPeriod; diff --git a/ping_pong_ping/utils.h b/ping_pong_ping/utils.h index 56c915b..8777ec4 100644 --- a/ping_pong_ping/utils.h +++ b/ping_pong_ping/utils.h @@ -24,8 +24,8 @@ namespace ping_pong { -inline std::string getenvOrEmpty(const char *name) { - const char *value = std::getenv(name); +inline std::string getenvOrEmpty(const char* name) { + const char* value = std::getenv(name); return value ? std::string(value) : std::string{}; } @@ -34,11 +34,11 @@ inline std::int64_t timeSinceEpochNs() { return std::chrono::duration_cast(now).count(); } -inline std::vector toPayload(const std::string &json) { +inline std::vector toPayload(const std::string& json) { return std::vector(json.begin(), json.end()); } -inline std::string toString(const std::vector &payload) { +inline std::string toString(const std::vector& payload) { return std::string(payload.begin(), payload.end()); } diff --git a/ping_pong_pong/json_converters.cpp b/ping_pong_pong/json_converters.cpp index 24f89b1..1943c0d 100644 --- a/ping_pong_pong/json_converters.cpp +++ b/ping_pong_pong/json_converters.cpp @@ -16,22 +16,21 @@ #include "json_converters.h" -#include "constants.h" - #include - #include +#include "constants.h" + namespace ping_pong { -std::string pingMessageToJson(const PingMessage &message) { +std::string pingMessageToJson(const PingMessage& message) { nlohmann::json json; json[kPingIdKey] = message.id; json[kTimestampKey] = message.ts_ns; return json.dump(); } -PingMessage pingMessageFromJson(const std::string &json_text) { +PingMessage pingMessageFromJson(const std::string& json_text) { try { const auto json = nlohmann::json::parse(json_text); @@ -39,20 +38,19 @@ PingMessage pingMessageFromJson(const std::string &json_text) { message.id = json.at(kPingIdKey).get(); message.ts_ns = json.at(kTimestampKey).get(); return message; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse ping JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse ping JSON: ") + e.what()); } } -std::string pongMessageToJson(const PongMessage &message) { +std::string pongMessageToJson(const PongMessage& message) { nlohmann::json json; json[kReceivedIdKey] = message.rec_id; json[kTimestampKey] = message.ts_ns; return json.dump(); } -PongMessage pongMessageFromJson(const std::string &json_text) { +PongMessage pongMessageFromJson(const std::string& json_text) { try { const auto json = nlohmann::json::parse(json_text); @@ -60,9 +58,8 @@ PongMessage pongMessageFromJson(const std::string &json_text) { message.rec_id = json.at(kReceivedIdKey).get(); message.ts_ns = json.at(kTimestampKey).get(); return message; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse pong JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse pong JSON: ") + e.what()); } } diff --git a/ping_pong_pong/json_converters.h b/ping_pong_pong/json_converters.h index 3491ef6..82e9daa 100644 --- a/ping_pong_pong/json_converters.h +++ b/ping_pong_pong/json_converters.h @@ -16,16 +16,16 @@ #pragma once -#include "messages.h" - #include +#include "messages.h" + namespace ping_pong { -std::string pingMessageToJson(const PingMessage &message); -PingMessage pingMessageFromJson(const std::string &json); +std::string pingMessageToJson(const PingMessage& message); +PingMessage pingMessageFromJson(const std::string& json); -std::string pongMessageToJson(const PongMessage &message); -PongMessage pongMessageFromJson(const std::string &json); +std::string pongMessageToJson(const PongMessage& message); +PongMessage pongMessageFromJson(const std::string& json); } // namespace ping_pong diff --git a/ping_pong_pong/main.cpp b/ping_pong_pong/main.cpp index 1991678..6e1fea4 100644 --- a/ping_pong_pong/main.cpp +++ b/ping_pong_pong/main.cpp @@ -17,24 +17,24 @@ /// Pong participant: listens on the "ping" data track and publishes responses /// on the "pong" data track. Use a token whose identity is `pong`. -#include "constants.h" -#include "json_converters.h" -#include "livekit/livekit.h" -#include "messages.h" -#include "utils.h" - #include #include #include #include -#include #include +#include #include #include #include #include #include +#include "constants.h" +#include "json_converters.h" +#include "livekit/livekit.h" +#include "messages.h" +#include "utils.h" + using namespace livekit; namespace { @@ -45,7 +45,7 @@ void handleSignal(int) { g_running.store(false); } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url = ping_pong::getenvOrEmpty("LIVEKIT_URL"); std::string token = ping_pong::getenvOrEmpty("LIVEKIT_TOKEN"); @@ -77,18 +77,17 @@ int main(int argc, char *argv[]) { return 1; } - LocalParticipant *local_participant = room->localParticipant(); + LocalParticipant* local_participant = room->localParticipant(); assert(local_participant); - std::cout << "[info] pong connected as identity='" << local_participant->identity() - << "' room='" << room->room_info().name << "'\n"; + std::cout << "[info] pong connected as identity='" << local_participant->identity() << "' room='" + << room->room_info().name << "'\n"; - auto publish_result = - local_participant->publishDataTrack(ping_pong::kPongTrackName); + auto publish_result = local_participant->publishDataTrack(ping_pong::kPongTrackName); if (!publish_result) { - const auto &error = publish_result.error(); - std::cerr << "[error] Failed to publish pong data track: code=" - << static_cast(error.code) << " message=" << error.message << "\n"; + const auto& error = publish_result.error(); + std::cerr << "[error] Failed to publish pong data track: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; room->setDelegate(nullptr); room.reset(); livekit::shutdown(); @@ -99,16 +98,14 @@ int main(int argc, char *argv[]) { const auto callback_id = room->addOnDataFrameCallback( ping_pong::kPingParticipantIdentity, ping_pong::kPingTrackName, - [pong_track](const std::vector &payload, - std::optional /*user_timestamp*/) { + [pong_track](const std::vector& payload, std::optional /*user_timestamp*/) { try { if (payload.empty()) { std::cout << "[debug] Ignoring empty ping payload\n"; return; } - const auto ping_message = - ping_pong::pingMessageFromJson(ping_pong::toString(payload)); + const auto ping_message = ping_pong::pingMessageFromJson(ping_pong::toString(payload)); ping_pong::PongMessage pong_message; pong_message.rec_id = ping_message.id; @@ -117,24 +114,21 @@ int main(int argc, char *argv[]) { const std::string json = ping_pong::pongMessageToJson(pong_message); auto push_result = pong_track->tryPush(ping_pong::toPayload(json)); if (!push_result) { - const auto &error = push_result.error(); - std::cerr << "[warn] Failed to push pong data frame: code=" - << static_cast(error.code) << " message=" << error.message - << "\n"; + const auto& error = push_result.error(); + std::cerr << "[warn] Failed to push pong data frame: code=" << static_cast(error.code) + << " message=" << error.message << "\n"; return; } std::cout << "[info] received ping id=" << ping_message.id << " ts_ns=" << ping_message.ts_ns - << " and sent pong rec_id=" << pong_message.rec_id << " ts_ns=" << pong_message.ts_ns - << "\n"; - } catch (const std::exception &e) { + << " and sent pong rec_id=" << pong_message.rec_id << " ts_ns=" << pong_message.ts_ns << "\n"; + } catch (const std::exception& e) { std::cerr << "[warn] Failed to process ping payload: " << e.what() << "\n"; } }); - std::cout << "[info] published data track '" << ping_pong::kPongTrackName - << "' and listening for '" << ping_pong::kPingTrackName << "' from '" - << ping_pong::kPingParticipantIdentity << "'\n"; + std::cout << "[info] published data track '" << ping_pong::kPongTrackName << "' and listening for '" + << ping_pong::kPingTrackName << "' from '" << ping_pong::kPingParticipantIdentity << "'\n"; while (g_running.load()) { std::this_thread::sleep_for(ping_pong::kPollPeriod); diff --git a/ping_pong_pong/utils.h b/ping_pong_pong/utils.h index 56c915b..8777ec4 100644 --- a/ping_pong_pong/utils.h +++ b/ping_pong_pong/utils.h @@ -24,8 +24,8 @@ namespace ping_pong { -inline std::string getenvOrEmpty(const char *name) { - const char *value = std::getenv(name); +inline std::string getenvOrEmpty(const char* name) { + const char* value = std::getenv(name); return value ? std::string(value) : std::string{}; } @@ -34,11 +34,11 @@ inline std::int64_t timeSinceEpochNs() { return std::chrono::duration_cast(now).count(); } -inline std::vector toPayload(const std::string &json) { +inline std::vector toPayload(const std::string& json) { return std::vector(json.begin(), json.end()); } -inline std::string toString(const std::vector &payload) { +inline std::string toString(const std::vector& payload) { return std::string(payload.begin(), payload.end()); } diff --git a/simple_data_stream/main.cpp b/simple_data_stream/main.cpp index 917f0ac..e3f63e3 100644 --- a/simple_data_stream/main.cpp +++ b/simple_data_stream/main.cpp @@ -39,15 +39,14 @@ std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } // Helper: get env var or empty string -std::string getenvOrEmpty(const char *name) { - const char *v = std::getenv(name); +std::string getenvOrEmpty(const char* name) { + const char* v = std::getenv(name); return v ? std::string(v) : std::string{}; } std::int64_t nowEpochMs() { using namespace std::chrono; - return duration_cast(system_clock::now().time_since_epoch()) - .count(); + return duration_cast(system_clock::now().time_since_epoch()).count(); } std::string randomHexId(std::size_t nbytes = 16) { @@ -55,17 +54,17 @@ std::string randomHexId(std::size_t nbytes = 16) { std::ostringstream oss; for (std::size_t i = 0; i < nbytes; ++i) { std::uint8_t b = static_cast(rng() & 0xFF); - const char *hex = "0123456789abcdef"; + const char* hex = "0123456789abcdef"; oss << hex[(b >> 4) & 0xF] << hex[b & 0xF]; } return oss.str(); } // Greeting: send text + image -void greetParticipant(Room *room, const std::string &identity) { +void greetParticipant(Room* room, const std::string& identity) { std::cout << "[DataStream] Greeting participant: " << identity << "\n"; - LocalParticipant *lp = room->localParticipant(); + LocalParticipant* lp = room->localParticipant(); if (!lp) { std::cerr << "[DataStream] No local participant, cannot greet.\n"; return; @@ -73,8 +72,7 @@ void greetParticipant(Room *room, const std::string &identity) { try { const std::int64_t sent_ms = nowEpochMs(); - const std::string sender_id = - !lp->identity().empty() ? lp->identity() : std::string("cpp_sender"); + const std::string sender_id = !lp->identity().empty() ? lp->identity() : std::string("cpp_sender"); const std::vector dest{identity}; // Send text stream ("chat") @@ -89,10 +87,9 @@ void greetParticipant(Room *room, const std::string &identity) { // Put timestamp in payload too (so you can compute latency even if // attributes aren’t plumbed through your reader info yet). const std::string body = "Hi! Just a friendly message"; - const std::string payload = "sent_ms=" + std::to_string(sent_ms) + "\n" + - "stream_id=" + chat_stream_id + "\n" + body; - TextStreamWriter text_writer(*lp, "chat", chat_attrs, chat_stream_id, - payload.size(), reply_to_id, dest, sender_id); + const std::string payload = + "sent_ms=" + std::to_string(sent_ms) + "\n" + "stream_id=" + chat_stream_id + "\n" + body; + TextStreamWriter text_writer(*lp, "chat", chat_attrs, chat_stream_id, payload.size(), reply_to_id, dest, sender_id); const std::string message = "Hi! Just a friendly message"; text_writer.write(message); // will be chunked internally if needed @@ -106,8 +103,7 @@ void greetParticipant(Room *room, const std::string &identity) { return; } - std::vector data((std::istreambuf_iterator(in)), - std::istreambuf_iterator()); + std::vector data((std::istreambuf_iterator(in)), std::istreambuf_iterator()); const std::string file_stream_id = randomHexId(); std::map file_attrs; @@ -115,48 +111,38 @@ void greetParticipant(Room *room, const std::string &identity) { file_attrs["kind"] = "file"; file_attrs["test_flag"] = "1"; file_attrs["orig_path"] = file_path; - const std::string name = - std::filesystem::path(file_path).filename().string(); + const std::string name = std::filesystem::path(file_path).filename().string(); const std::string mime = "image/avif"; - ByteStreamWriter byte_writer(*lp, name, "files", file_attrs, file_stream_id, - data.size(), mime, dest, sender_id); + ByteStreamWriter byte_writer(*lp, name, "files", file_attrs, file_stream_id, data.size(), mime, dest, sender_id); byte_writer.write(data); byte_writer.close(); - std::cout << "[DataStream] Greeting sent to " << identity - << " (sent_ms=" << sent_ms << ")\n"; - } catch (const std::exception &e) { - std::cerr << "[DataStream] Error greeting participant " << identity << ": " - << e.what() << "\n"; + std::cout << "[DataStream] Greeting sent to " << identity << " (sent_ms=" << sent_ms << ")\n"; + } catch (const std::exception& e) { + std::cerr << "[DataStream] Error greeting participant " << identity << ": " << e.what() << "\n"; } } // Handlers for incoming streams -void handleChatMessage(std::shared_ptr reader, - const std::string &participant_identity) { +void handleChatMessage(std::shared_ptr reader, const std::string& participant_identity) { try { const auto info = reader->info(); // copy (safe even if reader goes away) const std::int64_t recv_ms = nowEpochMs(); const std::int64_t sent_ms = info.timestamp; const auto latency = (sent_ms > 0) ? (recv_ms - sent_ms) : -1; std::string full_text = reader->readAll(); - std::cout << "[DataStream] Received chat from " << participant_identity - << " topic=" << info.topic << " stream_id=" << info.stream_id - << " latency_ms=" << latency << " text='" << full_text << "'\n"; - } catch (const std::exception &e) { - std::cerr << "[DataStream] Error reading chat stream from " - << participant_identity << ": " << e.what() << "\n"; + std::cout << "[DataStream] Received chat from " << participant_identity << " topic=" << info.topic + << " stream_id=" << info.stream_id << " latency_ms=" << latency << " text='" << full_text << "'\n"; + } catch (const std::exception& e) { + std::cerr << "[DataStream] Error reading chat stream from " << participant_identity << ": " << e.what() << "\n"; } } -void handleWelcomeImage(std::shared_ptr reader, - const std::string &participant_identity) { +void handleWelcomeImage(std::shared_ptr reader, const std::string& participant_identity) { try { const auto info = reader->info(); - const std::string stream_id = - info.stream_id.empty() ? "unknown" : info.stream_id; - const std::string original_name = - info.name.empty() ? "received_image.bin" : info.name; + const std::string stream_id = info.stream_id.empty() ? "unknown" : info.stream_id; + const std::string original_name = info.name.empty() ? "received_image.bin" : info.name; // Latency: prefer header timestamp std::int64_t sent_ms = info.timestamp; // Optional: override with explicit attribute if you set it @@ -170,39 +156,34 @@ void handleWelcomeImage(std::shared_ptr reader, const std::int64_t recv_ms = nowEpochMs(); const std::int64_t latency_ms = (sent_ms > 0) ? (recv_ms - sent_ms) : -1; const std::string out_file = "received_" + original_name; - std::cout << "[DataStream] Receiving image from " << participant_identity - << " stream_id=" << stream_id << " name='" << original_name << "'" + std::cout << "[DataStream] Receiving image from " << participant_identity << " stream_id=" << stream_id << " name='" + << original_name << "'" << " mime='" << info.mime_type << "'" - << " size=" - << (info.size ? std::to_string(*info.size) : "unknown") - << " latency_ms=" << latency_ms << " -> '" << out_file << "'\n"; + << " size=" << (info.size ? std::to_string(*info.size) : "unknown") << " latency_ms=" << latency_ms + << " -> '" << out_file << "'\n"; std::ofstream out(out_file, std::ios::binary); if (!out) { - std::cerr << "[DataStream] Failed to open output file: " << out_file - << "\n"; + std::cerr << "[DataStream] Failed to open output file: " << out_file << "\n"; return; } std::vector chunk; std::uint64_t total_written = 0; while (reader->readNext(chunk)) { if (!chunk.empty()) { - out.write(reinterpret_cast(chunk.data()), - static_cast(chunk.size())); + out.write(reinterpret_cast(chunk.data()), static_cast(chunk.size())); total_written += chunk.size(); } } - std::cout << "[DataStream] Saved image from " << participant_identity - << " stream_id=" << stream_id << " bytes=" << total_written - << " to '" << out_file << std::endl; - } catch (const std::exception &e) { - std::cerr << "[DataStream] Error reading image stream from " - << participant_identity << ": " << e.what() << "\n"; + std::cout << "[DataStream] Saved image from " << participant_identity << " stream_id=" << stream_id + << " bytes=" << total_written << " to '" << out_file << std::endl; + } catch (const std::exception& e) { + std::cerr << "[DataStream] Error reading image stream from " << participant_identity << ": " << e.what() << "\n"; } } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { // Get URL and token from env. std::string url = getenvOrEmpty("LIVEKIT_URL"); std::string token = getenvOrEmpty("LIVEKIT_TOKEN"); @@ -241,32 +222,26 @@ int main(int argc, char *argv[]) { } auto info = room->room_info(); - std::cout << "[DataStream] Connected to room '" << info.name - << "', participants: " << info.num_participants << "\n"; + std::cout << "[DataStream] Connected to room '" << info.name << "', participants: " << info.num_participants << "\n"; // Register stream handlers room->registerTextStreamHandler( - "chat", [](std::shared_ptr reader, - const std::string &participant_identity) { - std::thread t(handleChatMessage, std::move(reader), - participant_identity); + "chat", [](std::shared_ptr reader, const std::string& participant_identity) { + std::thread t(handleChatMessage, std::move(reader), participant_identity); t.detach(); }); room->registerByteStreamHandler( - "files", [](std::shared_ptr reader, - const std::string &participant_identity) { - std::thread t(handleWelcomeImage, std::move(reader), - participant_identity); + "files", [](std::shared_ptr reader, const std::string& participant_identity) { + std::thread t(handleWelcomeImage, std::move(reader), participant_identity); t.detach(); }); // Greet existing participants { auto remotes = room->remoteParticipants(); - for (const auto &rp : remotes) { - if (!rp) - continue; + for (const auto& rp : remotes) { + if (!rp) continue; std::cout << "Remote: " << rp->identity() << "\n"; greetParticipant(room.get(), rp->identity()); } diff --git a/simple_joystick_receiver/json_utils.cpp b/simple_joystick_receiver/json_utils.cpp index d634aaa..3c98c1c 100644 --- a/simple_joystick_receiver/json_utils.cpp +++ b/simple_joystick_receiver/json_utils.cpp @@ -21,7 +21,7 @@ namespace simple_joystick { -std::string joystick_to_json(const JoystickCommand &cmd) { +std::string joystick_to_json(const JoystickCommand& cmd) { nlohmann::json j; j["x"] = cmd.x; j["y"] = cmd.y; @@ -29,7 +29,7 @@ std::string joystick_to_json(const JoystickCommand &cmd) { return j.dump(); } -JoystickCommand json_to_joystick(const std::string &json) { +JoystickCommand json_to_joystick(const std::string& json) { try { auto j = nlohmann::json::parse(json); JoystickCommand cmd; @@ -37,9 +37,8 @@ JoystickCommand json_to_joystick(const std::string &json) { cmd.y = j.at("y").get(); cmd.z = j.at("z").get(); return cmd; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse joystick JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse joystick JSON: ") + e.what()); } } diff --git a/simple_joystick_receiver/json_utils.h b/simple_joystick_receiver/json_utils.h index 66ba16a..e1f47a8 100644 --- a/simple_joystick_receiver/json_utils.h +++ b/simple_joystick_receiver/json_utils.h @@ -29,10 +29,10 @@ struct JoystickCommand { /// Serialize a JoystickCommand to a JSON string. /// Example output: {"x":1.0,"y":2.0,"z":3.0} -std::string joystick_to_json(const JoystickCommand &cmd); +std::string joystick_to_json(const JoystickCommand& cmd); /// Deserialize a JSON string into a JoystickCommand. /// Throws std::runtime_error if the JSON is invalid or missing fields. -JoystickCommand json_to_joystick(const std::string &json); +JoystickCommand json_to_joystick(const std::string& json); } // namespace simple_joystick diff --git a/simple_joystick_receiver/main.cpp b/simple_joystick_receiver/main.cpp index d62785a..5f835ba 100644 --- a/simple_joystick_receiver/main.cpp +++ b/simple_joystick_receiver/main.cpp @@ -35,7 +35,7 @@ std::atomic g_sender_connected{false}; void handleSignal(int) { g_running.store(false); } -void printUsage(const char *prog) { +void printUsage(const char* prog) { std::cerr << "Usage:\n" << " " << prog << " \n" << "or:\n" @@ -49,7 +49,7 @@ void printUsage(const char *prog) { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url, token; if (!simple_joystick::parseArgs(argc, argv, url, token)) { printUsage(argv[0]); @@ -78,22 +78,19 @@ int main(int argc, char *argv[]) { std::cout << "[Receiver] Waiting for sender peer (up to 2 minutes)...\n"; // Register RPC handler for joystick commands - LocalParticipant *lp = room->localParticipant(); - lp->registerRpcMethod( - "joystick_command", - [](const RpcInvocationData &data) -> std::optional { - try { - auto cmd = simple_joystick::json_to_joystick(data.payload); - g_sender_connected.store(true); - std::cout << "[Receiver] Joystick from '" << data.caller_identity - << "': x=" << cmd.x << " y=" << cmd.y << " z=" << cmd.z - << "\n"; - return std::optional{"ok"}; - } catch (const std::exception &e) { - std::cerr << "[Receiver] Bad joystick payload: " << e.what() << "\n"; - throw; - } - }); + LocalParticipant* lp = room->localParticipant(); + lp->registerRpcMethod("joystick_command", [](const RpcInvocationData& data) -> std::optional { + try { + auto cmd = simple_joystick::json_to_joystick(data.payload); + g_sender_connected.store(true); + std::cout << "[Receiver] Joystick from '" << data.caller_identity << "': x=" << cmd.x << " y=" << cmd.y + << " z=" << cmd.z << "\n"; + return std::optional{"ok"}; + } catch (const std::exception& e) { + std::cerr << "[Receiver] Bad joystick payload: " << e.what() << "\n"; + throw; + } + }); std::cout << "[Receiver] RPC handler 'joystick_command' registered. " << "Listening for commands...\n"; @@ -108,9 +105,8 @@ int main(int argc, char *argv[]) { if (!g_running.load()) { std::cout << "[Receiver] Interrupted by signal. Shutting down.\n"; } else if (!g_sender_connected.load()) { - std::cerr - << "[Receiver] Timed out after 2 minutes with no sender connection. " - << "Exiting as failure.\n"; + std::cerr << "[Receiver] Timed out after 2 minutes with no sender connection. " + << "Exiting as failure.\n"; room->setDelegate(nullptr); room.reset(); livekit::shutdown(); diff --git a/simple_joystick_receiver/utils.cpp b/simple_joystick_receiver/utils.cpp index cc0ef96..fca40fb 100644 --- a/simple_joystick_receiver/utils.cpp +++ b/simple_joystick_receiver/utils.cpp @@ -22,7 +22,7 @@ namespace simple_joystick { -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token) { for (int i = 1; i < argc; ++i) { std::string a = argv[i]; if (a == "-h" || a == "--help") { @@ -30,7 +30,7 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { } } - auto get_flag_value = [&](const std::string &name, int &i) -> std::string { + auto get_flag_value = [&](const std::string& name, int& i) -> std::string { std::string arg = argv[i]; const std::string eq = name + "="; if (arg.rfind(name, 0) == 0) { @@ -47,12 +47,10 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { const std::string a = argv[i]; if (a.rfind("--url", 0) == 0) { auto v = get_flag_value("--url", i); - if (!v.empty()) - url = v; + if (!v.empty()) url = v; } else if (a.rfind("--token", 0) == 0) { auto v = get_flag_value("--token", i); - if (!v.empty()) - token = v; + if (!v.empty()) token = v; } } @@ -60,25 +58,20 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { std::vector pos; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; - if (a.rfind("--", 0) == 0) - continue; + if (a.rfind("--", 0) == 0) continue; pos.push_back(std::move(a)); } - if (url.empty() && pos.size() >= 1) - url = pos[0]; - if (token.empty() && pos.size() >= 2) - token = pos[1]; + if (url.empty() && pos.size() >= 1) url = pos[0]; + if (token.empty() && pos.size() >= 2) token = pos[1]; // Environment variable fallbacks if (url.empty()) { - const char *e = std::getenv("LIVEKIT_URL"); - if (e) - url = e; + const char* e = std::getenv("LIVEKIT_URL"); + if (e) url = e; } if (token.empty()) { - const char *e = std::getenv("LIVEKIT_TOKEN"); - if (e) - token = e; + const char* e = std::getenv("LIVEKIT_TOKEN"); + if (e) token = e; } return !(url.empty() || token.empty()); diff --git a/simple_joystick_receiver/utils.h b/simple_joystick_receiver/utils.h index 7fe94ee..c76e623 100644 --- a/simple_joystick_receiver/utils.h +++ b/simple_joystick_receiver/utils.h @@ -26,6 +26,6 @@ namespace simple_joystick { /// - Flags: --url= / --url , --token= / --token /// - Env vars: LIVEKIT_URL, LIVEKIT_TOKEN /// Returns true if both url and token were resolved, false otherwise. -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token); +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token); } // namespace simple_joystick diff --git a/simple_joystick_sender/json_utils.cpp b/simple_joystick_sender/json_utils.cpp index d634aaa..3c98c1c 100644 --- a/simple_joystick_sender/json_utils.cpp +++ b/simple_joystick_sender/json_utils.cpp @@ -21,7 +21,7 @@ namespace simple_joystick { -std::string joystick_to_json(const JoystickCommand &cmd) { +std::string joystick_to_json(const JoystickCommand& cmd) { nlohmann::json j; j["x"] = cmd.x; j["y"] = cmd.y; @@ -29,7 +29,7 @@ std::string joystick_to_json(const JoystickCommand &cmd) { return j.dump(); } -JoystickCommand json_to_joystick(const std::string &json) { +JoystickCommand json_to_joystick(const std::string& json) { try { auto j = nlohmann::json::parse(json); JoystickCommand cmd; @@ -37,9 +37,8 @@ JoystickCommand json_to_joystick(const std::string &json) { cmd.y = j.at("y").get(); cmd.z = j.at("z").get(); return cmd; - } catch (const nlohmann::json::exception &e) { - throw std::runtime_error(std::string("Failed to parse joystick JSON: ") + - e.what()); + } catch (const nlohmann::json::exception& e) { + throw std::runtime_error(std::string("Failed to parse joystick JSON: ") + e.what()); } } diff --git a/simple_joystick_sender/json_utils.h b/simple_joystick_sender/json_utils.h index 66ba16a..e1f47a8 100644 --- a/simple_joystick_sender/json_utils.h +++ b/simple_joystick_sender/json_utils.h @@ -29,10 +29,10 @@ struct JoystickCommand { /// Serialize a JoystickCommand to a JSON string. /// Example output: {"x":1.0,"y":2.0,"z":3.0} -std::string joystick_to_json(const JoystickCommand &cmd); +std::string joystick_to_json(const JoystickCommand& cmd); /// Deserialize a JSON string into a JoystickCommand. /// Throws std::runtime_error if the JSON is invalid or missing fields. -JoystickCommand json_to_joystick(const std::string &json); +JoystickCommand json_to_joystick(const std::string& json); } // namespace simple_joystick diff --git a/simple_joystick_sender/main.cpp b/simple_joystick_sender/main.cpp index a235c3d..2d1b749 100644 --- a/simple_joystick_sender/main.cpp +++ b/simple_joystick_sender/main.cpp @@ -75,8 +75,7 @@ int readKeyNonBlocking() { struct timeval tv = {0, 0}; // immediate return if (select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv) > 0) { unsigned char ch; - if (read(STDIN_FILENO, &ch, 1) == 1) - return ch; + if (read(STDIN_FILENO, &ch, 1) == 1) return ch; } return -1; } @@ -85,13 +84,12 @@ void enableRawMode() { /* Windows _getch() is already unbuffered */ } void disableRawMode() {} int readKeyNonBlocking() { - if (_kbhit()) - return _getch(); + if (_kbhit()) return _getch(); return -1; } #endif -void printUsage(const char *prog) { +void printUsage(const char* prog) { std::cerr << "Usage:\n" << " " << prog << " \n" << "or:\n" @@ -119,7 +117,7 @@ void printControls() { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url, token; if (!simple_joystick::parseArgs(argc, argv, url, token)) { printUsage(argv[0]); @@ -152,7 +150,7 @@ int main(int argc, char *argv[]) { std::cout << "[Sender] Waiting for 'robot' to join (checking every 2s)...\n"; printControls(); - LocalParticipant *lp = room->localParticipant(); + LocalParticipant* lp = room->localParticipant(); double x = 0.0, y = 0.0, z = 0.0; bool receiver_connected = false; auto last_receiver_check = std::chrono::steady_clock::now(); @@ -165,12 +163,10 @@ int main(int argc, char *argv[]) { bool receiver_present = (room->remoteParticipant("robot") != nullptr); if (receiver_present && !receiver_connected) { - std::cout - << "[Sender] Receiver connected! Use keys to send commands.\n"; + std::cout << "[Sender] Receiver connected! Use keys to send commands.\n"; receiver_connected = true; } else if (!receiver_present && receiver_connected) { - std::cout - << "[Sender] Receiver disconnected. Waiting for reconnect...\n"; + std::cout << "[Sender] Receiver disconnected. Waiting for reconnect...\n"; receiver_connected = false; } } @@ -191,46 +187,44 @@ int main(int argc, char *argv[]) { // Map key to axis change bool changed = false; switch (key) { - case 'w': - case 'W': - x += 1.0; - changed = true; - break; - case 's': - case 'S': - x -= 1.0; - changed = true; - break; - case 'd': - case 'D': - y += 1.0; - changed = true; - break; - case 'a': - case 'A': - y -= 1.0; - changed = true; - break; - case 'z': - case 'Z': - z += 1.0; - changed = true; - break; - case 'c': - case 'C': - z -= 1.0; - changed = true; - break; - default: - break; + case 'w': + case 'W': + x += 1.0; + changed = true; + break; + case 's': + case 'S': + x -= 1.0; + changed = true; + break; + case 'd': + case 'D': + y += 1.0; + changed = true; + break; + case 'a': + case 'A': + y -= 1.0; + changed = true; + break; + case 'z': + case 'Z': + z += 1.0; + changed = true; + break; + case 'c': + case 'C': + z -= 1.0; + changed = true; + break; + default: + break; } - if (!changed) - continue; + if (!changed) continue; if (!receiver_connected) { - std::cout << "[Sender] (no receiver connected) x=" << x << " y=" << y - << " z=" << z << "\n"; + std::cout << "[Sender] (no receiver connected) x=" << x << " y=" << y << " z=" << z << "\n"; continue; } @@ -238,22 +232,18 @@ int main(int argc, char *argv[]) { simple_joystick::JoystickCommand cmd{x, y, z}; std::string payload = simple_joystick::joystick_to_json(cmd); - std::cout << "[Sender] Sending: x=" << x << " y=" << y << " z=" << z - << "\n"; + std::cout << "[Sender] Sending: x=" << x << " y=" << y << " z=" << z << "\n"; try { - std::string response = - lp->performRpc("robot", "joystick_command", payload, 5.0); + std::string response = lp->performRpc("robot", "joystick_command", payload, 5.0); std::cout << "[Sender] Receiver acknowledged: " << response << "\n"; - } catch (const RpcError &e) { + } catch (const RpcError& e) { std::cerr << "[Sender] RPC error: " << e.message() << "\n"; - if (static_cast(e.code()) == - RpcError::ErrorCode::RECIPIENT_DISCONNECTED) { - std::cout - << "[Sender] Receiver disconnected. Waiting for reconnect...\n"; + if (static_cast(e.code()) == RpcError::ErrorCode::RECIPIENT_DISCONNECTED) { + std::cout << "[Sender] Receiver disconnected. Waiting for reconnect...\n"; receiver_connected = false; } - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[Sender] Error sending command: " << e.what() << "\n"; } } diff --git a/simple_joystick_sender/utils.cpp b/simple_joystick_sender/utils.cpp index cc0ef96..fca40fb 100644 --- a/simple_joystick_sender/utils.cpp +++ b/simple_joystick_sender/utils.cpp @@ -22,7 +22,7 @@ namespace simple_joystick { -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token) { for (int i = 1; i < argc; ++i) { std::string a = argv[i]; if (a == "-h" || a == "--help") { @@ -30,7 +30,7 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { } } - auto get_flag_value = [&](const std::string &name, int &i) -> std::string { + auto get_flag_value = [&](const std::string& name, int& i) -> std::string { std::string arg = argv[i]; const std::string eq = name + "="; if (arg.rfind(name, 0) == 0) { @@ -47,12 +47,10 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { const std::string a = argv[i]; if (a.rfind("--url", 0) == 0) { auto v = get_flag_value("--url", i); - if (!v.empty()) - url = v; + if (!v.empty()) url = v; } else if (a.rfind("--token", 0) == 0) { auto v = get_flag_value("--token", i); - if (!v.empty()) - token = v; + if (!v.empty()) token = v; } } @@ -60,25 +58,20 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token) { std::vector pos; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; - if (a.rfind("--", 0) == 0) - continue; + if (a.rfind("--", 0) == 0) continue; pos.push_back(std::move(a)); } - if (url.empty() && pos.size() >= 1) - url = pos[0]; - if (token.empty() && pos.size() >= 2) - token = pos[1]; + if (url.empty() && pos.size() >= 1) url = pos[0]; + if (token.empty() && pos.size() >= 2) token = pos[1]; // Environment variable fallbacks if (url.empty()) { - const char *e = std::getenv("LIVEKIT_URL"); - if (e) - url = e; + const char* e = std::getenv("LIVEKIT_URL"); + if (e) url = e; } if (token.empty()) { - const char *e = std::getenv("LIVEKIT_TOKEN"); - if (e) - token = e; + const char* e = std::getenv("LIVEKIT_TOKEN"); + if (e) token = e; } return !(url.empty() || token.empty()); diff --git a/simple_joystick_sender/utils.h b/simple_joystick_sender/utils.h index 7fe94ee..c76e623 100644 --- a/simple_joystick_sender/utils.h +++ b/simple_joystick_sender/utils.h @@ -26,6 +26,6 @@ namespace simple_joystick { /// - Flags: --url= / --url , --token= / --token /// - Env vars: LIVEKIT_URL, LIVEKIT_TOKEN /// Returns true if both url and token were resolved, false otherwise. -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token); +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token); } // namespace simple_joystick diff --git a/simple_room/fallback_capture.cpp b/simple_room/fallback_capture.cpp index 6590c09..9fa080e 100644 --- a/simple_room/fallback_capture.cpp +++ b/simple_room/fallback_capture.cpp @@ -29,8 +29,7 @@ using namespace livekit; // Test utils to run a capture loop to publish noisy audio frames to the room -void runNoiseCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag) { +void runNoiseCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag) { const int sample_rate = source->sample_rate(); const int num_channels = source->num_channels(); const int frame_ms = 10; @@ -42,14 +41,12 @@ void runNoiseCaptureLoop(const std::shared_ptr &source, using Clock = std::chrono::steady_clock; auto next_deadline = Clock::now(); while (running_flag.load(std::memory_order_relaxed)) { - AudioFrame frame = - AudioFrame::create(sample_rate, num_channels, samples_per_channel); + AudioFrame frame = AudioFrame::create(sample_rate, num_channels, samples_per_channel); wavSource.fillFrame(frame); try { source->captureFrame(frame); - } catch (const std::exception &e) { - std::cerr << "[error] Error in captureFrame (noise): " << e.what() - << "\n"; + } catch (const std::exception& e) { + std::cerr << "[error] Error in captureFrame (noise): " << e.what() << "\n"; break; } @@ -66,38 +63,35 @@ void runNoiseCaptureLoop(const std::shared_ptr &source, } // Fake video source: solid color cycling -void runFakeVideoCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag) { +void runFakeVideoCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag) { auto frame = VideoFrame::create(1280, 720, VideoBufferType::BGRA); const double framerate = 1.0 / 30.0; while (running_flag.load(std::memory_order_relaxed)) { static auto start = std::chrono::high_resolution_clock::now(); - float t = std::chrono::duration( - std::chrono::high_resolution_clock::now() - start) - .count(); + float t = std::chrono::duration(std::chrono::high_resolution_clock::now() - start).count(); // Cycle every 4 seconds: 0=red, 1=green, 2=blue, 3=black int stage = static_cast(t) % 4; std::array rgb{}; switch (stage) { - case 0: // red - rgb = {255, 0, 0, 0}; - break; - case 1: // green - rgb = {0, 255, 0, 0}; - break; - case 2: // blue - rgb = {0, 0, 255, 0}; - break; - case 3: // black - default: - rgb = {0, 0, 0, 0}; - break; + case 0: // red + rgb = {255, 0, 0, 0}; + break; + case 1: // green + rgb = {0, 255, 0, 0}; + break; + case 2: // blue + rgb = {0, 0, 255, 0}; + break; + case 3: // black + default: + rgb = {0, 0, 0, 0}; + break; } // ARGB - uint8_t *data = frame.data(); + uint8_t* data = frame.data(); const size_t size = frame.dataSize(); for (size_t i = 0; i < size; i += 4) { data[i + 0] = 255; // A @@ -110,9 +104,8 @@ void runFakeVideoCaptureLoop(const std::shared_ptr &source, // If VideoSource is ARGB-capable, pass frame. // If it expects I420, pass i420 instead. source->captureFrame(frame, 0, VideoRotation::VIDEO_ROTATION_0); - } catch (const std::exception &e) { - std::cerr << "[error] Error in captureFrame (fake video): " << e.what() - << "\n"; + } catch (const std::exception& e) { + std::cerr << "[error] Error in captureFrame (fake video): " << e.what() << "\n"; break; } diff --git a/simple_room/fallback_capture.h b/simple_room/fallback_capture.h index a7d8536..fcfbd78 100644 --- a/simple_room/fallback_capture.h +++ b/simple_room/fallback_capture.h @@ -27,9 +27,6 @@ class AudioSource; class VideoSource; } // namespace livekit -void runNoiseCaptureLoop(const std::shared_ptr &source, - std::atomic &running_flag); +void runNoiseCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag); -void runFakeVideoCaptureLoop( - const std::shared_ptr &source, - std::atomic &running_flag); +void runFakeVideoCaptureLoop(const std::shared_ptr& source, std::atomic& running_flag); diff --git a/simple_room/main.cpp b/simple_room/main.cpp index c2e7778..8b9367f 100644 --- a/simple_room/main.cpp +++ b/simple_room/main.cpp @@ -36,31 +36,27 @@ namespace { std::atomic g_running{true}; -void printUsage(const char *prog) { - std::cerr - << "Usage:\n" - << " " << prog - << " [--enable_e2ee] [--e2ee_key ]\n" - << "or:\n" - << " " << prog - << " --url= --token= [--enable_e2ee] [--e2ee_key=]\n" - << " " << prog - << " --url --token [--enable_e2ee] [--e2ee_key " - "]\n\n" - << "E2EE:\n" - << " --enable_e2ee Enable end-to-end encryption (E2EE)\n" - << " --e2ee_key Optional shared key (UTF-8). If omitted, " - "E2EE is enabled\n" - << " but no shared key is set (advanced " - "usage).\n\n" - << "Env fallbacks:\n" - << " LIVEKIT_URL, LIVEKIT_TOKEN, LIVEKIT_E2EE_KEY\n"; +void printUsage(const char* prog) { + std::cerr << "Usage:\n" + << " " << prog << " [--enable_e2ee] [--e2ee_key ]\n" + << "or:\n" + << " " << prog << " --url= --token= [--enable_e2ee] [--e2ee_key=]\n" + << " " << prog + << " --url --token [--enable_e2ee] [--e2ee_key " + "]\n\n" + << "E2EE:\n" + << " --enable_e2ee Enable end-to-end encryption (E2EE)\n" + << " --e2ee_key Optional shared key (UTF-8). If omitted, " + "E2EE is enabled\n" + << " but no shared key is set (advanced " + "usage).\n\n" + << "Env fallbacks:\n" + << " LIVEKIT_URL, LIVEKIT_TOKEN, LIVEKIT_E2EE_KEY\n"; } void handleSignal(int) { g_running.store(false); } -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, - bool &enable_e2ee, std::string &e2ee_key) { +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token, bool& enable_e2ee, std::string& e2ee_key) { enable_e2ee = false; // --help for (int i = 1; i < argc; ++i) { @@ -71,7 +67,7 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, } // flags: --url= / --token= or split form - auto get_flag_value = [&](const std::string &name, int &i) -> std::string { + auto get_flag_value = [&](const std::string& name, int& i) -> std::string { std::string arg = argv[i]; const std::string eq = name + "="; if (arg.rfind(name, 0) == 0) { // starts with name @@ -90,16 +86,13 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, enable_e2ee = true; } else if (a.rfind("--url", 0) == 0) { auto v = get_flag_value("--url", i); - if (!v.empty()) - url = v; + if (!v.empty()) url = v; } else if (a.rfind("--token", 0) == 0) { auto v = get_flag_value("--token", i); - if (!v.empty()) - token = v; + if (!v.empty()) token = v; } else if (a.rfind("--e2ee_key", 0) == 0) { auto v = get_flag_value("--e2ee_key", i); - if (!v.empty()) - e2ee_key = v; + if (!v.empty()) e2ee_key = v; } } @@ -108,33 +101,27 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, std::vector pos; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; - if (a.rfind("--", 0) == 0) - continue; // skip flags we already parsed + if (a.rfind("--", 0) == 0) continue; // skip flags we already parsed pos.push_back(std::move(a)); } if (pos.size() >= 2) { - if (url.empty()) - url = pos[0]; - if (token.empty()) - token = pos[1]; + if (url.empty()) url = pos[0]; + if (token.empty()) token = pos[1]; } } // 4) env fallbacks if (url.empty()) { - const char *e = std::getenv("LIVEKIT_URL"); - if (e) - url = e; + const char* e = std::getenv("LIVEKIT_URL"); + if (e) url = e; } if (token.empty()) { - const char *e = std::getenv("LIVEKIT_TOKEN"); - if (e) - token = e; + const char* e = std::getenv("LIVEKIT_TOKEN"); + if (e) token = e; } if (e2ee_key.empty()) { - const char *e = std::getenv("LIVEKIT_E2EE_KEY"); - if (e) - e2ee_key = e; + const char* e = std::getenv("LIVEKIT_E2EE_KEY"); + if (e) e2ee_key = e; } return !(url.empty() || token.empty()); @@ -169,26 +156,18 @@ class MainThreadDispatcher { class SimpleRoomDelegate : public livekit::RoomDelegate { public: - explicit SimpleRoomDelegate(SDLMediaManager &media) : media_(media) {} + explicit SimpleRoomDelegate(SDLMediaManager& media) : media_(media) {} - void onParticipantConnected( - livekit::Room & /*room*/, - const livekit::ParticipantConnectedEvent &ev) override { - std::cout << "[Room] participant connected: identity=" - << ev.participant->identity() + void onParticipantConnected(livekit::Room& /*room*/, const livekit::ParticipantConnectedEvent& ev) override { + std::cout << "[Room] participant connected: identity=" << ev.participant->identity() << " name=" << ev.participant->name() << "\n"; } - void onTrackSubscribed(livekit::Room & /*room*/, - const livekit::TrackSubscribedEvent &ev) override { - const char *participant_identity = - ev.participant ? ev.participant->identity().c_str() : ""; - const std::string track_sid = - ev.publication ? ev.publication->sid() : ""; - const std::string track_name = - ev.publication ? ev.publication->name() : ""; - std::cout << "[Room] track subscribed: participant_identity=" - << participant_identity << " track_sid=" << track_sid + void onTrackSubscribed(livekit::Room& /*room*/, const livekit::TrackSubscribedEvent& ev) override { + const char* participant_identity = ev.participant ? ev.participant->identity().c_str() : ""; + const std::string track_sid = ev.publication ? ev.publication->sid() : ""; + const std::string track_name = ev.publication ? ev.publication->name() : ""; + std::cout << "[Room] track subscribed: participant_identity=" << participant_identity << " track_sid=" << track_sid << " name=" << track_name; if (ev.track) { std::cout << " kind=" << static_cast(ev.track->kind()); @@ -225,22 +204,19 @@ class SimpleRoomDelegate : public livekit::RoomDelegate { } private: - SDLMediaManager &media_; + SDLMediaManager& media_; }; -static std::vector toBytes(const std::string &s) { - return std::vector(s.begin(), s.end()); -} +static std::vector toBytes(const std::string& s) { return std::vector(s.begin(), s.end()); } void print_livekit_version() { - std::cout << "LiveKit version: " << LIVEKIT_BUILD_VERSION_FULL << " (" - << LIVEKIT_BUILD_FLAVOR << ", commit " << LIVEKIT_BUILD_COMMIT - << ", built " << LIVEKIT_BUILD_DATE << ")" << std::endl; + std::cout << "LiveKit version: " << LIVEKIT_BUILD_VERSION_FULL << " (" << LIVEKIT_BUILD_FLAVOR << ", commit " + << LIVEKIT_BUILD_COMMIT << ", built " << LIVEKIT_BUILD_DATE << ")" << std::endl; } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { print_livekit_version(); std::string url, token; bool enable_e2ee = false; @@ -290,8 +266,7 @@ int main(int argc, char *argv[]) { } options.encryption = encryption; if (!e2ee_key.empty()) { - std::cout << "[E2EE] enabled : (shared key length=" << e2ee_key.size() - << ")\n"; + std::cout << "[E2EE] enabled : (shared key length=" << e2ee_key.size() << ")\n"; } else { std::cout << "[E2EE] enabled: (no shared key set)\n"; } @@ -313,20 +288,16 @@ int main(int argc, char *argv[]) { << " Max participants: " << info.max_participants << "\n" << " Num participants: " << info.num_participants << "\n" << " Num publishers: " << info.num_publishers << "\n" - << " Active recording: " << (info.active_recording ? "yes" : "no") - << "\n" + << " Active recording: " << (info.active_recording ? "yes" : "no") << "\n" << " Empty timeout (s): " << info.empty_timeout << "\n" << " Departure timeout (s): " << info.departure_timeout << "\n" - << " Lossy DC low threshold: " - << info.lossy_dc_buffered_amount_low_threshold << "\n" - << " Reliable DC low threshold: " - << info.reliable_dc_buffered_amount_low_threshold << "\n" + << " Lossy DC low threshold: " << info.lossy_dc_buffered_amount_low_threshold << "\n" + << " Reliable DC low threshold: " << info.reliable_dc_buffered_amount_low_threshold << "\n" << " Creation time (ms): " << info.creation_time << "\n"; // Setup Audio Source / Track auto audioSource = std::make_shared(44100, 1, 0); - auto audioTrack = - LocalAudioTrack::createLocalAudioTrack("micTrack", audioSource); + auto audioTrack = LocalAudioTrack::createLocalAudioTrack("micTrack", audioSource); TrackPublishOptions audioOpts; audioOpts.source = TrackSource::SOURCE_MICROPHONE; @@ -341,10 +312,9 @@ int main(int argc, char *argv[]) { << " Name: " << audioPub->name() << "\n" << " Kind: " << static_cast(audioPub->kind()) << "\n" << " Source: " << static_cast(audioPub->source()) << "\n" - << " Simulcasted: " << std::boolalpha << audioPub->simulcasted() - << "\n" + << " Simulcasted: " << std::boolalpha << audioPub->simulcasted() << "\n" << " Muted: " << std::boolalpha << audioPub->muted() << "\n"; - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[error] Failed to publish track: " << e.what() << "\n"; } @@ -370,10 +340,9 @@ int main(int argc, char *argv[]) { << " Name: " << videoPub->name() << "\n" << " Kind: " << static_cast(videoPub->kind()) << "\n" << " Source: " << static_cast(videoPub->source()) << "\n" - << " Simulcasted: " << std::boolalpha << videoPub->simulcasted() - << "\n" + << " Simulcasted: " << std::boolalpha << videoPub->simulcasted() << "\n" << " Muted: " << std::boolalpha << videoPub->muted() << "\n"; - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[error] Failed to publish track: " << e.what() << "\n"; } media.startCamera(videoSource); diff --git a/simple_room/sdl_media.cpp b/simple_room/sdl_media.cpp index 21a4fea..e6e8503 100644 --- a/simple_room/sdl_media.cpp +++ b/simple_room/sdl_media.cpp @@ -20,10 +20,8 @@ // ---------------------- SDLMicSource ----------------------------- -SDLMicSource::SDLMicSource(int sample_rate, int channels, int frame_samples, - AudioCallback cb) - : sample_rate_(sample_rate), channels_(channels), - frame_samples_(frame_samples), callback_(std::move(cb)) {} +SDLMicSource::SDLMicSource(int sample_rate, int channels, int frame_samples, AudioCallback cb) + : sample_rate_(sample_rate), channels_(channels), frame_samples_(frame_samples), callback_(std::move(cb)) {} SDLMicSource::~SDLMicSource() { if (stream_) { @@ -41,11 +39,10 @@ bool SDLMicSource::init() { // Open default recording device as an audio stream // This works for both playback and recording, depending on the device id. - stream_ = SDL_OpenAudioDeviceStream( - SDL_AUDIO_DEVICE_DEFAULT_RECORDING, // recording device - &spec_, - nullptr, // no callback, we'll poll - nullptr); + stream_ = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_RECORDING, // recording device + &spec_, + nullptr, // no callback, we'll poll + nullptr); if (!stream_) { std::cerr << "[error] Failed to open recording stream: " << SDL_GetError() << "\n"; @@ -61,8 +58,7 @@ bool SDLMicSource::init() { } void SDLMicSource::pump() { - if (!stream_ || !callback_) - return; + if (!stream_ || !callback_) return; const int samples_per_frame_total = frame_samples_ * channels_; const int bytes_per_frame = samples_per_frame_total * sizeof(int16_t); @@ -102,8 +98,7 @@ void SDLMicSource::resume() { // ---------------------- DDLSpeakerSink ----------------------------- -DDLSpeakerSink::DDLSpeakerSink(int sample_rate, int channels) - : sample_rate_(sample_rate), channels_(channels) {} +DDLSpeakerSink::DDLSpeakerSink(int sample_rate, int channels) : sample_rate_(sample_rate), channels_(channels) {} DDLSpeakerSink::~DDLSpeakerSink() { if (stream_) { @@ -136,10 +131,8 @@ bool DDLSpeakerSink::init() { return true; } -void DDLSpeakerSink::enqueue(const int16_t *samples, - int num_samples_per_channel) { - if (!stream_ || !samples) - return; +void DDLSpeakerSink::enqueue(const int16_t* samples, int num_samples_per_channel) { + if (!stream_ || !samples) return; const int totalSamples = num_samples_per_channel * channels_; const int bytes = totalSamples * static_cast(sizeof(int16_t)); @@ -164,11 +157,13 @@ void DDLSpeakerSink::resume() { // ---------------------- SDLCamSource ----------------------------- -SDLCamSource::SDLCamSource(int desired_width, int desired_height, - int desired_fps, SDL_PixelFormat pixel_format, +SDLCamSource::SDLCamSource(int desired_width, int desired_height, int desired_fps, SDL_PixelFormat pixel_format, VideoCallback cb) - : width_(desired_width), height_(desired_height), fps_(desired_fps), - format_(pixel_format), callback_(std::move(cb)) {} + : width_(desired_width), + height_(desired_height), + fps_(desired_fps), + format_(pixel_format), + callback_(std::move(cb)) {} SDLCamSource::~SDLCamSource() { if (camera_) { @@ -179,11 +174,10 @@ SDLCamSource::~SDLCamSource() { bool SDLCamSource::init() { int count = 0; - SDL_CameraID *cams = SDL_GetCameras(&count); // + SDL_CameraID* cams = SDL_GetCameras(&count); // if (!cams || count == 0) { std::cerr << "[error] No cameras available: " << SDL_GetError() << "\n"; - if (cams) - SDL_free(cams); + if (cams) SDL_free(cams); return false; } @@ -210,17 +204,15 @@ bool SDLCamSource::init() { } void SDLCamSource::pump() { - if (!camera_ || !callback_) - return; + if (!camera_ || !callback_) return; Uint64 tsNS = 0; - SDL_Surface *surf = SDL_AcquireCameraFrame(camera_, &tsNS); // non-blocking + SDL_Surface* surf = SDL_AcquireCameraFrame(camera_, &tsNS); // non-blocking if (!surf) { return; } - callback_(static_cast(surf->pixels), surf->pitch, surf->w, surf->h, - surf->format, tsNS); + callback_(static_cast(surf->pixels), surf->pitch, surf->w, surf->h, surf->format, tsNS); SDL_ReleaseCameraFrame(camera_, surf); // } diff --git a/simple_room/sdl_media.h b/simple_room/sdl_media.h index a60bca6..7ed2a08 100644 --- a/simple_room/sdl_media.h +++ b/simple_room/sdl_media.h @@ -17,6 +17,7 @@ #pragma once #include + #include #include #include @@ -29,12 +30,10 @@ // AudioCallback. class SDLMicSource { public: - using AudioCallback = std::function; + using AudioCallback = std::function; - SDLMicSource(int sample_rate = 48000, int channels = 1, - int frame_samples = 480, AudioCallback cb = nullptr); + SDLMicSource(int sample_rate = 48000, int channels = 1, int frame_samples = 480, AudioCallback cb = nullptr); ~SDLMicSource(); @@ -50,7 +49,7 @@ class SDLMicSource { bool isValid() const { return stream_ != nullptr; } private: - SDL_AudioStream *stream_ = nullptr; + SDL_AudioStream* stream_ = nullptr; SDL_AudioSpec spec_{}; int sample_rate_; int channels_; @@ -72,7 +71,7 @@ class DDLSpeakerSink { bool init(); // Enqueue interleaved S16 samples for playback. - void enqueue(const int16_t *samples, int num_samples_per_channel); + void enqueue(const int16_t* samples, int num_samples_per_channel); void pause(); void resume(); @@ -80,7 +79,7 @@ class DDLSpeakerSink { bool isValid() const { return stream_ != nullptr; } private: - SDL_AudioStream *stream_ = nullptr; + SDL_AudioStream* stream_ = nullptr; SDL_AudioSpec spec_{}; int sample_rate_; int channels_; @@ -98,15 +97,12 @@ class DDLSpeakerSink { // - tell LiveKit that this is ARGB with the given stride. class SDLCamSource { public: - using VideoCallback = std::function; + using VideoCallback = std::function; - SDLCamSource(int desired_width = 1280, int desired_height = 720, - int desired_fps = 30, - SDL_PixelFormat pixelFormat = SDL_PIXELFORMAT_RGBA8888, - VideoCallback cb = nullptr); + SDLCamSource(int desired_width = 1280, int desired_height = 720, int desired_fps = 30, + SDL_PixelFormat pixelFormat = SDL_PIXELFORMAT_RGBA8888, VideoCallback cb = nullptr); ~SDLCamSource(); @@ -118,7 +114,7 @@ class SDLCamSource { bool isValid() const { return camera_ != nullptr; } private: - SDL_Camera *camera_ = nullptr; + SDL_Camera* camera_ = nullptr; SDL_CameraSpec spec_{}; int width_; int height_; diff --git a/simple_room/sdl_media_manager.cpp b/simple_room/sdl_media_manager.cpp index 66f703e..b0be500 100644 --- a/simple_room/sdl_media_manager.cpp +++ b/simple_room/sdl_media_manager.cpp @@ -16,13 +16,14 @@ #include "sdl_media_manager.h" +#include +#include +#include + #include "fallback_capture.h" #include "livekit/livekit.h" -#include #include "sdl_media.h" #include "sdl_video_renderer.h" -#include -#include using namespace livekit; SDLMediaManager::SDLMediaManager() = default; @@ -47,8 +48,7 @@ bool SDLMediaManager::ensureSDLInit(Uint32 flags) { // ---------- Mic control ---------- -bool SDLMediaManager::startMic( - const std::shared_ptr &audio_source) { +bool SDLMediaManager::startMic(const std::shared_ptr& audio_source) { stopMic(); if (!audio_source) { @@ -63,20 +63,17 @@ bool SDLMediaManager::startMic( if (!ensureSDLInit(SDL_INIT_AUDIO)) { std::cerr << "[warn] No SDL audio, falling back to noise loop.\n"; mic_using_sdl_ = false; - mic_thread_ = - std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); + mic_thread_ = std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); return true; } int recCount = 0; - SDL_AudioDeviceID *recDevs = SDL_GetAudioRecordingDevices(&recCount); + SDL_AudioDeviceID* recDevs = SDL_GetAudioRecordingDevices(&recCount); if (!recDevs || recCount == 0) { std::cerr << "[warn] No microphone devices found, falling back to noise loop.\n"; - if (recDevs) - SDL_free(recDevs); + if (recDevs) SDL_free(recDevs); mic_using_sdl_ = false; - mic_thread_ = - std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); + mic_thread_ = std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); return true; } SDL_free(recDevs); @@ -87,15 +84,12 @@ bool SDLMediaManager::startMic( mic_sdl_ = std::make_unique( mic_source_->sample_rate(), mic_source_->num_channels(), mic_source_->sample_rate() / 100, // ~10ms - [src = mic_source_](const int16_t *samples, int num_samples_per_channel, - int sample_rate, int num_channels) { - AudioFrame frame = AudioFrame::create(sample_rate, num_channels, - num_samples_per_channel); - std::memcpy(frame.data().data(), samples, - num_samples_per_channel * num_channels * sizeof(int16_t)); + [src = mic_source_](const int16_t* samples, int num_samples_per_channel, int sample_rate, int num_channels) { + AudioFrame frame = AudioFrame::create(sample_rate, num_channels, num_samples_per_channel); + std::memcpy(frame.data().data(), samples, num_samples_per_channel * num_channels * sizeof(int16_t)); try { src->captureFrame(frame); - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[error] Error in captureFrame (SDL mic): " << e.what() << "\n"; } }); @@ -104,8 +98,7 @@ bool SDLMediaManager::startMic( std::cerr << "[warn] Failed to init SDL mic, falling back to noise loop.\n"; mic_using_sdl_ = false; mic_sdl_.reset(); - mic_thread_ = - std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); + mic_thread_ = std::thread(runNoiseCaptureLoop, mic_source_, std::ref(mic_running_)); return true; } @@ -131,8 +124,7 @@ void SDLMediaManager::stopMic() { // ---------- Camera control ---------- -bool SDLMediaManager::startCamera( - const std::shared_ptr &video_source) { +bool SDLMediaManager::startCamera(const std::shared_ptr& video_source) { stopCamera(); if (!video_source) { @@ -147,54 +139,48 @@ bool SDLMediaManager::startCamera( if (!ensureSDLInit(SDL_INIT_CAMERA)) { std::cerr << "[warn] No SDL camera subsystem, using fake video loop.\n"; cam_using_sdl_ = false; - cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, - std::ref(cam_running_)); + cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, std::ref(cam_running_)); return true; } int camCount = 0; - SDL_CameraID *cams = SDL_GetCameras(&camCount); + SDL_CameraID* cams = SDL_GetCameras(&camCount); if (!cams || camCount == 0) { std::cerr << "[warn] No camera devices found, using fake video loop.\n"; - if (cams) - SDL_free(cams); + if (cams) SDL_free(cams); cam_using_sdl_ = false; - cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, - std::ref(cam_running_)); + cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, std::ref(cam_running_)); return true; } SDL_free(cams); cam_using_sdl_ = true; - can_sdl_ = std::make_unique( - 1280, 720, 30, - SDL_PIXELFORMAT_RGBA32, // Note SDL_PIXELFORMAT_RGBA8888 is not compatable - // with Livekit RGBA format. - [src = cam_source_](const uint8_t *pixels, int pitch, int width, - int height, SDL_PixelFormat /*fmt*/, - Uint64 timestampNS) { - auto frame = VideoFrame::create(width, height, VideoBufferType::RGBA); - uint8_t *dst = frame.data(); - const int dstPitch = width * 4; - - for (int y = 0; y < height; ++y) { - std::memcpy(dst + y * dstPitch, pixels + y * pitch, dstPitch); - } - - try { - src->captureFrame(frame, timestampNS / 1000, - VideoRotation::VIDEO_ROTATION_0); - } catch (const std::exception &e) { - std::cerr << "[error] Error in captureFrame (SDL cam): " << e.what() << "\n"; - } - }); + can_sdl_ = + std::make_unique(1280, 720, 30, + SDL_PIXELFORMAT_RGBA32, // Note SDL_PIXELFORMAT_RGBA8888 is not compatable + // with Livekit RGBA format. + [src = cam_source_](const uint8_t* pixels, int pitch, int width, int height, + SDL_PixelFormat /*fmt*/, Uint64 timestampNS) { + auto frame = VideoFrame::create(width, height, VideoBufferType::RGBA); + uint8_t* dst = frame.data(); + const int dstPitch = width * 4; + + for (int y = 0; y < height; ++y) { + std::memcpy(dst + y * dstPitch, pixels + y * pitch, dstPitch); + } + + try { + src->captureFrame(frame, timestampNS / 1000, VideoRotation::VIDEO_ROTATION_0); + } catch (const std::exception& e) { + std::cerr << "[error] Error in captureFrame (SDL cam): " << e.what() << "\n"; + } + }); if (!can_sdl_->init()) { std::cerr << "[warn] Failed to init SDL camera, using fake video loop.\n"; cam_using_sdl_ = false; can_sdl_.reset(); - cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, - std::ref(cam_running_)); + cam_thread_ = std::thread(runFakeVideoCaptureLoop, cam_source_, std::ref(cam_running_)); return true; } @@ -220,8 +206,7 @@ void SDLMediaManager::stopCamera() { // ---------- Speaker control (placeholder) ---------- -bool SDLMediaManager::startSpeaker( - const std::shared_ptr &audio_stream) { +bool SDLMediaManager::startSpeaker(const std::shared_ptr& audio_stream) { stopSpeaker(); if (!audio_stream) { @@ -242,7 +227,7 @@ bool SDLMediaManager::startSpeaker( // format. try { speaker_thread_ = std::thread(&SDLMediaManager::speakerLoopSDL, this); - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "[error] startSpeaker: failed to start speaker thread: " << e.what() << "\n"; speaker_running_.store(false, std::memory_order_relaxed); speaker_stream_.reset(); @@ -253,7 +238,7 @@ bool SDLMediaManager::startSpeaker( } void SDLMediaManager::speakerLoopSDL() { - SDL_AudioStream *localStream = nullptr; + SDL_AudioStream* localStream = nullptr; SDL_AudioDeviceID dev = 0; while (speaker_running_.load(std::memory_order_relaxed)) { @@ -267,8 +252,8 @@ void SDLMediaManager::speakerLoopSDL() { break; } - const livekit::AudioFrame &frame = ev.frame; - const auto &data = frame.data(); + const livekit::AudioFrame& frame = ev.frame; + const auto& data = frame.data(); if (data.empty()) { continue; } @@ -281,10 +266,9 @@ void SDLMediaManager::speakerLoopSDL() { want.channels = static_cast(frame.num_channels()); want.freq = frame.sample_rate(); - localStream = - SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &want, - /*callback=*/nullptr, - /*userdata=*/nullptr); + localStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &want, + /*callback=*/nullptr, + /*userdata=*/nullptr); if (!localStream) { std::cerr << "[error] speakerLoopSDL: SDL_OpenAudioDeviceStream failed: " << SDL_GetError() << "\n"; @@ -341,8 +325,7 @@ void SDLMediaManager::stopSpeaker() { // ---------- Renderer control (placeholder) ---------- -bool SDLMediaManager::initRenderer( - const std::shared_ptr &video_stream) { +bool SDLMediaManager::initRenderer(const std::shared_ptr& video_stream) { if (!video_stream) { std::cerr << "[error] startRenderer: videoStream is null\n"; return false; diff --git a/simple_room/sdl_media_manager.h b/simple_room/sdl_media_manager.h index cd9ba46..15e059f 100644 --- a/simple_room/sdl_media_manager.h +++ b/simple_room/sdl_media_manager.h @@ -16,14 +16,14 @@ #pragma once -#include -#include -#include - #include #include #include +#include +#include +#include + #include "wav_audio_source.h" namespace livekit { @@ -49,20 +49,20 @@ class SDLMediaManager { ~SDLMediaManager(); // Mic (local capture -> AudioSource) - bool startMic(const std::shared_ptr &audio_source); + bool startMic(const std::shared_ptr& audio_source); void stopMic(); // Camera (local capture -> VideoSource) - bool startCamera(const std::shared_ptr &video_source); + bool startCamera(const std::shared_ptr& video_source); void stopCamera(); // Speaker (remote audio playback) - bool startSpeaker(const std::shared_ptr &audio_stream); + bool startSpeaker(const std::shared_ptr& audio_stream); void stopSpeaker(); // Renderer (remote video rendering) // Following APIs must be called on main thread - bool initRenderer(const std::shared_ptr &video_stream); + bool initRenderer(const std::shared_ptr& video_stream); void shutdownRenderer(); void render(); @@ -99,7 +99,7 @@ class SDLMediaManager { std::shared_ptr speaker_stream_; std::thread speaker_thread_; std::atomic speaker_running_{false}; - SDL_AudioStream *sdl_audio_stream_ = nullptr; + SDL_AudioStream* sdl_audio_stream_ = nullptr; // Renderer (remote video) – left mostly as a placeholder std::unique_ptr sdl_renderer_; diff --git a/simple_room/sdl_video_renderer.cpp b/simple_room/sdl_video_renderer.cpp index 3554ccf..4584e42 100644 --- a/simple_room/sdl_video_renderer.cpp +++ b/simple_room/sdl_video_renderer.cpp @@ -16,9 +16,10 @@ #include "sdl_video_renderer.h" -#include "livekit/livekit.h" -#include #include +#include + +#include "livekit/livekit.h" using namespace livekit; @@ -28,7 +29,7 @@ SDLVideoRenderer::SDLVideoRenderer() = default; SDLVideoRenderer::~SDLVideoRenderer() { shutdown(); } -bool SDLVideoRenderer::init(const char *title, int width, int height) { +bool SDLVideoRenderer::init(const char* title, int width, int height) { width_ = width; height_ = height; @@ -47,8 +48,7 @@ bool SDLVideoRenderer::init(const char *title, int width, int height) { // Note, web will send out BGRA as default, and we can't use ARGB since ffi // does not support converting from BGRA to ARGB. - texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_STREAMING, width_, height_); + texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width_, height_); if (!texture_) { std::cerr << "[error] SDL_CreateTexture failed: " << SDL_GetError() << "\n"; return false; @@ -74,9 +74,7 @@ void SDLVideoRenderer::shutdown() { stream_.reset(); } -void SDLVideoRenderer::setStream(std::shared_ptr stream) { - stream_ = std::move(stream); -} +void SDLVideoRenderer::setStream(std::shared_ptr stream) { stream_ = std::move(stream); } void SDLVideoRenderer::render() { // 0) Basic sanity @@ -115,14 +113,14 @@ void SDLVideoRenderer::render() { return; } - livekit::VideoFrame &frame = vfe.frame; + livekit::VideoFrame& frame = vfe.frame; // 4) Ensure the frame is RGBA. // Ideally you requested RGBA from VideoStream::Options so this is a no-op. if (frame.type() != livekit::VideoBufferType::RGBA) { try { frame = frame.convert(livekit::VideoBufferType::RGBA, false); - } catch (const std::exception &ex) { + } catch (const std::exception& ex) { std::cerr << "[error] SDLVideoRenderer: convert to RGBA failed: " << ex.what() << "\n"; return; } @@ -137,11 +135,10 @@ void SDLVideoRenderer::render() { SDL_DestroyTexture(texture_); texture_ = nullptr; } - texture_ = SDL_CreateTexture( - renderer_, - SDL_PIXELFORMAT_RGBA32, // Note, SDL_PIXELFORMAT_RGBA8888 is not - // compatible with Livekit RGBA format. - SDL_TEXTUREACCESS_STREAMING, width_, height_); + texture_ = SDL_CreateTexture(renderer_, + SDL_PIXELFORMAT_RGBA32, // Note, SDL_PIXELFORMAT_RGBA8888 is not + // compatible with Livekit RGBA format. + SDL_TEXTUREACCESS_STREAMING, width_, height_); if (!texture_) { std::cerr << "[error] SDLVideoRenderer: SDL_CreateTexture failed: " << SDL_GetError() << "\n"; return; @@ -149,19 +146,18 @@ void SDLVideoRenderer::render() { } // 6) Upload RGBA data to SDL texture - void *pixels = nullptr; + void* pixels = nullptr; int pitch = 0; if (!SDL_LockTexture(texture_, nullptr, &pixels, &pitch)) { std::cerr << "[error] SDLVideoRenderer: SDL_LockTexture failed: " << SDL_GetError() << "\n"; return; } - const std::uint8_t *src = frame.data(); + const std::uint8_t* src = frame.data(); const int srcPitch = frame.width() * 4; // RGBA: 4 bytes per pixel for (int y = 0; y < frame.height(); ++y) { - std::memcpy(static_cast(pixels) + y * pitch, - src + y * srcPitch, srcPitch); + std::memcpy(static_cast(pixels) + y * pitch, src + y * srcPitch, srcPitch); } SDL_UnlockTexture(texture_); diff --git a/simple_room/sdl_video_renderer.h b/simple_room/sdl_video_renderer.h index fb0d41e..060693f 100644 --- a/simple_room/sdl_video_renderer.h +++ b/simple_room/sdl_video_renderer.h @@ -17,6 +17,7 @@ #pragma once #include + #include #include #include @@ -31,7 +32,7 @@ class SDLVideoRenderer { ~SDLVideoRenderer(); // Must be called on main thread, after SDL_Init(SDL_INIT_VIDEO). - bool init(const char *title, int width, int height); + bool init(const char* title, int width, int height); // Set/replace the stream to render. Safe to call from main thread. void setStream(std::shared_ptr stream); @@ -42,9 +43,9 @@ class SDLVideoRenderer { void shutdown(); // destroy window/renderer/texture private: - SDL_Window *window_ = nullptr; - SDL_Renderer *renderer_ = nullptr; - SDL_Texture *texture_ = nullptr; + SDL_Window* window_ = nullptr; + SDL_Renderer* renderer_ = nullptr; + SDL_Texture* texture_ = nullptr; std::shared_ptr stream_; int width_ = 0; diff --git a/simple_room/wav_audio_source.cpp b/simple_room/wav_audio_source.cpp index b519b81..62a430b 100644 --- a/simple_room/wav_audio_source.cpp +++ b/simple_room/wav_audio_source.cpp @@ -23,7 +23,7 @@ // -------------------------------------------------- // Minimal WAV loader (16-bit PCM only) // -------------------------------------------------- -WavData load_wav16(const std::string &path) { +WavData load_wav16(const std::string& path) { std::ifstream file(path, std::ios::binary); if (!file) { throw std::runtime_error("Failed to open WAV file: " + path + @@ -31,12 +31,8 @@ WavData load_wav16(const std::string &path) { "LFS is installed and run `git lfs pull`)"); } - auto read_u32 = [&](uint32_t &out_value) { - file.read(reinterpret_cast(&out_value), 4); - }; - auto read_u16 = [&](uint16_t &out_value) { - file.read(reinterpret_cast(&out_value), 2); - }; + auto read_u32 = [&](uint32_t& out_value) { file.read(reinterpret_cast(&out_value), 4); }; + auto read_u16 = [&](uint16_t& out_value) { file.read(reinterpret_cast(&out_value), 2); }; char riff[4]; file.read(riff, 4); @@ -101,7 +97,7 @@ WavData load_wav16(const std::string &path) { have_data = true; const std::size_t count = sub_size / sizeof(int16_t); samples.resize(count); - file.read(reinterpret_cast(samples.data()), sub_size); + file.read(reinterpret_cast(samples.data()), sub_size); } else { // Unknown chunk: skip it @@ -120,8 +116,7 @@ WavData load_wav16(const std::string &path) { return out; } -WavAudioSource::WavAudioSource(const std::string &path, - int expected_sample_rate, int expected_channels, +WavAudioSource::WavAudioSource(const std::string& path, int expected_sample_rate, int expected_channels, bool loop_enabled) : loop_enabled_(loop_enabled) { wav_ = load_wav16(path); @@ -139,12 +134,11 @@ WavAudioSource::WavAudioSource(const std::string &path, playhead_ = 0; } -void WavAudioSource::fillFrame(AudioFrame &frame) { +void WavAudioSource::fillFrame(AudioFrame& frame) { const std::size_t frame_samples = - static_cast(frame.num_channels()) * - static_cast(frame.samples_per_channel()); + static_cast(frame.num_channels()) * static_cast(frame.samples_per_channel()); - int16_t *dst = frame.data().data(); + int16_t* dst = frame.data().data(); const std::size_t total_wav_samples = wav_.samples.size(); for (std::size_t i = 0; i < frame_samples; ++i) { diff --git a/simple_room/wav_audio_source.h b/simple_room/wav_audio_source.h index 51a101c..c1d480f 100644 --- a/simple_room/wav_audio_source.h +++ b/simple_room/wav_audio_source.h @@ -17,12 +17,13 @@ #pragma once -#include "livekit/livekit.h" #include #include #include #include +#include "livekit/livekit.h" + // Simple WAV container for 16-bit PCM files struct WavData { int sample_rate = 0; @@ -31,18 +32,17 @@ struct WavData { }; // Helper that loads 16-bit PCM WAV (16-bit, PCM only) -WavData loadWav16(const std::string &path); +WavData loadWav16(const std::string& path); using namespace livekit; class WavAudioSource { public: // loop_enabled: whether to loop when reaching the end - WavAudioSource(const std::string &path, int expected_sample_rate, - int expected_channels, bool loop_enabled = true); + WavAudioSource(const std::string& path, int expected_sample_rate, int expected_channels, bool loop_enabled = true); // Fill a frame with the next chunk of audio. - void fillFrame(AudioFrame &frame); + void fillFrame(AudioFrame& frame); private: void initLoopDelayCounter(); diff --git a/simple_rpc/main.cpp b/simple_rpc/main.cpp index b171f9b..9ecdf74 100644 --- a/simple_rpc/main.cpp +++ b/simple_rpc/main.cpp @@ -43,14 +43,12 @@ std::atomic g_running{true}; void handleSignal(int) { g_running.store(false); } -void printUsage(const char *prog) { +void printUsage(const char* prog) { std::cerr << "Usage:\n" << " " << prog << " [role]\n" << "or:\n" - << " " << prog - << " --url= --token= [--role=]\n" - << " " << prog - << " --url --token [--role ]\n\n" + << " " << prog << " --url= --token= [--role=]\n" + << " " << prog << " --url --token [--role ]\n\n" << "Env fallbacks:\n" << " LIVEKIT_URL, LIVEKIT_TOKEN\n" << "Role (participant behavior):\n" @@ -59,15 +57,12 @@ void printUsage(const char *prog) { } inline double nowMs() { - return std::chrono::duration( - std::chrono::steady_clock::now().time_since_epoch()) - .count(); + return std::chrono::duration(std::chrono::steady_clock::now().time_since_epoch()).count(); } // Poll the room until a remote participant with the given identity appears, // or until 'timeout' elapses. Returns true if found, false on timeout. -bool waitForParticipant(Room *room, const std::string &identity, - std::chrono::milliseconds timeout) { +bool waitForParticipant(Room* room, const std::string& identity, std::chrono::milliseconds timeout) { auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < timeout) { @@ -81,15 +76,11 @@ bool waitForParticipant(Room *room, const std::string &identity, // For the caller: wait for a specific peer, and if they don't show up, // explain why and how to start them in another terminal. -bool ensurePeerPresent(Room *room, const std::string &identity, - const std::string &friendly_role, const std::string &url, - std::chrono::seconds timeout) { - std::cout << "[Caller] Waiting up to " << timeout.count() << "s for " - << friendly_role << " (identity=\"" << identity +bool ensurePeerPresent(Room* room, const std::string& identity, const std::string& friendly_role, + const std::string& url, std::chrono::seconds timeout) { + std::cout << "[Caller] Waiting up to " << timeout.count() << "s for " << friendly_role << " (identity=\"" << identity << "\") to join...\n"; - bool present = waitForParticipant( - room, identity, - std::chrono::duration_cast(timeout)); + bool present = waitForParticipant(room, identity, std::chrono::duration_cast(timeout)); if (present) { std::cout << "[Caller] " << friendly_role << " is present.\n"; return true; @@ -97,23 +88,18 @@ bool ensurePeerPresent(Room *room, const std::string &identity, // Timed out auto info = room->room_info(); const std::string room_name = info.name; - std::cout << "[Caller] Timed out after " << timeout.count() - << "s waiting for " << friendly_role << " (identity=\"" << identity - << "\").\n"; - std::cout << "[Caller] No participant with identity \"" << identity - << "\" appears to be connected to room \"" << room_name - << "\".\n\n"; - std::cout << "To start a " << friendly_role - << " in another terminal, run:\n\n" - << " lk token create -r test -i " << identity - << " --join --valid-for 99999h --dev --room=" << room_name << "\n" - << " ./build/examples/SimpleRpc " << url - << " $token --role=" << friendly_role << "\n\n"; + std::cout << "[Caller] Timed out after " << timeout.count() << "s waiting for " << friendly_role << " (identity=\"" + << identity << "\").\n"; + std::cout << "[Caller] No participant with identity \"" << identity << "\" appears to be connected to room \"" + << room_name << "\".\n\n"; + std::cout << "To start a " << friendly_role << " in another terminal, run:\n\n" + << " lk token create -r test -i " << identity << " --join --valid-for 99999h --dev --room=" << room_name + << "\n" + << " ./build/examples/SimpleRpc " << url << " $token --role=" << friendly_role << "\n\n"; return false; } -bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, - std::string &role) { +bool parseArgs(int argc, char* argv[], std::string& url, std::string& token, std::string& role) { // --help for (int i = 1; i < argc; ++i) { std::string a = argv[i]; @@ -123,7 +109,7 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, } // helper for flags - auto get_flag_value = [&](const std::string &name, int &i) -> std::string { + auto get_flag_value = [&](const std::string& name, int& i) -> std::string { std::string arg = argv[i]; const std::string eq = name + "="; if (arg.rfind(name, 0) == 0) { // starts with name @@ -141,24 +127,20 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, const std::string a = argv[i]; if (a.rfind("--url", 0) == 0) { auto v = get_flag_value("--url", i); - if (!v.empty()) - url = v; + if (!v.empty()) url = v; } else if (a.rfind("--token", 0) == 0) { auto v = get_flag_value("--token", i); - if (!v.empty()) - token = v; + if (!v.empty()) token = v; } else if (a.rfind("--role", 0) == 0) { auto v = get_flag_value("--role", i); - if (!v.empty()) - role = v; + if (!v.empty()) role = v; } } std::vector pos; for (int i = 1; i < argc; ++i) { std::string a = argv[i]; - if (a.rfind("--", 0) == 0) - continue; + if (a.rfind("--", 0) == 0) continue; pos.push_back(std::move(a)); } if (!pos.empty()) { @@ -174,19 +156,16 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, } if (url.empty()) { - const char *e = std::getenv("LIVEKIT_URL"); - if (e) - url = e; + const char* e = std::getenv("LIVEKIT_URL"); + if (e) url = e; } if (token.empty()) { - const char *e = std::getenv("LIVEKIT_TOKEN"); - if (e) - token = e; + const char* e = std::getenv("LIVEKIT_TOKEN"); + if (e) token = e; } if (role.empty()) { - const char *e = std::getenv("SIMPLE_RPC_ROLE"); - if (e) - role = e; + const char* e = std::getenv("SIMPLE_RPC_ROLE"); + if (e) role = e; } if (role.empty()) { role = "caller"; @@ -195,106 +174,90 @@ bool parseArgs(int argc, char *argv[], std::string &url, std::string &token, return !(url.empty() || token.empty()); } -std::string makeNumberJson(const std::string &key, double value) { +std::string makeNumberJson(const std::string& key, double value) { std::ostringstream oss; oss << "{\"" << key << "\":" << value << "}"; return oss.str(); } -std::string makeStringJson(const std::string &key, const std::string &value) { +std::string makeStringJson(const std::string& key, const std::string& value) { std::ostringstream oss; oss << "{\"" << key << "\":\"" << value << "\"}"; return oss.str(); } -double parseNumberFromJson(const std::string &json) { +double parseNumberFromJson(const std::string& json) { auto colon = json.find(':'); - if (colon == std::string::npos) - throw std::runtime_error("invalid json: " + json); + if (colon == std::string::npos) throw std::runtime_error("invalid json: " + json); auto start = colon + 1; auto end = json.find_first_of(",}", start); std::string num_str = json.substr(start, end - start); return std::stod(num_str); } -std::string parseStringFromJson(const std::string &json) { +std::string parseStringFromJson(const std::string& json) { auto colon = json.find(':'); - if (colon == std::string::npos) - throw std::runtime_error("invalid json: " + json); + if (colon == std::string::npos) throw std::runtime_error("invalid json: " + json); auto first_quote = json.find('"', colon + 1); - if (first_quote == std::string::npos) - throw std::runtime_error("invalid json: " + json); + if (first_quote == std::string::npos) throw std::runtime_error("invalid json: " + json); auto second_quote = json.find('"', first_quote + 1); - if (second_quote == std::string::npos) - throw std::runtime_error("invalid json: " + json); + if (second_quote == std::string::npos) throw std::runtime_error("invalid json: " + json); return json.substr(first_quote + 1, second_quote - first_quote - 1); } // RPC handler registration -void registerReceiverMethods(Room *greeters_room, Room *math_genius_room) { - LocalParticipant *greeter_lp = greeters_room->localParticipant(); - LocalParticipant *math_genius_lp = math_genius_room->localParticipant(); +void registerReceiverMethods(Room* greeters_room, Room* math_genius_room) { + LocalParticipant* greeter_lp = greeters_room->localParticipant(); + LocalParticipant* math_genius_lp = math_genius_room->localParticipant(); // arrival - greeter_lp->registerRpcMethod( - "arrival", - [](const RpcInvocationData &data) -> std::optional { - std::cout << "[Greeter] Oh " << data.caller_identity - << " arrived and said \"" << data.payload << "\"\n"; - std::this_thread::sleep_for(2s); - return std::optional{"Welcome and have a wonderful day!"}; - }); + greeter_lp->registerRpcMethod("arrival", [](const RpcInvocationData& data) -> std::optional { + std::cout << "[Greeter] Oh " << data.caller_identity << " arrived and said \"" << data.payload << "\"\n"; + std::this_thread::sleep_for(2s); + return std::optional{"Welcome and have a wonderful day!"}; + }); // square-root - math_genius_lp->registerRpcMethod( - "square-root", - [](const RpcInvocationData &data) -> std::optional { - double number = parseNumberFromJson(data.payload); - std::cout << "[Math Genius] I guess " << data.caller_identity - << " wants the square root of " << number - << ". I've only got " << data.response_timeout_sec - << " seconds to respond but I think I can pull it off.\n"; - std::cout << "[Math Genius] *doing math*…\n"; - std::this_thread::sleep_for(2s); - double result = std::sqrt(number); - std::cout << "[Math Genius] Aha! It's " << result << "\n"; - return makeNumberJson("result", result); - }); + math_genius_lp->registerRpcMethod("square-root", [](const RpcInvocationData& data) -> std::optional { + double number = parseNumberFromJson(data.payload); + std::cout << "[Math Genius] I guess " << data.caller_identity << " wants the square root of " << number + << ". I've only got " << data.response_timeout_sec + << " seconds to respond but I think I can pull it off.\n"; + std::cout << "[Math Genius] *doing math*…\n"; + std::this_thread::sleep_for(2s); + double result = std::sqrt(number); + std::cout << "[Math Genius] Aha! It's " << result << "\n"; + return makeNumberJson("result", result); + }); // divide - math_genius_lp->registerRpcMethod( - "divide", - [](const RpcInvocationData &data) -> std::optional { - // expect {"dividend":X,"divisor":Y} – we'll parse very lazily - auto div_pos = data.payload.find("dividend"); - auto dvr_pos = data.payload.find("divisor"); - if (div_pos == std::string::npos || dvr_pos == std::string::npos) { - throw std::runtime_error("invalid divide payload"); - } - - double dividend = parseNumberFromJson( - data.payload.substr(div_pos, dvr_pos - div_pos - 1)); // rough slice - double divisor = parseNumberFromJson(data.payload.substr(dvr_pos)); - - std::cout << "[Math Genius] " << data.caller_identity - << " wants to divide " << dividend << " by " << divisor - << ".\n"; - - if (divisor == 0.0) { - // will be translated to APPLICATION_ERROR by your RpcError logic - throw std::runtime_error("division by zero"); - } - - double result = dividend / divisor; - return makeNumberJson("result", result); - }); + math_genius_lp->registerRpcMethod("divide", [](const RpcInvocationData& data) -> std::optional { + // expect {"dividend":X,"divisor":Y} – we'll parse very lazily + auto div_pos = data.payload.find("dividend"); + auto dvr_pos = data.payload.find("divisor"); + if (div_pos == std::string::npos || dvr_pos == std::string::npos) { + throw std::runtime_error("invalid divide payload"); + } + + double dividend = parseNumberFromJson(data.payload.substr(div_pos, dvr_pos - div_pos - 1)); // rough slice + double divisor = parseNumberFromJson(data.payload.substr(dvr_pos)); + + std::cout << "[Math Genius] " << data.caller_identity << " wants to divide " << dividend << " by " << divisor + << ".\n"; + + if (divisor == 0.0) { + // will be translated to APPLICATION_ERROR by your RpcError logic + throw std::runtime_error("division by zero"); + } + + double result = dividend / divisor; + return makeNumberJson("result", result); + }); // long-calculation math_genius_lp->registerRpcMethod( - "long-calculation", - [](const RpcInvocationData &data) -> std::optional { - std::cout << "[Math Genius] Starting a very long calculation for " - << data.caller_identity << "\n"; + "long-calculation", [](const RpcInvocationData& data) -> std::optional { + std::cout << "[Math Genius] Starting a very long calculation for " << data.caller_identity << "\n"; std::cout << "[Math Genius] This will take 30 seconds even though " "you're only giving me " << data.response_timeout_sec << " seconds\n"; @@ -307,17 +270,15 @@ void registerReceiverMethods(Room *greeters_room, Room *math_genius_room) { // so the caller sees UNSUPPORTED_METHOD } -void performGreeting(Room *room) { +void performGreeting(Room* room) { std::cout << "[Caller] Letting the greeter know that I've arrived\n"; double t0 = nowMs(); try { - std::string response = room->localParticipant()->performRpc( - "greeter", "arrival", "Hello", std::nullopt); + std::string response = room->localParticipant()->performRpc("greeter", "arrival", "Hello", std::nullopt); double t1 = nowMs(); std::cout << "[Caller] RTT: " << (t1 - t0) << " ms\n"; - std::cout << "[Caller] That's nice, the greeter said: \"" << response - << "\"\n"; - } catch (const std::exception &error) { + std::cout << "[Caller] That's nice, the greeter said: \"" << response << "\"\n"; + } catch (const std::exception& error) { double t1 = nowMs(); std::cout << "[Caller] (FAILED) RTT: " << (t1 - t0) << " ms\n"; std::cout << "[Caller] RPC call failed: " << error.what() << "\n"; @@ -325,18 +286,17 @@ void performGreeting(Room *room) { } } -void performSquareRoot(Room *room) { +void performSquareRoot(Room* room) { std::cout << "[Caller] What's the square root of 16?\n"; double t0 = nowMs(); try { std::string payload = makeNumberJson("number", 16.0); - std::string response = room->localParticipant()->performRpc( - "math-genius", "square-root", payload, std::nullopt); + std::string response = room->localParticipant()->performRpc("math-genius", "square-root", payload, std::nullopt); double t1 = nowMs(); std::cout << "[Caller] RTT: " << (t1 - t0) << " ms\n"; double result = parseNumberFromJson(response); std::cout << "[Caller] Nice, the answer was " << result << "\n"; - } catch (const std::exception &error) { + } catch (const std::exception& error) { double t1 = nowMs(); std::cout << "[Caller] (FAILED) RTT: " << (t1 - t0) << " ms\n"; std::cout << "[Caller] RPC call failed: " << error.what() << "\n"; @@ -344,20 +304,19 @@ void performSquareRoot(Room *room) { } } -void performQuantumHyperGeometricSeries(Room *room) { +void performQuantumHyperGeometricSeries(Room* room) { std::cout << "\n=== Unsupported Method Example ===\n"; - std::cout - << "[Caller] Asking math-genius for 'quantum-hypergeometric-series'. " - "This should FAIL because the handler is NOT registered.\n"; + std::cout << "[Caller] Asking math-genius for 'quantum-hypergeometric-series'. " + "This should FAIL because the handler is NOT registered.\n"; double t0 = nowMs(); try { std::string payload = makeNumberJson("number", 42.0); - std::string response = room->localParticipant()->performRpc( - "math-genius", "quantum-hypergeometric-series", payload, std::nullopt); + std::string response = + room->localParticipant()->performRpc("math-genius", "quantum-hypergeometric-series", payload, std::nullopt); double t1 = nowMs(); std::cout << "[Caller] (Unexpected success) RTT=" << (t1 - t0) << " ms\n"; std::cout << "[Caller] Result: " << response << "\n"; - } catch (const RpcError &error) { + } catch (const RpcError& error) { double t1 = nowMs(); std::cout << "[Caller] RpcError RTT=" << (t1 - t0) << " ms\n"; auto code = static_cast(error.code()); @@ -366,74 +325,65 @@ void performQuantumHyperGeometricSeries(Room *room) { "method.\n"; std::cout << "[Caller] Server returned UNSUPPORTED_METHOD.\n"; } else { - std::cout << "[Caller] ✗ Unexpected error type: " << error.message() - << "\n"; + std::cout << "[Caller] ✗ Unexpected error type: " << error.message() << "\n"; } } } -void performDivide(Room *room) { +void performDivide(Room* room) { std::cout << "\n=== Divide Example ===\n"; std::cout << "[Caller] Asking math-genius to divide 10 by 0. " "This is EXPECTED to FAIL with an APPLICATION_ERROR.\n"; double t0 = nowMs(); try { std::string payload = "{\"dividend\":10,\"divisor\":0}"; - std::string response = room->localParticipant()->performRpc( - "math-genius", "divide", payload, std::nullopt); + std::string response = room->localParticipant()->performRpc("math-genius", "divide", payload, std::nullopt); double t1 = nowMs(); std::cout << "[Caller] (Unexpected success) RTT=" << (t1 - t0) << " ms\n"; std::cout << "[Caller] Result = " << response << "\n"; - } catch (const RpcError &error) { + } catch (const RpcError& error) { double t1 = nowMs(); std::cout << "[Caller] RpcError RTT=" << (t1 - t0) << " ms\n"; auto code = static_cast(error.code()); if (code == RpcError::ErrorCode::APPLICATION_ERROR) { std::cout << "[Caller] ✓ Expected: divide-by-zero triggers " "APPLICATION_ERROR.\n"; - std::cout << "[Caller] Math-genius threw an exception: " - << error.message() << "\n"; + std::cout << "[Caller] Math-genius threw an exception: " << error.message() << "\n"; } else { - std::cout << "[Caller] ✗ Unexpected RpcError type: " << error.message() - << "\n"; + std::cout << "[Caller] ✗ Unexpected RpcError type: " << error.message() << "\n"; } } } -void performLongCalculation(Room *room) { +void performLongCalculation(Room* room) { std::cout << "\n=== Long Calculation Example ===\n"; - std::cout - << "[Caller] Asking math-genius for a calculation that takes 30s.\n"; - std::cout - << "[Caller] Giving only 10s to respond. EXPECTED RESULT: TIMEOUT.\n"; + std::cout << "[Caller] Asking math-genius for a calculation that takes 30s.\n"; + std::cout << "[Caller] Giving only 10s to respond. EXPECTED RESULT: TIMEOUT.\n"; double t0 = nowMs(); try { - std::string response = room->localParticipant()->performRpc( - "math-genius", "long-calculation", "{}", 10.0); + std::string response = room->localParticipant()->performRpc("math-genius", "long-calculation", "{}", 10.0); double t1 = nowMs(); std::cout << "[Caller] (Unexpected success) RTT=" << (t1 - t0) << " ms\n"; std::cout << "[Caller] Result: " << response << "\n"; - } catch (const RpcError &error) { + } catch (const RpcError& error) { double t1 = nowMs(); std::cout << "[Caller] RpcError RTT=" << (t1 - t0) << " ms\n"; auto code = static_cast(error.code()); if (code == RpcError::ErrorCode::RESPONSE_TIMEOUT) { - std::cout - << "[Caller] ✓ Expected: handler sleeps 30s but timeout is 10s.\n"; + std::cout << "[Caller] ✓ Expected: handler sleeps 30s but timeout is 10s.\n"; std::cout << "[Caller] Server correctly returned RESPONSE_TIMEOUT.\n"; } else if (code == RpcError::ErrorCode::RECIPIENT_DISCONNECTED) { std::cout << "[Caller] ✓ Expected if math-genius disconnects during the " "test.\n"; } else { - std::cout << "[Caller] ✗ Unexpected RPC error: " << error.message() - << "\n"; + std::cout << "[Caller] ✗ Unexpected RPC error: " << error.message() << "\n"; } } } } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { std::string url, token, role; if (!parseArgs(argc, argv, url, token, role)) { printUsage(argv[0]); @@ -475,10 +425,8 @@ int main(int argc, char *argv[]) { try { if (role == "caller") { // Check that both peers are present (or explain how to start them). - bool has_greeter = - ensurePeerPresent(room.get(), "greeter", "greeter", url, 8s); - bool has_math_genius = - ensurePeerPresent(room.get(), "math-genius", "math-genius", url, 8s); + bool has_greeter = ensurePeerPresent(room.get(), "greeter", "greeter", url, 8s); + bool has_math_genius = ensurePeerPresent(room.get(), "math-genius", "math-genius", url, 8s); if (!has_greeter || !has_math_genius) { std::cout << "\n[Caller] One or more RPC peers are missing. " << "Some examples may be skipped.\n"; @@ -525,8 +473,7 @@ int main(int argc, char *argv[]) { registerReceiverMethods(room.get(), room.get()); } - std::cout << "RPC handlers registered for role=" << role - << ". Waiting for RPC calls (Ctrl-C to exit)...\n"; + std::cout << "RPC handlers registered for role=" << role << ". Waiting for RPC calls (Ctrl-C to exit)...\n"; while (g_running.load()) { std::this_thread::sleep_for(50ms); @@ -535,7 +482,7 @@ int main(int argc, char *argv[]) { } else { std::cerr << "Unknown role: " << role << "\n"; } - } catch (const std::exception &e) { + } catch (const std::exception& e) { std::cerr << "Unexpected error in main: " << e.what() << "\n"; } diff --git a/user_timestamped_video/common/cli_utils.h b/user_timestamped_video/common/cli_utils.h index 821d882..f6102ad 100644 --- a/user_timestamped_video/common/cli_utils.h +++ b/user_timestamped_video/common/cli_utils.h @@ -46,12 +46,12 @@ inline void installSignalHandlers() { #endif } -inline std::string getenvOrEmpty(const char *name) { - const char *value = std::getenv(name); +inline std::string getenvOrEmpty(const char* name) { + const char* value = std::getenv(name); return value ? std::string(value) : std::string{}; } -inline void printUsage(const char *program) { +inline void printUsage(const char* program) { std::cerr << "Usage:\n" << " " << program << " " << "[--with-user-timestamp|--without-user-timestamp]\n" @@ -60,7 +60,7 @@ inline void printUsage(const char *program) { << " [--with-user-timestamp|--without-user-timestamp]\n"; } -inline ParseResult parseArgs(int argc, char *argv[], CliOptions &options) { +inline ParseResult parseArgs(int argc, char* argv[], CliOptions& options) { std::vector positional; options = CliOptions{}; @@ -98,8 +98,7 @@ inline ParseResult parseArgs(int argc, char *argv[], CliOptions &options) { return ParseResult::Error; } - return (options.url.empty() || options.token.empty()) ? ParseResult::Error - : ParseResult::Ok; + return (options.url.empty() || options.token.empty()) ? ParseResult::Error : ParseResult::Ok; } } // namespace user_timestamped_video diff --git a/user_timestamped_video/consumer/main.cpp b/user_timestamped_video/consumer/main.cpp index b021a7b..904b37c 100644 --- a/user_timestamped_video/consumer/main.cpp +++ b/user_timestamped_video/consumer/main.cpp @@ -43,10 +43,9 @@ using namespace livekit; namespace { -constexpr const char *kTrackName = "timestamped-camera"; +constexpr const char* kTrackName = "timestamped-camera"; -std::string -formatUserTimestamp(const std::optional &metadata) { +std::string formatUserTimestamp(const std::optional& metadata) { if (!metadata || !metadata->user_timestamp_us.has_value()) { return "n/a"; } @@ -56,30 +55,27 @@ formatUserTimestamp(const std::optional &metadata) { class UserTimestampedVideoConsumerDelegate : public RoomDelegate { public: - UserTimestampedVideoConsumerDelegate(Room &room, bool read_user_timestamp) + UserTimestampedVideoConsumerDelegate(Room& room, bool read_user_timestamp) : room_(room), read_user_timestamp_(read_user_timestamp) {} void registerExistingParticipants() { - for (const auto &participant : room_.remoteParticipants()) { + for (const auto& participant : room_.remoteParticipants()) { if (participant) { registerRemoteVideoCallback(participant->identity()); } } } - void onParticipantConnected(Room &, - const ParticipantConnectedEvent &event) override { + void onParticipantConnected(Room&, const ParticipantConnectedEvent& event) override { if (!event.participant) { return; } - std::cout << "[consumer] participant connected: " - << event.participant->identity() << "\n"; + std::cout << "[consumer] participant connected: " << event.participant->identity() << "\n"; registerRemoteVideoCallback(event.participant->identity()); } - void onParticipantDisconnected( - Room &, const ParticipantDisconnectedEvent &event) override { + void onParticipantDisconnected(Room&, const ParticipantDisconnectedEvent& event) override { if (!event.participant) { return; } @@ -96,7 +92,7 @@ class UserTimestampedVideoConsumerDelegate : public RoomDelegate { } private: - void registerRemoteVideoCallback(const std::string &identity) { + void registerRemoteVideoCallback(const std::string& identity) { { std::lock_guard lock(mutex_); if (!registered_identities_.insert(identity).second) { @@ -110,34 +106,28 @@ class UserTimestampedVideoConsumerDelegate : public RoomDelegate { if (read_user_timestamp_) { room_.setOnVideoFrameEventCallback( identity, std::string(kTrackName), - [identity](const VideoFrameEvent &event) { - std::cout << "[consumer] from=" << identity - << " size=" << event.frame.width() << "x" - << event.frame.height() - << " capture_ts_us=" << event.timestamp_us + [identity](const VideoFrameEvent& event) { + std::cout << "[consumer] from=" << identity << " size=" << event.frame.width() << "x" + << event.frame.height() << " capture_ts_us=" << event.timestamp_us << " user_ts_us=" << formatUserTimestamp(event.metadata) - << " rotation=" << static_cast(event.rotation) - << "\n"; + << " rotation=" << static_cast(event.rotation) << "\n"; }, stream_options); } else { room_.setOnVideoFrameCallback( identity, std::string(kTrackName), - [identity](const VideoFrame &frame, const std::int64_t timestamp_us) { - std::cout << "[consumer] from=" << identity - << " size=" << frame.width() << "x" << frame.height() - << " capture_ts_us=" << timestamp_us - << " user_ts_us=ignored\n"; + [identity](const VideoFrame& frame, const std::int64_t timestamp_us) { + std::cout << "[consumer] from=" << identity << " size=" << frame.width() << "x" << frame.height() + << " capture_ts_us=" << timestamp_us << " user_ts_us=ignored\n"; }, stream_options); } - std::cout << "[consumer] listening for video frames from " << identity - << " track=\"" << kTrackName << "\" with user timestamp " - << (read_user_timestamp_ ? "enabled" : "ignored") << "\n"; + std::cout << "[consumer] listening for video frames from " << identity << " track=\"" << kTrackName + << "\" with user timestamp " << (read_user_timestamp_ ? "enabled" : "ignored") << "\n"; } - Room &room_; + Room& room_; bool read_user_timestamp_; std::mutex mutex_; std::unordered_set registered_identities_; @@ -145,11 +135,10 @@ class UserTimestampedVideoConsumerDelegate : public RoomDelegate { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { user_timestamped_video::CliOptions cli_options; - const user_timestamped_video::ParseResult parse_result = - user_timestamped_video::parseArgs(argc, argv, cli_options); + const user_timestamped_video::ParseResult parse_result = user_timestamped_video::parseArgs(argc, argv, cli_options); if (parse_result != user_timestamped_video::ParseResult::Ok) { user_timestamped_video::printUsage(argv[0]); return parse_result == user_timestamped_video::ParseResult::Help ? 0 : 1; @@ -166,8 +155,7 @@ int main(int argc, char *argv[]) { options.auto_subscribe = true; options.dynacast = false; - UserTimestampedVideoConsumerDelegate delegate( - room, cli_options.use_user_timestamp); + UserTimestampedVideoConsumerDelegate delegate(room, cli_options.use_user_timestamp); room.setDelegate(&delegate); std::cout << "[consumer] connecting to " << cli_options.url << "\n"; @@ -175,11 +163,9 @@ int main(int argc, char *argv[]) { std::cerr << "[consumer] failed to connect\n"; exit_code = 1; } else { - std::cout << "[consumer] connected as " - << room.localParticipant()->identity() << " to room '" + std::cout << "[consumer] connected as " << room.localParticipant()->identity() << " to room '" << room.room_info().name << "' with user timestamp " - << (cli_options.use_user_timestamp ? "enabled" : "ignored") - << "\n"; + << (cli_options.use_user_timestamp ? "enabled" : "ignored") << "\n"; delegate.registerExistingParticipants(); @@ -187,10 +173,9 @@ int main(int argc, char *argv[]) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - for (const auto &participant : room.remoteParticipants()) { + for (const auto& participant : room.remoteParticipants()) { if (participant) { - room.clearOnVideoFrameCallback(participant->identity(), - std::string(kTrackName)); + room.clearOnVideoFrameCallback(participant->identity(), std::string(kTrackName)); } } } diff --git a/user_timestamped_video/producer/main.cpp b/user_timestamped_video/producer/main.cpp index 95d8a66..73cd608 100644 --- a/user_timestamped_video/producer/main.cpp +++ b/user_timestamped_video/producer/main.cpp @@ -48,18 +48,16 @@ constexpr int kFrameIntervalMs = 200; std::uint64_t nowEpochUs() { return static_cast( - std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) + std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()) .count()); } -void fillFrame(VideoFrame &frame, std::uint32_t frame_index) { +void fillFrame(VideoFrame& frame, std::uint32_t frame_index) { const std::uint8_t blue = static_cast((frame_index * 7) % 255); - const std::uint8_t green = - static_cast((frame_index * 13) % 255); + const std::uint8_t green = static_cast((frame_index * 13) % 255); const std::uint8_t red = static_cast((frame_index * 29) % 255); - std::uint8_t *data = frame.data(); + std::uint8_t* data = frame.data(); for (std::size_t i = 0; i < frame.dataSize(); i += 4) { data[i + 0] = blue; data[i + 1] = green; @@ -70,11 +68,10 @@ void fillFrame(VideoFrame &frame, std::uint32_t frame_index) { } // namespace -int main(int argc, char *argv[]) { +int main(int argc, char* argv[]) { user_timestamped_video::CliOptions cli_options; - const user_timestamped_video::ParseResult parse_result = - user_timestamped_video::parseArgs(argc, argv, cli_options); + const user_timestamped_video::ParseResult parse_result = user_timestamped_video::parseArgs(argc, argv, cli_options); if (parse_result != user_timestamped_video::ParseResult::Ok) { user_timestamped_video::printUsage(argv[0]); return parse_result == user_timestamped_video::ParseResult::Help ? 0 : 1; @@ -96,27 +93,22 @@ int main(int argc, char *argv[]) { std::cerr << "[producer] failed to connect\n"; exit_code = 1; } else { - std::cout << "[producer] connected as " - << room.localParticipant()->identity() << " to room '" + std::cout << "[producer] connected as " << room.localParticipant()->identity() << " to room '" << room.room_info().name << "'\n"; auto source = std::make_shared(kFrameWidth, kFrameHeight); - auto track = - LocalVideoTrack::createLocalVideoTrack("timestamped-camera", source); + auto track = LocalVideoTrack::createLocalVideoTrack("timestamped-camera", source); try { TrackPublishOptions publish_options; publish_options.source = TrackSource::SOURCE_CAMERA; - publish_options.packet_trailer_features.user_timestamp = - cli_options.use_user_timestamp; + publish_options.packet_trailer_features.user_timestamp = cli_options.use_user_timestamp; room.localParticipant()->publishTrack(track, publish_options); std::cout << "[producer] published camera track with user timestamp " - << (cli_options.use_user_timestamp ? "enabled" : "disabled") - << "\n"; + << (cli_options.use_user_timestamp ? "enabled" : "disabled") << "\n"; - VideoFrame frame = VideoFrame::create(kFrameWidth, kFrameHeight, - VideoBufferType::BGRA); + VideoFrame frame = VideoFrame::create(kFrameWidth, kFrameHeight, VideoBufferType::BGRA); const auto capture_start = std::chrono::steady_clock::now(); std::uint32_t frame_index = 0; auto next_frame_at = std::chrono::steady_clock::now(); @@ -128,8 +120,7 @@ int main(int argc, char *argv[]) { // a steady_clock to align with other data/video frames capture_options.timestamp_us = static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now() - capture_start) + std::chrono::duration_cast(std::chrono::steady_clock::now() - capture_start) .count()); capture_options.rotation = VideoRotation::VIDEO_ROTATION_0; if (cli_options.use_user_timestamp) { @@ -140,13 +131,10 @@ int main(int argc, char *argv[]) { source->captureFrame(frame, capture_options); if (frame_index % 5 == 0) { - std::cout << "[producer] frame=" << frame_index - << " capture_ts_us=" << capture_options.timestamp_us + std::cout << "[producer] frame=" << frame_index << " capture_ts_us=" << capture_options.timestamp_us << " user_ts_us=" - << (cli_options.use_user_timestamp - ? std::to_string(*capture_options.metadata - ->user_timestamp_us) - : std::string("disabled")) + << (cli_options.use_user_timestamp ? std::to_string(*capture_options.metadata->user_timestamp_us) + : std::string("disabled")) << "\n"; } @@ -154,7 +142,7 @@ int main(int argc, char *argv[]) { next_frame_at += std::chrono::milliseconds(kFrameIntervalMs); std::this_thread::sleep_until(next_frame_at); } - } catch (const std::exception &error) { + } catch (const std::exception& error) { std::cerr << "[producer] error: " << error.what() << "\n"; exit_code = 1; }