#include "livekit/webrtc.h"
#include <algorithm>
#include <atomic>
#include <iostream>
#include <memory>
#include "livekit/audio_track.h"
#include "livekit/media_stream_track.h"
#include "livekit/rtp_receiver.h"
#include "livekit/rtp_sender.h"
#include "livekit/video_track.h"
#include "rtc_base/logging.h"
#include "rtc_base/crypto_random.h"
#include "rtc_base/synchronization/mutex.h"
#ifdef WEBRTC_WIN
#include "rtc_base/win32.h"
#endif
namespace livekit_ffi {
static webrtc::Mutex g_mutex{};
static uint32_t g_release_counter(0);
RtcRuntime::RtcRuntime() {
RTC_LOG(LS_VERBOSE) << "RtcRuntime()";
{
webrtc::MutexLock lock(&g_mutex);
if (g_release_counter == 0) {
RTC_CHECK(webrtc::InitializeSSL()) << "Failed to InitializeSSL()";
#ifdef WEBRTC_WIN
WSADATA data;
WSAStartup(MAKEWORD(1, 0), &data);
#endif
}
g_release_counter++;
}
network_thread_ = webrtc::Thread::CreateWithSocketServer();
network_thread_->SetName("network_thread", &network_thread_);
network_thread_->Start();
worker_thread_ = webrtc::Thread::Create();
worker_thread_->SetName("worker_thread", &worker_thread_);
worker_thread_->Start();
signaling_thread_ = webrtc::Thread::Create();
signaling_thread_->SetName("signaling_thread", &signaling_thread_);
signaling_thread_->Start();
}
RtcRuntime::~RtcRuntime() {
RTC_LOG(LS_VERBOSE) << "~RtcRuntime()";
worker_thread_->Stop();
signaling_thread_->Stop();
network_thread_->Stop();
{
webrtc::MutexLock lock(&g_mutex);
g_release_counter--;
if (g_release_counter == 0) {
RTC_CHECK(webrtc::CleanupSSL()) << "Failed to CleanupSSL()";
#ifdef WEBRTC_WIN
WSACleanup();
#endif
}
}
}
webrtc::Thread* RtcRuntime::network_thread() const {
return network_thread_.get();
}
webrtc::Thread* RtcRuntime::worker_thread() const {
return worker_thread_.get();
}
webrtc::Thread* RtcRuntime::signaling_thread() const {
return signaling_thread_.get();
}
std::shared_ptr<MediaStreamTrack> RtcRuntime::get_or_create_media_stream_track(
webrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtc_track) {
webrtc::MutexLock lock(&mutex_);
for (std::weak_ptr<MediaStreamTrack> weak_existing_track :
media_stream_tracks_) {
if (std::shared_ptr<MediaStreamTrack> existing_track =
weak_existing_track.lock()) {
if (existing_track->rtc_track() == rtc_track) {
return existing_track;
}
}
}
if (rtc_track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) {
std::shared_ptr<VideoTrack> video_track =
std::shared_ptr<VideoTrack>(new VideoTrack(
shared_from_this(),
webrtc::scoped_refptr<webrtc::VideoTrackInterface>(
static_cast<webrtc::VideoTrackInterface*>(rtc_track.get()))));
media_stream_tracks_.push_back(
std::static_pointer_cast<MediaStreamTrack>(video_track));
return video_track;
} else {
std::shared_ptr<AudioTrack> audio_track =
std::shared_ptr<AudioTrack>(new AudioTrack(
shared_from_this(),
webrtc::scoped_refptr<webrtc::AudioTrackInterface>(
static_cast<webrtc::AudioTrackInterface*>(rtc_track.get()))));
media_stream_tracks_.push_back(
std::static_pointer_cast<MediaStreamTrack>(audio_track));
return audio_track;
}
}
std::shared_ptr<AudioTrack> RtcRuntime::get_or_create_audio_track(
webrtc::scoped_refptr<webrtc::AudioTrackInterface> track) {
return std::static_pointer_cast<AudioTrack>(
get_or_create_media_stream_track(track));
}
std::shared_ptr<VideoTrack> RtcRuntime::get_or_create_video_track(
webrtc::scoped_refptr<webrtc::VideoTrackInterface> track) {
return std::static_pointer_cast<VideoTrack>(
get_or_create_media_stream_track(track));
}
LogSink::LogSink(
rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc)
: fnc_(fnc) {
webrtc::LogMessage::AddLogToStream(this, webrtc::LoggingSeverity::LS_VERBOSE);
}
LogSink::~LogSink() {
webrtc::LogMessage::RemoveLogToStream(this);
}
void LogSink::OnLogMessage(const std::string& message,
webrtc::LoggingSeverity severity) {
fnc_(rust::String::lossy(message), static_cast<LoggingSeverity>(severity));
}
std::unique_ptr<LogSink> new_log_sink(
rust::Fn<void(rust::String, LoggingSeverity)> fnc) {
return std::make_unique<LogSink>(fnc);
}
rust::String create_random_uuid() {
return webrtc::CreateRandomUuid();
}
}