Add native self-hosted instance connection to fluxer_desktop
Trimmed monorepo checkout (fluxer_desktop + packages/voice_engine_v2 + tools/ci) with a "Connect to a Different Server" menu item and popout that lets the desktop app switch to any self-hosted Fluxer instance, plus fixes for well-known discovery on single-domain self-hosted deployments and a false-positive ERR_ABORTED on same-origin client redirects during the switch. Defaults to chat.fluxr.chat and uses an isolated userData directory from the official build.
This commit is contained in:
+305
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright 2026 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "api/environment/environment.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/recorded_audio_tap.h"
|
||||
#include "livekit/synthetic_audio_device.h"
|
||||
#include "modules/audio_device/include/audio_device.h"
|
||||
#include "modules/audio_device/include/audio_device_defines.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
|
||||
namespace webrtc {
|
||||
class Thread;
|
||||
} // namespace webrtc
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
/// ADM Proxy that manages synthetic and platform audio modes.
|
||||
///
|
||||
/// This proxy implements the AudioDeviceModule interface and switches between:
|
||||
/// 1. **Synthetic mode**: Uses `SyntheticAudioDevice`, which pumps the WebRTC
|
||||
/// audio pipeline without platform audio. Remote audio is delivered via FFI
|
||||
/// callbacks to external audio systems (e.g., Unity AudioSource).
|
||||
/// 2. **Platform mode**: Real audio I/O through the Platform ADM with microphone
|
||||
/// capture and speaker playout. Used when PlatformAudio is active for VoIP
|
||||
/// with AEC.
|
||||
///
|
||||
/// ## Mode Selection
|
||||
///
|
||||
/// - **Playout**: Uses Platform ADM when `ref_count > 0 && playout_enabled`,
|
||||
/// otherwise uses synthetic mode (internal audio pumping task).
|
||||
/// - **Recording**: Uses Platform ADM when `ref_count > 0 && recording_enabled`,
|
||||
/// otherwise recording is unavailable (synthetic mode has no microphone).
|
||||
///
|
||||
/// ## Lifecycle Management
|
||||
///
|
||||
/// Platform ADM creation is attempted eagerly at construction (for iOS
|
||||
/// compatibility). If that attempt fails (e.g. the OS audio stack is still
|
||||
/// starting up), creation is retried on demand via EnsurePlatformAdm() and
|
||||
/// AcquirePlatformAdm() instead of failing for the process lifetime.
|
||||
/// Reference counting controls which mode is active:
|
||||
/// - `AcquirePlatformAdm()`: Increments ref count
|
||||
/// - `ReleasePlatformAdm()`: Decrements ref count
|
||||
/// - When ref_count is 0, playout uses synthetic mode
|
||||
///
|
||||
/// ## Audio Modes
|
||||
///
|
||||
/// | Mode | Recording | Playout | Use Case |
|
||||
/// |------|-----------|---------|----------|
|
||||
/// | Synthetic | NativeAudioSource | Internal task + FFI | Unity audio, agents |
|
||||
/// | Platform | Platform ADM mic | Platform ADM speakers | VoIP with AEC |
|
||||
///
|
||||
class AdmProxy : public webrtc::AudioDeviceModule {
|
||||
public:
|
||||
explicit AdmProxy(const webrtc::Environment& env,
|
||||
webrtc::Thread* worker_thread);
|
||||
~AdmProxy() override;
|
||||
|
||||
// ===========================================================================
|
||||
// Platform ADM Lifecycle Management
|
||||
// ===========================================================================
|
||||
|
||||
/// Acquires a reference to the Platform ADM.
|
||||
///
|
||||
/// On first call, creates and initializes the Platform ADM. On subsequent
|
||||
/// calls, just increments the reference count.
|
||||
///
|
||||
/// @return true if Platform ADM is ready for use, false if initialization failed.
|
||||
bool AcquirePlatformAdm();
|
||||
|
||||
/// Releases a reference to the Platform ADM.
|
||||
///
|
||||
/// When the reference count reaches zero, the Platform ADM is terminated
|
||||
/// and the proxy returns to synthetic mode.
|
||||
void ReleasePlatformAdm();
|
||||
|
||||
/// Returns the current reference count for the Platform ADM.
|
||||
int platform_adm_ref_count() const;
|
||||
|
||||
/// Returns true if Platform ADM is currently active (ref_count > 0).
|
||||
bool is_platform_adm_active() const;
|
||||
|
||||
/// Ensures the Platform ADM exists, creating and initializing it if needed.
|
||||
///
|
||||
/// Platform ADM creation can fail transiently when the OS audio stack is
|
||||
/// not ready yet (e.g. an app launched at login racing coreaudiod or the
|
||||
/// Windows audio services). A failed attempt leaves platform_adm_ null so
|
||||
/// the next call retries instead of staying broken for the process
|
||||
/// lifetime.
|
||||
///
|
||||
/// @return true if the Platform ADM is available after the call.
|
||||
bool EnsurePlatformAdm();
|
||||
|
||||
/// Returns true if the Platform ADM has been created and initialized.
|
||||
/// Distinguishes "audio stack unavailable" from "zero audio devices".
|
||||
bool platform_adm_available() const;
|
||||
|
||||
// ===========================================================================
|
||||
// Recording/Playout Control
|
||||
// ===========================================================================
|
||||
|
||||
/// Control whether recording (microphone) is enabled.
|
||||
///
|
||||
/// When disabled (default), InitRecording/StartRecording return success but
|
||||
/// do nothing. This allows NativeAudioSource to work without interference.
|
||||
///
|
||||
/// @note Only effective when Platform ADM is active.
|
||||
void set_recording_enabled(bool enabled);
|
||||
bool recording_enabled() const;
|
||||
|
||||
/// Control whether playout goes through Platform ADM speakers.
|
||||
///
|
||||
/// When disabled (default), playout uses synthetic mode - remote audio is
|
||||
/// delivered via FFI callbacks to the application (e.g., Unity AudioSource).
|
||||
///
|
||||
/// When enabled, remote audio plays through the platform speakers with AEC.
|
||||
///
|
||||
/// @note Only effective when Platform ADM is active.
|
||||
void set_playout_enabled(bool enabled);
|
||||
bool playout_enabled() const;
|
||||
|
||||
// ===========================================================================
|
||||
// AudioDeviceModule Interface
|
||||
// ===========================================================================
|
||||
|
||||
int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override;
|
||||
int32_t RegisterAudioCallback(webrtc::AudioTransport* transport) override;
|
||||
|
||||
int32_t Init() override;
|
||||
int32_t Terminate() override;
|
||||
bool Initialized() const override;
|
||||
|
||||
int16_t PlayoutDevices() override;
|
||||
int16_t RecordingDevices() override;
|
||||
int32_t PlayoutDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
int32_t RecordingDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
|
||||
int32_t SetPlayoutDevice(uint16_t index) override;
|
||||
int32_t SetPlayoutDevice(WindowsDeviceType device) override;
|
||||
int32_t SetRecordingDevice(uint16_t index) override;
|
||||
int32_t SetRecordingDevice(WindowsDeviceType device) override;
|
||||
|
||||
int32_t PlayoutIsAvailable(bool* available) override;
|
||||
int32_t InitPlayout() override;
|
||||
bool PlayoutIsInitialized() const override;
|
||||
int32_t RecordingIsAvailable(bool* available) override;
|
||||
int32_t InitRecording() override;
|
||||
bool RecordingIsInitialized() const override;
|
||||
|
||||
int32_t StartPlayout() override;
|
||||
int32_t StopPlayout() override;
|
||||
bool Playing() const override;
|
||||
int32_t StartRecording() override;
|
||||
int32_t StopRecording() override;
|
||||
bool Recording() const override;
|
||||
|
||||
int32_t InitSpeaker() override;
|
||||
bool SpeakerIsInitialized() const override;
|
||||
int32_t InitMicrophone() override;
|
||||
bool MicrophoneIsInitialized() const override;
|
||||
|
||||
int32_t SpeakerVolumeIsAvailable(bool* available) override;
|
||||
int32_t SetSpeakerVolume(uint32_t volume) override;
|
||||
int32_t SpeakerVolume(uint32_t* volume) const override;
|
||||
int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override;
|
||||
int32_t MinSpeakerVolume(uint32_t* minVolume) const override;
|
||||
|
||||
int32_t MicrophoneVolumeIsAvailable(bool* available) override;
|
||||
int32_t SetMicrophoneVolume(uint32_t volume) override;
|
||||
int32_t MicrophoneVolume(uint32_t* volume) const override;
|
||||
int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override;
|
||||
int32_t MinMicrophoneVolume(uint32_t* minVolume) const override;
|
||||
|
||||
int32_t SpeakerMuteIsAvailable(bool* available) override;
|
||||
int32_t SetSpeakerMute(bool enable) override;
|
||||
int32_t SpeakerMute(bool* enabled) const override;
|
||||
|
||||
int32_t MicrophoneMuteIsAvailable(bool* available) override;
|
||||
int32_t SetMicrophoneMute(bool enable) override;
|
||||
int32_t MicrophoneMute(bool* enabled) const override;
|
||||
|
||||
int32_t StereoPlayoutIsAvailable(bool* available) const override;
|
||||
int32_t SetStereoPlayout(bool enable) override;
|
||||
int32_t StereoPlayout(bool* enabled) const override;
|
||||
int32_t StereoRecordingIsAvailable(bool* available) const override;
|
||||
int32_t SetStereoRecording(bool enable) override;
|
||||
int32_t StereoRecording(bool* enabled) const override;
|
||||
|
||||
int32_t PlayoutDelay(uint16_t* delayMS) const override;
|
||||
|
||||
bool BuiltInAECIsAvailable() const override;
|
||||
bool BuiltInAGCIsAvailable() const override;
|
||||
bool BuiltInNSIsAvailable() const override;
|
||||
|
||||
int32_t EnableBuiltInAEC(bool enable) override;
|
||||
int32_t EnableBuiltInAGC(bool enable) override;
|
||||
int32_t EnableBuiltInNS(bool enable) override;
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(webrtc::AudioParameters* params) const override;
|
||||
int GetRecordAudioParameters(webrtc::AudioParameters* params) const override;
|
||||
#endif
|
||||
|
||||
int32_t SetObserver(webrtc::AudioDeviceObserver* observer) override;
|
||||
|
||||
private:
|
||||
// Returns true if platform mode is active for playout
|
||||
// (ref_count > 0 && playout_enabled)
|
||||
bool is_platform_playout_active() const;
|
||||
|
||||
// Returns the ADM to use for recording operations
|
||||
// - Platform ADM when recording is enabled (ref_count > 0 && recording_enabled)
|
||||
// - nullptr otherwise (recording not available in synthetic mode)
|
||||
webrtc::AudioDeviceModule* recording_adm() const;
|
||||
|
||||
// Switches playout mode based on current state.
|
||||
// Called when ref_count or playout_enabled changes.
|
||||
// If playout is active, stops the old mode and starts the new one.
|
||||
// Must be called with mutex_ held.
|
||||
void SwitchPlayoutModeIfNeeded();
|
||||
|
||||
// Switches recording to the correct ADM based on current mode.
|
||||
// Called when ref_count or recording_enabled changes.
|
||||
// If recording is active, stops the old ADM and starts the new one.
|
||||
// Must be called with mutex_ held.
|
||||
void SwitchRecordingAdmIfNeeded();
|
||||
|
||||
// Lazily creates and initializes the Platform ADM. On failure the ADM
|
||||
// stays null so a later call can retry once the OS audio stack is ready.
|
||||
// Must be called with mutex_ held.
|
||||
// Returns true if ADM is available after the call.
|
||||
bool EnsurePlatformAdmCreated();
|
||||
|
||||
// Re-applies state that predates a late Platform ADM creation: the
|
||||
// registered audio transport and any previously selected devices.
|
||||
// Must be called with mutex_ held and platform_adm_ non-null.
|
||||
void RestorePlatformAdmStateLocked();
|
||||
|
||||
const webrtc::Environment env_;
|
||||
webrtc::Thread* worker_thread_;
|
||||
|
||||
// Mutex for thread-safe access to mutable state
|
||||
mutable webrtc::Mutex mutex_;
|
||||
|
||||
// Synthetic ADM for synthetic mode - pumps the WebRTC audio pipeline without
|
||||
// platform audio via SyntheticAudioDevice's internal task.
|
||||
webrtc::scoped_refptr<SyntheticAudioDevice> synthetic_adm_;
|
||||
|
||||
// Platform ADM for real audio I/O (microphone capture, speaker playout with AEC)
|
||||
webrtc::scoped_refptr<webrtc::AudioDeviceModule> platform_adm_;
|
||||
|
||||
// Reference count for Platform ADM users (PlatformAudio instances)
|
||||
int platform_adm_ref_count_ = 0;
|
||||
|
||||
// Audio transport callback (registered by WebRTC)
|
||||
webrtc::AudioTransport* audio_transport_ = nullptr;
|
||||
|
||||
// Interposed between the platform ADM and audio_transport_ so recorded
|
||||
// microphone frames can be teed to the global recorded-audio sink. Forwards
|
||||
// every call to audio_transport_, leaving the send and playout paths intact.
|
||||
RecordingTransportProxy recording_transport_proxy_;
|
||||
|
||||
// State tracking
|
||||
bool playout_initialized_ = false;
|
||||
bool recording_initialized_ = false;
|
||||
bool playing_ = false;
|
||||
bool recording_ = false;
|
||||
|
||||
// Control flags
|
||||
// When false (default), recording operations are no-ops (NativeAudioSource mode)
|
||||
bool recording_enabled_ = false;
|
||||
// When false (default), playout uses synthetic mode (internal task pumps audio)
|
||||
bool playout_enabled_ = false;
|
||||
|
||||
// Selected device information (for re-initialization after ADM restart)
|
||||
// We store both index and GUID. GUID is preferred for restoration as it's
|
||||
// stable across device hot-plug events.
|
||||
uint16_t selected_playout_device_ = 0;
|
||||
uint16_t selected_recording_device_ = 0;
|
||||
std::string selected_playout_guid_;
|
||||
std::string selected_recording_guid_;
|
||||
};
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
typedef JavaVM JavaVM;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/android.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
/// Initialize Android WebRTC with the JVM.
|
||||
/// This is called automatically by init_android_context(), so you only need to
|
||||
/// call this directly in JNI_OnLoad or if you don't have an Android Context.
|
||||
/// This function is idempotent - safe to call multiple times.
|
||||
///
|
||||
/// @param jvm The JavaVM pointer
|
||||
void init_android(JavaVM* jvm);
|
||||
|
||||
/// Initialize Android WebRTC with the application context.
|
||||
/// This is the main initialization function - it calls init_android() internally
|
||||
/// and then initializes ContextUtils for PlatformAudio support.
|
||||
/// This function is idempotent - safe to call multiple times.
|
||||
///
|
||||
/// @param jvm The JavaVM pointer
|
||||
/// @param context The Android application context (jobject cast to uintptr_t)
|
||||
/// @return true if context initialization was successful, false otherwise.
|
||||
/// Note: JVM init (init_android) always happens regardless of return value.
|
||||
bool init_android_context(JavaVM* jvm, uintptr_t context);
|
||||
|
||||
std::unique_ptr<webrtc::VideoEncoderFactory> CreateAndroidVideoEncoderFactory();
|
||||
std::unique_ptr<webrtc::VideoDecoderFactory> CreateAndroidVideoDecoderFactory();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
#include "modules/audio_processing/aec3/echo_canceller3.h"
|
||||
#include "modules/audio_processing/audio_buffer.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
struct AudioProcessingConfig {
|
||||
bool echo_canceller_enabled;
|
||||
bool gain_controller_enabled;
|
||||
bool high_pass_filter_enabled;
|
||||
bool noise_suppression_enabled;
|
||||
|
||||
webrtc::AudioProcessing::Config ToWebrtcConfig() const {
|
||||
webrtc::AudioProcessing::Config config;
|
||||
config.echo_canceller.enabled = echo_canceller_enabled;
|
||||
config.gain_controller2.enabled = gain_controller_enabled;
|
||||
config.gain_controller2.adaptive_digital.enabled = gain_controller_enabled;
|
||||
config.high_pass_filter.enabled = high_pass_filter_enabled;
|
||||
config.noise_suppression.enabled = noise_suppression_enabled;
|
||||
return config;
|
||||
}
|
||||
};
|
||||
|
||||
class AudioProcessingModule {
|
||||
public:
|
||||
AudioProcessingModule(const AudioProcessingConfig& config);
|
||||
|
||||
int process_stream(const int16_t* src,
|
||||
size_t src_len,
|
||||
int16_t* dst,
|
||||
size_t dst_len,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
|
||||
int process_reverse_stream(const int16_t* src,
|
||||
size_t src_len,
|
||||
int16_t* dst,
|
||||
size_t dst_len,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
|
||||
int set_stream_delay_ms(int delay_ms);
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<webrtc::AudioProcessing> apm_;
|
||||
};
|
||||
|
||||
std::unique_ptr<AudioProcessingModule> create_apm(
|
||||
bool echo_canceller_enabled,
|
||||
bool gain_controller_enabled,
|
||||
bool high_pass_filter_enabled,
|
||||
bool noise_suppression_enabled);
|
||||
|
||||
} // namespace livekit_ffi
|
||||
Vendored
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2026 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/adm_proxy.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class AudioDeviceController {
|
||||
public:
|
||||
explicit AudioDeviceController(webrtc::scoped_refptr<AdmProxy> adm_proxy);
|
||||
|
||||
// Device enumeration
|
||||
int16_t playout_devices() const;
|
||||
int16_t recording_devices() const;
|
||||
rust::String playout_device_name(uint16_t index) const;
|
||||
rust::String recording_device_name(uint16_t index) const;
|
||||
rust::String playout_device_guid(uint16_t index) const;
|
||||
rust::String recording_device_guid(uint16_t index) const;
|
||||
|
||||
// Device selection
|
||||
bool set_playout_device(uint16_t index) const;
|
||||
bool set_recording_device(uint16_t index) const;
|
||||
bool set_playout_device_by_guid(rust::String guid) const;
|
||||
bool set_recording_device_by_guid(rust::String guid) const;
|
||||
|
||||
// Recording control
|
||||
bool stop_recording() const;
|
||||
bool init_recording() const;
|
||||
bool start_recording() const;
|
||||
bool recording_is_initialized() const;
|
||||
|
||||
// Playout control
|
||||
bool stop_playout() const;
|
||||
bool init_playout() const;
|
||||
bool start_playout() const;
|
||||
bool playout_is_initialized() const;
|
||||
|
||||
// Built-in audio processing
|
||||
bool builtin_aec_is_available() const;
|
||||
bool builtin_agc_is_available() const;
|
||||
bool builtin_ns_is_available() const;
|
||||
bool enable_builtin_aec(bool enable) const;
|
||||
bool enable_builtin_agc(bool enable) const;
|
||||
bool enable_builtin_ns(bool enable) const;
|
||||
|
||||
// ADM recording control
|
||||
void set_adm_recording_enabled(bool enabled) const;
|
||||
bool adm_recording_enabled() const;
|
||||
|
||||
// ADM playout control
|
||||
void set_adm_playout_enabled(bool enabled) const;
|
||||
bool adm_playout_enabled() const;
|
||||
|
||||
// Platform ADM lifecycle management
|
||||
bool acquire_platform_adm() const;
|
||||
void release_platform_adm() const;
|
||||
int platform_adm_ref_count() const;
|
||||
bool is_platform_adm_active() const;
|
||||
bool ensure_platform_adm() const;
|
||||
bool platform_adm_available() const;
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<AdmProxy> adm_proxy_;
|
||||
};
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/audio/audio_mixer.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "modules/audio_mixer/audio_mixer_impl.h"
|
||||
#include "modules/audio_processing/audio_buffer.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class AudioMixer;
|
||||
class NativeAudioFrame;
|
||||
} // namespace livekit_ffi
|
||||
|
||||
#include "webrtc-sys/src/audio_mixer.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class NativeAudioFrame {
|
||||
public:
|
||||
NativeAudioFrame(webrtc::AudioFrame* frame) : frame_(frame) {}
|
||||
void update_frame(uint32_t timestamp,
|
||||
const int16_t* data,
|
||||
size_t samples_per_channel,
|
||||
int sample_rate_hz,
|
||||
size_t num_channels);
|
||||
|
||||
private:
|
||||
webrtc::AudioFrame* frame_;
|
||||
};
|
||||
|
||||
class AudioMixerSource : public webrtc::AudioMixer::Source {
|
||||
public:
|
||||
AudioMixerSource(rust::Box<AudioMixerSourceWrapper> source);
|
||||
|
||||
AudioFrameInfo GetAudioFrameWithInfo(
|
||||
int sample_rate_hz,
|
||||
webrtc::AudioFrame* audio_frame) override;
|
||||
|
||||
int Ssrc() const override;
|
||||
|
||||
int PreferredSampleRate() const override;
|
||||
|
||||
~AudioMixerSource() {}
|
||||
|
||||
private:
|
||||
rust::Box<AudioMixerSourceWrapper> source_;
|
||||
};
|
||||
|
||||
class AudioMixer {
|
||||
public:
|
||||
AudioMixer();
|
||||
|
||||
void add_source(rust::Box<AudioMixerSourceWrapper> source);
|
||||
|
||||
void remove_source(int ssrc);
|
||||
|
||||
size_t mix(size_t num_channels);
|
||||
const int16_t* data() const;
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex sources_mutex_;
|
||||
webrtc::AudioFrame frame_;
|
||||
std::vector<std::shared_ptr<AudioMixerSource>> sources_;
|
||||
webrtc::scoped_refptr<webrtc::AudioMixer> audio_mixer_;
|
||||
};
|
||||
|
||||
std::unique_ptr<AudioMixer> create_audio_mixer();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/audio/audio_frame.h"
|
||||
#include "api/data_channel_interface.h"
|
||||
#include "common_audio/resampler/include/push_resampler.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class AudioResampler {
|
||||
public:
|
||||
size_t remix_and_resample(const int16_t* src,
|
||||
size_t samples_per_channel,
|
||||
size_t num_channels,
|
||||
int sample_rate_hz,
|
||||
size_t dest_num_channels,
|
||||
int dest_sample_rate_hz);
|
||||
|
||||
const int16_t* data() const;
|
||||
|
||||
private:
|
||||
webrtc::AudioFrame frame_;
|
||||
webrtc::PushResampler<int16_t> resampler_;
|
||||
};
|
||||
|
||||
std::unique_ptr<AudioResampler> create_audio_resampler();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "api/audio/audio_frame.h"
|
||||
#include "api/audio_options.h"
|
||||
#include "api/task_queue/task_queue_factory.h"
|
||||
#include "common_audio/resampler/include/push_resampler.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/media_stream_track.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "pc/local_audio_source.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "api/task_queue/task_queue_base.h"
|
||||
#include "rtc_base/task_utils/repeating_task.h"
|
||||
#include "rtc_base/thread_annotations.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class AudioTrack;
|
||||
class NativeAudioSink;
|
||||
class AudioTrackSource;
|
||||
class SourceContext;
|
||||
|
||||
using CompleteCallback = void (*)(const livekit_ffi::SourceContext*);
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/audio_track.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class AudioTrack : public MediaStreamTrack {
|
||||
private:
|
||||
friend RtcRuntime;
|
||||
AudioTrack(std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::AudioTrackInterface> track);
|
||||
|
||||
public:
|
||||
~AudioTrack();
|
||||
|
||||
void add_sink(const std::shared_ptr<NativeAudioSink>& sink) const;
|
||||
void remove_sink(const std::shared_ptr<NativeAudioSink>& sink) const;
|
||||
|
||||
private:
|
||||
webrtc::AudioTrackInterface* track() const {
|
||||
return static_cast<webrtc::AudioTrackInterface*>(track_.get());
|
||||
}
|
||||
|
||||
mutable webrtc::Mutex mutex_;
|
||||
|
||||
// Same for VideoTrack:
|
||||
// Keep a strong reference to the added sinks, so we don't need to
|
||||
// manage the lifetime safety on the Rust side
|
||||
mutable std::vector<std::shared_ptr<NativeAudioSink>> sinks_;
|
||||
};
|
||||
|
||||
class NativeAudioSink : public webrtc::AudioTrackSinkInterface {
|
||||
public:
|
||||
explicit NativeAudioSink(rust::Box<AudioSinkWrapper> observer,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
void OnData(const void* audio_data,
|
||||
int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames) override;
|
||||
|
||||
private:
|
||||
rust::Box<AudioSinkWrapper> observer_;
|
||||
|
||||
int sample_rate_;
|
||||
int num_channels_;
|
||||
|
||||
webrtc::AudioFrame frame_;
|
||||
webrtc::PushResampler<int16_t> resampler_;
|
||||
};
|
||||
|
||||
std::shared_ptr<NativeAudioSink> new_native_audio_sink(
|
||||
rust::Box<AudioSinkWrapper> observer,
|
||||
int sample_rate,
|
||||
int num_channels);
|
||||
|
||||
class AudioTrackSource {
|
||||
class InternalSource : public webrtc::LocalAudioSource {
|
||||
public:
|
||||
InternalSource(const webrtc::AudioOptions& options,
|
||||
int sample_rate,
|
||||
int num_channels,
|
||||
int buffer_size_ms,
|
||||
webrtc::TaskQueueFactory* task_queue_factory);
|
||||
|
||||
~InternalSource() override;
|
||||
|
||||
SourceState state() const override;
|
||||
bool remote() const override;
|
||||
|
||||
const webrtc::AudioOptions options() const override;
|
||||
|
||||
void AddSink(webrtc::AudioTrackSinkInterface* sink) override;
|
||||
void RemoveSink(webrtc::AudioTrackSinkInterface* sink) override;
|
||||
|
||||
void set_options(const webrtc::AudioOptions& options);
|
||||
|
||||
bool capture_frame(rust::Slice<const int16_t> audio_data,
|
||||
uint32_t sample_rate,
|
||||
uint32_t number_of_channels,
|
||||
size_t number_of_frames,
|
||||
const SourceContext* ctx,
|
||||
void (*on_complete)(const SourceContext*));
|
||||
|
||||
void clear_buffer();
|
||||
|
||||
// Indicate this is an external audio source (when external_audio_source.patch is applied).
|
||||
// This prevents AudioState from sending device audio to streams using this source.
|
||||
// Note: Omit 'override' to allow builds without the patch applied.
|
||||
// When the patch is applied, this will correctly override the base class virtual method.
|
||||
bool is_external_source() const { return true; }
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex mutex_;
|
||||
std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> audio_queue_;
|
||||
webrtc::RepeatingTaskHandle audio_task_;
|
||||
|
||||
std::vector<webrtc::AudioTrackSinkInterface*> sinks_ RTC_GUARDED_BY(mutex_);
|
||||
std::vector<int16_t> buffer_ RTC_GUARDED_BY(mutex_);
|
||||
|
||||
const SourceContext* capture_userdata_ RTC_GUARDED_BY(mutex_);
|
||||
void (*on_complete_)(const SourceContext*) RTC_GUARDED_BY(mutex_);
|
||||
|
||||
std::vector<int16_t> silence_buffer_;
|
||||
|
||||
int sample_rate_ = 0;
|
||||
int num_channels_ = 0;
|
||||
int queue_size_samples_ = 0;
|
||||
int notify_threshold_samples_ = 0;
|
||||
|
||||
webrtc::AudioOptions options_{};
|
||||
};
|
||||
|
||||
public:
|
||||
AudioTrackSource(AudioSourceOptions options,
|
||||
int sample_rate,
|
||||
int num_channels,
|
||||
int queue_size_ms,
|
||||
webrtc::TaskQueueFactory* task_queue_factory);
|
||||
|
||||
AudioSourceOptions audio_options() const;
|
||||
|
||||
void set_audio_options(const AudioSourceOptions& options) const;
|
||||
|
||||
bool capture_frame(rust::Slice<const int16_t> audio_data,
|
||||
uint32_t sample_rate,
|
||||
uint32_t number_of_channels,
|
||||
size_t number_of_frames,
|
||||
const SourceContext* ctx,
|
||||
CompleteCallback on_complete) const;
|
||||
|
||||
void clear_buffer() const;
|
||||
|
||||
webrtc::scoped_refptr<InternalSource> get() const;
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<InternalSource> source_;
|
||||
};
|
||||
|
||||
std::shared_ptr<AudioTrackSource> new_audio_track_source(
|
||||
AudioSourceOptions options,
|
||||
int sample_rate,
|
||||
int num_channels,
|
||||
int queue_size_ms);
|
||||
|
||||
static std::shared_ptr<MediaStreamTrack> audio_to_media(
|
||||
std::shared_ptr<AudioTrack> track) {
|
||||
return track;
|
||||
}
|
||||
|
||||
static std::shared_ptr<AudioTrack> media_to_audio(
|
||||
std::shared_ptr<MediaStreamTrack> track) {
|
||||
return std::static_pointer_cast<AudioTrack>(track);
|
||||
}
|
||||
|
||||
static std::shared_ptr<AudioTrack> _shared_audio_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
static std::shared_ptr<AudioTrackSource> _shared_audio_track_source() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/candidate.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class Candidate;
|
||||
}
|
||||
#include "webrtc-sys/src/candidate.rs.h"
|
||||
|
||||
// webrtc::Candidate
|
||||
namespace livekit_ffi {
|
||||
|
||||
class Candidate {
|
||||
public:
|
||||
explicit Candidate(const webrtc::Candidate& candidate);
|
||||
|
||||
private:
|
||||
webrtc::Candidate candidate_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<Candidate> _shared_candidate() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "api/data_channel_interface.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class DataChannel;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class NativeDataChannelObserver;
|
||||
|
||||
webrtc::DataChannelInit to_native_data_channel_init(DataChannelInit init);
|
||||
|
||||
class DataChannel {
|
||||
public:
|
||||
explicit DataChannel(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
||||
~DataChannel();
|
||||
|
||||
void register_observer(rust::Box<DataChannelObserverWrapper> observer) const;
|
||||
void unregister_observer() const;
|
||||
bool send(const DataBuffer& buffer) const;
|
||||
int id() const;
|
||||
rust::String label() const;
|
||||
DataState state() const;
|
||||
void close() const;
|
||||
uint64_t buffered_amount() const;
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex mutex_;
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
|
||||
mutable std::unique_ptr<NativeDataChannelObserver> observer_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<DataChannel> _shared_data_channel() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class NativeDataChannelObserver : public webrtc::DataChannelObserver {
|
||||
public:
|
||||
NativeDataChannelObserver(rust::Box<DataChannelObserverWrapper> observer,
|
||||
const DataChannel* dc);
|
||||
|
||||
void OnStateChange() override;
|
||||
void OnMessage(const webrtc::DataBuffer& buffer) override;
|
||||
void OnBufferedAmountChange(uint64_t sent_data_size) override;
|
||||
|
||||
private:
|
||||
rust::Box<DataChannelObserverWrapper> observer_;
|
||||
const DataChannel* dc_;
|
||||
};
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
#include "modules/desktop_capture/desktop_capturer.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class DesktopFrame;
|
||||
class DesktopCapturer;
|
||||
class DesktopCapturerOptions;
|
||||
class Source;
|
||||
} // namespace livekit_ffi
|
||||
|
||||
#include "webrtc-sys/src/desktop_capturer.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class DesktopCapturer : public webrtc::DesktopCapturer::Callback {
|
||||
public:
|
||||
explicit DesktopCapturer(std::unique_ptr<webrtc::DesktopCapturer> capturer)
|
||||
: capturer(std::move(capturer)), callback(std::nullopt) {}
|
||||
|
||||
void OnCaptureResult(webrtc::DesktopCapturer::Result result,
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame) final;
|
||||
|
||||
rust::Vec<Source> get_source_list() const;
|
||||
bool select_source(uint64_t id) const { return capturer->SelectSource(id); }
|
||||
void start(rust::Box<DesktopCapturerCallbackWrapper> callback);
|
||||
void capture_frame() const { capturer->CaptureFrame(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<webrtc::DesktopCapturer> capturer;
|
||||
std::optional<rust::Box<DesktopCapturerCallbackWrapper>> callback;
|
||||
};
|
||||
|
||||
class DesktopFrame {
|
||||
public:
|
||||
DesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame) : frame(std::move(frame)) {}
|
||||
int32_t width() const { return frame->size().width(); }
|
||||
|
||||
int32_t height() const { return frame->size().height(); }
|
||||
|
||||
int32_t left() const { return frame->rect().left(); }
|
||||
|
||||
int32_t top() const { return frame->rect().top(); }
|
||||
|
||||
int32_t stride() const { return frame->stride(); }
|
||||
|
||||
const uint8_t* data() const { return frame->data(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<webrtc::DesktopFrame> frame;
|
||||
};
|
||||
|
||||
std::unique_ptr<DesktopCapturer> new_desktop_capturer(DesktopCapturerOptions options);
|
||||
} // namespace livekit_ffi
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/crypto/frame_crypto_transformer.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/peer_connection.h"
|
||||
#include "livekit/peer_connection_factory.h"
|
||||
#include "livekit/rtp_receiver.h"
|
||||
#include "livekit/rtp_sender.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
struct KeyProviderOptions;
|
||||
struct EncryptedPacket;
|
||||
enum class Algorithm : ::std::int32_t;
|
||||
class RtcFrameCryptorObserverWrapper;
|
||||
class NativeFrameCryptorObserver;
|
||||
class PacketTrailerHandler;
|
||||
|
||||
/// Shared secret key for frame encryption.
|
||||
class KeyProvider {
|
||||
public:
|
||||
KeyProvider(KeyProviderOptions options);
|
||||
~KeyProvider() {}
|
||||
|
||||
bool set_shared_key(int32_t index, rust::Vec<::std::uint8_t> key) const {
|
||||
std::vector<uint8_t> key_vec;
|
||||
std::copy(key.begin(), key.end(), std::back_inserter(key_vec));
|
||||
return impl_->SetSharedKey(index, key_vec);
|
||||
}
|
||||
|
||||
rust::Vec<::std::uint8_t> ratchet_shared_key(int32_t key_index) const {
|
||||
rust::Vec<uint8_t> vec;
|
||||
auto data = impl_->RatchetSharedKey(key_index);
|
||||
if (data.empty()) {
|
||||
throw std::runtime_error("ratchet_shared_key failed");
|
||||
}
|
||||
|
||||
std::move(data.begin(), data.end(), std::back_inserter(vec));
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<::std::uint8_t> get_shared_key(int32_t key_index) const {
|
||||
rust::Vec<uint8_t> vec;
|
||||
auto data = impl_->ExportSharedKey(key_index);
|
||||
if (data.empty()) {
|
||||
throw std::runtime_error("get_shared_key failed");
|
||||
}
|
||||
|
||||
std::move(data.begin(), data.end(), std::back_inserter(vec));
|
||||
return vec;
|
||||
}
|
||||
|
||||
/// Set the key at the given index.
|
||||
bool set_key(const ::rust::String participant_id,
|
||||
int32_t index,
|
||||
rust::Vec<::std::uint8_t> key) const {
|
||||
std::vector<uint8_t> key_vec;
|
||||
std::copy(key.begin(), key.end(), std::back_inserter(key_vec));
|
||||
return impl_->SetKey(
|
||||
std::string(participant_id.data(), participant_id.size()), index,
|
||||
key_vec);
|
||||
}
|
||||
|
||||
rust::Vec<::std::uint8_t> ratchet_key(const ::rust::String participant_id,
|
||||
int32_t key_index) const {
|
||||
rust::Vec<uint8_t> vec;
|
||||
auto data = impl_->RatchetKey(
|
||||
std::string(participant_id.data(), participant_id.size()), key_index);
|
||||
if (data.empty()) {
|
||||
throw std::runtime_error("ratchet_key failed");
|
||||
}
|
||||
|
||||
std::move(data.begin(), data.end(), std::back_inserter(vec));
|
||||
return vec;
|
||||
}
|
||||
|
||||
rust::Vec<::std::uint8_t> get_key(const ::rust::String participant_id,
|
||||
int32_t key_index) const {
|
||||
rust::Vec<uint8_t> vec;
|
||||
auto data = impl_->ExportKey(
|
||||
std::string(participant_id.data(), participant_id.size()), key_index);
|
||||
if (data.empty()) {
|
||||
throw std::runtime_error("get_key failed");
|
||||
}
|
||||
|
||||
std::move(data.begin(), data.end(), std::back_inserter(vec));
|
||||
return vec;
|
||||
}
|
||||
|
||||
void set_sif_trailer(rust::Vec<::std::uint8_t> trailer) const {
|
||||
std::vector<uint8_t> trailer_vec;
|
||||
std::copy(trailer.begin(), trailer.end(), std::back_inserter(trailer_vec));
|
||||
impl_->SetSifTrailer(trailer_vec);
|
||||
}
|
||||
|
||||
webrtc::scoped_refptr<webrtc::KeyProvider> rtc_key_provider() { return impl_; }
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<webrtc::DefaultKeyProviderImpl> impl_;
|
||||
};
|
||||
|
||||
class FrameCryptor {
|
||||
public:
|
||||
FrameCryptor(std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
const std::string participant_id,
|
||||
webrtc::FrameCryptorTransformer::Algorithm algorithm,
|
||||
webrtc::scoped_refptr<webrtc::KeyProvider> key_provider,
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
|
||||
|
||||
FrameCryptor(std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
const std::string participant_id,
|
||||
webrtc::FrameCryptorTransformer::Algorithm algorithm,
|
||||
webrtc::scoped_refptr<webrtc::KeyProvider> key_provider,
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
|
||||
~FrameCryptor();
|
||||
|
||||
/// Enable/Disable frame crypto for the sender or receiver.
|
||||
void set_enabled(bool enabled) const;
|
||||
|
||||
/// Get the enabled state for the sender or receiver.
|
||||
bool enabled() const;
|
||||
|
||||
/// Set the key index for the sender or receiver.
|
||||
/// If the key index is not set, the key index will be set to 0.
|
||||
void set_key_index(int32_t index) const;
|
||||
|
||||
/// Get the key index for the sender or receiver.
|
||||
int32_t key_index() const;
|
||||
|
||||
rust::String participant_id() const { return participant_id_; }
|
||||
|
||||
void register_observer(
|
||||
rust::Box<RtcFrameCryptorObserverWrapper> observer) const;
|
||||
|
||||
void unregister_observer() const;
|
||||
|
||||
/// Attach a packet trailer transformer for chained processing.
|
||||
void set_packet_trailer_handler(
|
||||
std::shared_ptr<PacketTrailerHandler> handler) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
const rust::String participant_id_;
|
||||
mutable webrtc::Mutex mutex_;
|
||||
webrtc::scoped_refptr<webrtc::FrameCryptorTransformer> e2ee_transformer_;
|
||||
webrtc::scoped_refptr<webrtc::KeyProvider> key_provider_;
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender_;
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
|
||||
mutable webrtc::scoped_refptr<NativeFrameCryptorObserver> observer_;
|
||||
mutable webrtc::scoped_refptr<webrtc::FrameTransformerInterface>
|
||||
chained_transformer_;
|
||||
};
|
||||
|
||||
class NativeFrameCryptorObserver
|
||||
: public webrtc::FrameCryptorTransformerObserver {
|
||||
public:
|
||||
NativeFrameCryptorObserver(rust::Box<RtcFrameCryptorObserverWrapper> observer,
|
||||
const FrameCryptor* fc);
|
||||
~NativeFrameCryptorObserver();
|
||||
|
||||
void OnFrameCryptionStateChanged(const std::string participant_id,
|
||||
webrtc::FrameCryptionState error) override;
|
||||
|
||||
private:
|
||||
rust::Box<RtcFrameCryptorObserverWrapper> observer_;
|
||||
const FrameCryptor* fc_;
|
||||
};
|
||||
|
||||
class DataPacketCryptor {
|
||||
public:
|
||||
DataPacketCryptor(webrtc::FrameCryptorTransformer::Algorithm algorithm,
|
||||
webrtc::scoped_refptr<webrtc::KeyProvider> key_provider);
|
||||
|
||||
EncryptedPacket encrypt_data_packet(
|
||||
const ::rust::String participant_id,
|
||||
uint32_t key_index,
|
||||
rust::Vec<::std::uint8_t> data) const;
|
||||
|
||||
rust::Vec<::std::uint8_t> decrypt_data_packet(
|
||||
const ::rust::String participant_id,
|
||||
const EncryptedPacket& encrypted_packet) const;
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<webrtc::DataPacketCryptor> data_packet_cryptor_;
|
||||
};
|
||||
|
||||
std::shared_ptr<FrameCryptor> new_frame_cryptor_for_rtp_sender(
|
||||
std::shared_ptr<PeerConnectionFactory> peer_factory,
|
||||
const ::rust::String participant_id,
|
||||
Algorithm algorithm,
|
||||
std::shared_ptr<KeyProvider> key_provider,
|
||||
std::shared_ptr<RtpSender> sender);
|
||||
|
||||
std::shared_ptr<FrameCryptor> new_frame_cryptor_for_rtp_receiver(
|
||||
std::shared_ptr<PeerConnectionFactory> peer_factory,
|
||||
const ::rust::String participant_id,
|
||||
Algorithm algorithm,
|
||||
std::shared_ptr<KeyProvider> key_provider,
|
||||
std::shared_ptr<RtpReceiver> receiver);
|
||||
|
||||
std::shared_ptr<KeyProvider> new_key_provider(KeyProviderOptions options);
|
||||
|
||||
std::shared_ptr<DataPacketCryptor> new_data_packet_cryptor(
|
||||
Algorithm algorithm,
|
||||
std::shared_ptr<KeyProvider> key_provider);
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/task_queue/task_queue_factory.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
webrtc::TaskQueueFactory* GetGlobalTaskQueueFactory();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class MediaStream;
|
||||
class AudioTrack;
|
||||
class VideoTrack;
|
||||
class Candidate;
|
||||
class RtpSender;
|
||||
class RtpReceiver;
|
||||
class RtpTransceiver;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/helper.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
// Impl not needed
|
||||
static rust::Vec<MediaStreamPtr> _vec_media_stream_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<CandidatePtr> _vec_candidate_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<AudioTrackPtr> _vec_audio_track_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<VideoTrackPtr> _vec_video_track_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpSenderPtr> _vec_rtp_sender_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpReceiverPtr> _vec_rtp_receiver_ptr() {
|
||||
throw;
|
||||
}
|
||||
static rust::Vec<RtpTransceiverPtr> _vec_rtp_transceiver_ptr() {
|
||||
throw;
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/jsep.h"
|
||||
#include "api/ref_counted_base.h"
|
||||
#include "api/set_local_description_observer_interface.h"
|
||||
#include "api/set_remote_description_observer_interface.h"
|
||||
#include "api/stats/rtc_stats_collector_callback.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "rtc_base/ref_count.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class IceCandidate;
|
||||
class SessionDescription;
|
||||
}; // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/jsep.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class PeerContext;
|
||||
|
||||
class IceCandidate {
|
||||
public:
|
||||
explicit IceCandidate(
|
||||
std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate);
|
||||
|
||||
rust::String sdp_mid() const;
|
||||
int sdp_mline_index() const;
|
||||
rust::String candidate() const; // TODO(theomonnom) Return livekit_ffi::Candidate
|
||||
// instead of rust::String
|
||||
|
||||
rust::String stringify() const;
|
||||
std::unique_ptr<webrtc::IceCandidateInterface> release();
|
||||
|
||||
private:
|
||||
std::unique_ptr<webrtc::IceCandidateInterface> ice_candidate_;
|
||||
};
|
||||
|
||||
std::shared_ptr<IceCandidate> create_ice_candidate(rust::String sdp_mid,
|
||||
int sdp_mline_index,
|
||||
rust::String sdp);
|
||||
|
||||
static std::shared_ptr<IceCandidate> _shared_ice_candidate() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
class SessionDescription {
|
||||
public:
|
||||
explicit SessionDescription(
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> session_description);
|
||||
|
||||
SdpType sdp_type() const;
|
||||
rust::String stringify() const;
|
||||
std::unique_ptr<SessionDescription> clone() const;
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> release();
|
||||
|
||||
private:
|
||||
std::unique_ptr<webrtc::SessionDescriptionInterface> session_description_;
|
||||
};
|
||||
|
||||
std::unique_ptr<SessionDescription> create_session_description(
|
||||
SdpType type,
|
||||
rust::String sdp);
|
||||
|
||||
static std::unique_ptr<SessionDescription> _unique_session_description() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
#ifdef LIVEKIT_TEST
|
||||
rust::String serialize_sdp_parse_error_for_test();
|
||||
#endif
|
||||
|
||||
class NativeCreateSdpObserver
|
||||
: public webrtc::CreateSessionDescriptionObserver {
|
||||
public:
|
||||
NativeCreateSdpObserver(
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext> ctx,
|
||||
std::unique_ptr<SessionDescription>)> on_success,
|
||||
rust::Fn<void(rust::Box<PeerContext> ctx, RtcError)> on_error);
|
||||
|
||||
void OnSuccess(webrtc::SessionDescriptionInterface* desc) override;
|
||||
void OnFailure(webrtc::RTCError error) override;
|
||||
|
||||
private:
|
||||
rust::Box<PeerContext> ctx_;
|
||||
rust::Fn<void(rust::Box<PeerContext>, std::unique_ptr<SessionDescription>)>
|
||||
on_success_;
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_error_;
|
||||
};
|
||||
|
||||
class NativeSetLocalSdpObserver
|
||||
: public webrtc::SetLocalDescriptionObserverInterface {
|
||||
public:
|
||||
NativeSetLocalSdpObserver(
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete);
|
||||
|
||||
void OnSetLocalDescriptionComplete(webrtc::RTCError error) override;
|
||||
|
||||
private:
|
||||
rust::Box<PeerContext> ctx_;
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete_;
|
||||
};
|
||||
|
||||
class NativeSetRemoteSdpObserver
|
||||
: public webrtc::SetRemoteDescriptionObserverInterface {
|
||||
public:
|
||||
NativeSetRemoteSdpObserver(
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete);
|
||||
|
||||
void OnSetRemoteDescriptionComplete(webrtc::RTCError error) override;
|
||||
|
||||
private:
|
||||
rust::Box<PeerContext> ctx_;
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete_;
|
||||
};
|
||||
|
||||
template <class T> // Context type
|
||||
class NativeRtcStatsCollector : public webrtc::RTCStatsCollectorCallback {
|
||||
public:
|
||||
NativeRtcStatsCollector(rust::Box<T> ctx,
|
||||
rust::Fn<void(rust::Box<T>, rust::String)> on_stats)
|
||||
: ctx_(std::move(ctx)), on_stats_(on_stats) {}
|
||||
|
||||
void OnStatsDelivered(
|
||||
const webrtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override {
|
||||
on_stats_(std::move(ctx_), report->ToJson());
|
||||
}
|
||||
|
||||
private:
|
||||
rust::Box<T> ctx_;
|
||||
rust::Fn<void(rust::Box<T>, rust::String)> on_stats_;
|
||||
};
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class MediaStream;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/media_stream.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class MediaStream {
|
||||
public:
|
||||
MediaStream(std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
|
||||
|
||||
rust::String id() const;
|
||||
rust::Vec<VideoTrackPtr> get_video_tracks() const;
|
||||
rust::Vec<AudioTrackPtr> get_audio_tracks() const;
|
||||
|
||||
std::shared_ptr<AudioTrack> find_audio_track(rust::String track_id) const;
|
||||
std::shared_ptr<VideoTrack> find_video_track(rust::String track_id) const;
|
||||
|
||||
bool add_track(std::shared_ptr<MediaStreamTrack> track) const;
|
||||
bool remove_track(std::shared_ptr<MediaStreamTrack> track) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamInterface> media_stream_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<MediaStream> _shared_media_stream() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class MediaStreamTrack;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/media_stream_track.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class MediaStreamTrack {
|
||||
protected:
|
||||
MediaStreamTrack(std::shared_ptr<RtcRuntime>,
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
|
||||
|
||||
public:
|
||||
rust::String kind() const;
|
||||
rust::String id() const;
|
||||
|
||||
bool enabled() const;
|
||||
bool set_enabled(bool enable) const;
|
||||
|
||||
TrackState state() const;
|
||||
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> rtc_track() const {
|
||||
return track_;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<MediaStreamTrack> _shared_media_stream_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
std::unique_ptr<webrtc::VideoEncoderFactory> CreateObjCVideoEncoderFactory();
|
||||
std::unique_ptr<webrtc::VideoDecoderFactory> CreateObjCVideoDecoderFactory();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/frame_transformer_interface.h"
|
||||
#include "api/rtp_sender_interface.h"
|
||||
#include "api/rtp_receiver_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
// Forward declarations to avoid circular includes
|
||||
// (video_track.h -> packet_trailer.h -> peer_connection.h -> media_stream.h -> video_track.h)
|
||||
namespace livekit_ffi {
|
||||
class PeerConnectionFactory;
|
||||
class RtpSender;
|
||||
class RtpReceiver;
|
||||
enum class VideoPublishTimingStage : int32_t;
|
||||
enum class VideoSubscribeTimingStage : int32_t;
|
||||
struct VideoPublishTimingObserverWrapper;
|
||||
struct VideoSubscribeTimingObserverWrapper;
|
||||
} // namespace livekit_ffi
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
// Magic bytes to identify packet trailers: "LKTS" (LiveKit TimeStamp)
|
||||
constexpr uint8_t kPacketTrailerMagic[4] = {'L', 'K', 'T', 'S'};
|
||||
|
||||
// Trailer envelope: [trailer_len: 1B] [magic: 4B] = 5 bytes.
|
||||
// Always present at the end of every trailer.
|
||||
constexpr size_t kTrailerEnvelopeSize = 5;
|
||||
|
||||
// TLV element overhead: [tag: 1B] [len: 1B] = 2 bytes before value.
|
||||
// All TLV bytes (tag, len, value) are XORed with 0xFF.
|
||||
|
||||
// TLV tag IDs
|
||||
constexpr uint8_t kTagTimestampUs = 0x01; // value: 8 bytes big-endian uint64
|
||||
constexpr uint8_t kTagFrameId = 0x02; // value: 4 bytes big-endian uint32
|
||||
|
||||
constexpr size_t kTimestampTlvSize = 10; // tag + len + 8-byte value
|
||||
constexpr size_t kFrameIdTlvSize = 6; // tag + len + 4-byte value
|
||||
|
||||
// Trailer size varies because frame_id is omitted when it is unset (0).
|
||||
constexpr size_t kPacketTrailerMinSize =
|
||||
kTimestampTlvSize + kTrailerEnvelopeSize;
|
||||
constexpr size_t kPacketTrailerMaxSize =
|
||||
kTimestampTlvSize + kFrameIdTlvSize + kTrailerEnvelopeSize;
|
||||
|
||||
struct PacketTrailerMetadata {
|
||||
uint64_t user_timestamp;
|
||||
uint32_t frame_id;
|
||||
uint32_t ssrc; // SSRC that produced this entry (for simulcast tracking)
|
||||
};
|
||||
|
||||
/// Frame transformer that appends/extracts packet trailers.
|
||||
/// This transformer can be used standalone or in conjunction with e2ee.
|
||||
///
|
||||
/// On the send side, user timestamps are stored in an internal map keyed
|
||||
/// by capture timestamp (microseconds). When TransformSend fires it
|
||||
/// looks up the user timestamp via the frame's CaptureTime().
|
||||
///
|
||||
/// On the receive side, extracted frame metadata is stored in an
|
||||
/// internal map keyed by RTP timestamp (uint32_t). Decoded frames can
|
||||
/// look up their metadata via lookup_frame_metadata(rtp_ts).
|
||||
class PacketTrailerTransformer : public webrtc::FrameTransformerInterface {
|
||||
public:
|
||||
enum class Direction { kSend, kReceive };
|
||||
|
||||
explicit PacketTrailerTransformer(Direction direction);
|
||||
~PacketTrailerTransformer() override = default;
|
||||
|
||||
// FrameTransformerInterface implementation
|
||||
void Transform(
|
||||
std::unique_ptr<webrtc::TransformableFrameInterface> frame) override;
|
||||
void RegisterTransformedFrameCallback(
|
||||
webrtc::scoped_refptr<webrtc::TransformedFrameCallback> callback) override;
|
||||
void RegisterTransformedFrameSinkCallback(
|
||||
webrtc::scoped_refptr<webrtc::TransformedFrameCallback> callback,
|
||||
uint32_t ssrc) override;
|
||||
void UnregisterTransformedFrameCallback() override;
|
||||
void UnregisterTransformedFrameSinkCallback(uint32_t ssrc) override;
|
||||
|
||||
/// Enable/disable timestamp embedding
|
||||
void set_enabled(bool enabled);
|
||||
bool enabled() const;
|
||||
|
||||
/// Lookup the frame metadata associated with a given RTP timestamp.
|
||||
/// Returns the metadata if found, nullopt otherwise.
|
||||
/// The entry is removed from the map after lookup.
|
||||
std::optional<PacketTrailerMetadata> lookup_frame_metadata(uint32_t rtp_timestamp);
|
||||
|
||||
/// Store frame metadata for a given capture timestamp (sender side).
|
||||
/// Called from VideoTrackSource::on_captured_frame with the
|
||||
/// TimestampAligner-adjusted timestamp, which matches CaptureTime()
|
||||
/// in the encoder pipeline.
|
||||
void store_frame_metadata(int64_t capture_timestamp_us,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id);
|
||||
|
||||
/// Set the observer receiving sender-side publish timing events.
|
||||
void set_publish_timing_observer(
|
||||
rust::Box<VideoPublishTimingObserverWrapper> observer);
|
||||
|
||||
/// Clear the observer receiving sender-side publish timing events.
|
||||
void clear_publish_timing_observer();
|
||||
|
||||
/// Emit a sender-side publish timing event.
|
||||
void emit_publish_timing(VideoPublishTimingStage stage,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id) const;
|
||||
|
||||
/// Set the observer receiving receiver-side subscribe timing events.
|
||||
void set_subscribe_timing_observer(
|
||||
rust::Box<VideoSubscribeTimingObserverWrapper> observer);
|
||||
|
||||
/// Clear the observer receiving receiver-side subscribe timing events.
|
||||
void clear_subscribe_timing_observer();
|
||||
|
||||
/// Emit a receiver-side subscribe timing event.
|
||||
void emit_subscribe_timing(VideoSubscribeTimingStage stage,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id) const;
|
||||
|
||||
private:
|
||||
void TransformSend(
|
||||
std::unique_ptr<webrtc::TransformableFrameInterface> frame);
|
||||
void TransformReceive(
|
||||
std::unique_ptr<webrtc::TransformableFrameInterface> frame);
|
||||
void emit_subscribe_timing(VideoSubscribeTimingStage stage,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id,
|
||||
uint64_t timestamp_us) const;
|
||||
bool publish_timing_enabled() const;
|
||||
bool subscribe_timing_enabled() const;
|
||||
|
||||
PacketTrailerMetadata LookupSendMetadata(
|
||||
const webrtc::TransformableFrameInterface& frame,
|
||||
uint32_t ssrc,
|
||||
uint32_t rtp_timestamp) const;
|
||||
|
||||
/// Append frame metadata trailer to frame data
|
||||
std::vector<uint8_t> AppendTrailer(
|
||||
webrtc::ArrayView<const uint8_t> data,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id);
|
||||
|
||||
/// Extract and remove frame metadata trailer from frame data
|
||||
std::optional<PacketTrailerMetadata> ExtractTrailer(
|
||||
webrtc::ArrayView<const uint8_t> data,
|
||||
std::vector<uint8_t>& out_data);
|
||||
|
||||
const Direction direction_;
|
||||
std::atomic<bool> enabled_{true};
|
||||
mutable webrtc::Mutex mutex_;
|
||||
webrtc::scoped_refptr<webrtc::TransformedFrameCallback> callback_;
|
||||
std::unordered_map<uint32_t,
|
||||
webrtc::scoped_refptr<webrtc::TransformedFrameCallback>>
|
||||
sink_callbacks_;
|
||||
// Send-side map: capture timestamp (us) -> frame metadata.
|
||||
// Populated by store_frame_metadata(), consumed by TransformSend()
|
||||
// via CaptureTime() lookup.
|
||||
mutable webrtc::Mutex send_map_mutex_;
|
||||
mutable std::unordered_map<int64_t, PacketTrailerMetadata> send_map_;
|
||||
mutable std::deque<int64_t> send_map_order_;
|
||||
static constexpr size_t kMaxSendMapEntries = 300;
|
||||
|
||||
// Receive-side map: RTP timestamp -> frame metadata.
|
||||
// Keyed by RTP timestamp so decoded frames can look up their
|
||||
// metadata regardless of frame drops or reordering.
|
||||
mutable webrtc::Mutex recv_map_mutex_;
|
||||
mutable std::unordered_map<uint32_t, PacketTrailerMetadata> recv_map_;
|
||||
mutable std::deque<uint32_t> recv_map_order_;
|
||||
static constexpr size_t kMaxRecvMapEntries = 300;
|
||||
|
||||
// Simulcast tracking: detect layer switches and flush stale entries.
|
||||
mutable uint32_t recv_active_ssrc_{0};
|
||||
|
||||
mutable webrtc::Mutex publish_timing_observer_mutex_;
|
||||
std::atomic<bool> publish_timing_enabled_{false};
|
||||
mutable std::shared_ptr<rust::Box<VideoPublishTimingObserverWrapper>>
|
||||
publish_timing_observer_;
|
||||
mutable webrtc::Mutex subscribe_timing_observer_mutex_;
|
||||
std::atomic<bool> subscribe_timing_enabled_{false};
|
||||
mutable std::shared_ptr<rust::Box<VideoSubscribeTimingObserverWrapper>>
|
||||
subscribe_timing_observer_;
|
||||
};
|
||||
|
||||
/// Wrapper class for Rust FFI that manages packet trailer transformers.
|
||||
class PacketTrailerHandler {
|
||||
public:
|
||||
PacketTrailerHandler(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender);
|
||||
|
||||
PacketTrailerHandler(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver);
|
||||
|
||||
~PacketTrailerHandler() = default;
|
||||
|
||||
/// Enable/disable timestamp embedding
|
||||
void set_enabled(bool enabled) const;
|
||||
bool enabled() const;
|
||||
|
||||
/// Lookup the user timestamp for a given RTP timestamp (receiver side).
|
||||
/// Returns UINT64_MAX if not found. The entry is removed after lookup.
|
||||
/// Also caches the frame_id for retrieval via last_lookup_frame_id().
|
||||
uint64_t lookup_timestamp(uint32_t rtp_timestamp) const;
|
||||
|
||||
/// Returns the frame_id from the most recent successful
|
||||
/// lookup_timestamp() call. Returns 0 if no lookup succeeded.
|
||||
uint32_t last_lookup_frame_id() const;
|
||||
|
||||
/// Store frame metadata for a given capture timestamp (sender side).
|
||||
void store_frame_metadata(int64_t capture_timestamp_us,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id) const;
|
||||
|
||||
/// Set the observer receiving sender-side publish timing events.
|
||||
void set_publish_timing_observer(
|
||||
rust::Box<VideoPublishTimingObserverWrapper> observer) const;
|
||||
|
||||
/// Clear the observer receiving sender-side publish timing events.
|
||||
void clear_publish_timing_observer() const;
|
||||
|
||||
/// Emit a sender-side publish timing event.
|
||||
void emit_publish_timing(VideoPublishTimingStage stage,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id) const;
|
||||
|
||||
/// Set the observer receiving receiver-side subscribe timing events.
|
||||
void set_subscribe_timing_observer(
|
||||
rust::Box<VideoSubscribeTimingObserverWrapper> observer) const;
|
||||
|
||||
/// Clear the observer receiving receiver-side subscribe timing events.
|
||||
void clear_subscribe_timing_observer() const;
|
||||
|
||||
/// Emit a receiver-side subscribe timing event.
|
||||
void emit_subscribe_timing(VideoSubscribeTimingStage stage,
|
||||
uint64_t user_timestamp,
|
||||
uint32_t frame_id) const;
|
||||
|
||||
/// Access the underlying transformer for chaining.
|
||||
webrtc::scoped_refptr<PacketTrailerTransformer> transformer() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<PacketTrailerTransformer> transformer_;
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender_;
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
|
||||
mutable uint32_t last_frame_id_{0};
|
||||
};
|
||||
|
||||
// Factory functions for Rust FFI
|
||||
|
||||
std::shared_ptr<PacketTrailerHandler> new_packet_trailer_sender(
|
||||
std::shared_ptr<PeerConnectionFactory> peer_factory,
|
||||
std::shared_ptr<RtpSender> sender);
|
||||
|
||||
std::shared_ptr<PacketTrailerHandler> new_packet_trailer_receiver(
|
||||
std::shared_ptr<PeerConnectionFactory> peer_factory,
|
||||
std::shared_ptr<RtpReceiver> receiver);
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/data_channel.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/jsep.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_receiver.h"
|
||||
#include "livekit/rtp_sender.h"
|
||||
#include "livekit/rtp_transceiver.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "webrtc-sys/src/data_channel.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class PeerConnection;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/peer_connection.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration to_native_rtc_configuration(
|
||||
RtcConfiguration config);
|
||||
|
||||
class PeerConnectionObserverWrapper;
|
||||
|
||||
class PeerConnection : webrtc::PeerConnectionObserver {
|
||||
public:
|
||||
PeerConnection(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory,
|
||||
rust::Box<PeerConnectionObserverWrapper> observer);
|
||||
|
||||
~PeerConnection();
|
||||
|
||||
bool Initialize(webrtc::PeerConnectionInterface::RTCConfiguration config);
|
||||
|
||||
void set_configuration(RtcConfiguration config) const;
|
||||
|
||||
void create_offer(
|
||||
RtcOfferAnswerOptions options,
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>,
|
||||
std::unique_ptr<SessionDescription>)> on_success,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_error) const;
|
||||
|
||||
void create_answer(
|
||||
RtcOfferAnswerOptions options,
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>,
|
||||
std::unique_ptr<SessionDescription>)> on_success,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_error) const;
|
||||
|
||||
void set_local_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete) const;
|
||||
|
||||
void set_remote_description(
|
||||
std::unique_ptr<SessionDescription> desc,
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete) const;
|
||||
|
||||
std::shared_ptr<DataChannel> create_data_channel(rust::String label,
|
||||
DataChannelInit init) const;
|
||||
|
||||
void add_ice_candidate(
|
||||
std::shared_ptr<IceCandidate> candidate,
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, RtcError)> on_complete) const;
|
||||
|
||||
std::shared_ptr<RtpSender> add_track(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
const rust::Vec<rust::String>& stream_ids) const;
|
||||
|
||||
void remove_track(std::shared_ptr<RtpSender> sender) const;
|
||||
|
||||
void get_stats(
|
||||
rust::Box<PeerContext> ctx,
|
||||
rust::Fn<void(rust::Box<PeerContext>, rust::String)> on_stats) const;
|
||||
|
||||
void restart_ice() const;
|
||||
|
||||
std::shared_ptr<RtpTransceiver> add_transceiver(
|
||||
std::shared_ptr<MediaStreamTrack> track,
|
||||
RtpTransceiverInit init) const;
|
||||
|
||||
std::shared_ptr<RtpTransceiver> add_transceiver_for_media(
|
||||
MediaType media_type,
|
||||
RtpTransceiverInit init) const;
|
||||
|
||||
rust::Vec<RtpSenderPtr> get_senders() const;
|
||||
|
||||
rust::Vec<RtpReceiverPtr> get_receivers() const;
|
||||
|
||||
rust::Vec<RtpTransceiverPtr> get_transceivers() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> current_local_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> current_remote_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> pending_local_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> pending_remote_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> local_description() const;
|
||||
|
||||
std::unique_ptr<SessionDescription> remote_description() const;
|
||||
|
||||
PeerConnectionState connection_state() const;
|
||||
|
||||
SignalingState signaling_state() const;
|
||||
|
||||
IceGatheringState ice_gathering_state() const;
|
||||
|
||||
IceConnectionState ice_connection_state() const;
|
||||
|
||||
void close() const;
|
||||
|
||||
void OnSignalingChange(
|
||||
webrtc::PeerConnectionInterface::SignalingState new_state) override;
|
||||
|
||||
void OnAddStream(
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
|
||||
void OnRemoveStream(
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
|
||||
void OnDataChannel(
|
||||
webrtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) override;
|
||||
|
||||
void OnRenegotiationNeeded() override;
|
||||
|
||||
void OnNegotiationNeededEvent(uint32_t event_id) override;
|
||||
|
||||
void OnIceConnectionChange(
|
||||
webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
|
||||
|
||||
void OnStandardizedIceConnectionChange(
|
||||
webrtc::PeerConnectionInterface::IceConnectionState new_state) override;
|
||||
|
||||
void OnConnectionChange(
|
||||
webrtc::PeerConnectionInterface::PeerConnectionState new_state) override;
|
||||
|
||||
void OnIceGatheringChange(
|
||||
webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
|
||||
|
||||
void OnIceCandidate(const webrtc::IceCandidate* candidate) override;
|
||||
|
||||
void OnIceCandidateError(const std::string& address,
|
||||
int port,
|
||||
const std::string& url,
|
||||
int error_code,
|
||||
const std::string& error_text) override;
|
||||
|
||||
void OnIceCandidateRemoved(const webrtc::IceCandidate* candidate) override;
|
||||
|
||||
void OnIceConnectionReceivingChange(bool receiving) override;
|
||||
|
||||
void OnIceSelectedCandidatePairChanged(
|
||||
const webrtc::CandidatePairChangeEvent& event) override;
|
||||
|
||||
void OnAddTrack(
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
|
||||
const std::vector<webrtc::scoped_refptr<webrtc::MediaStreamInterface>>&
|
||||
streams) override;
|
||||
|
||||
void OnTrack(
|
||||
webrtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver) override;
|
||||
|
||||
void OnRemoveTrack(
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
|
||||
|
||||
void OnInterestingUsage(int usage_pattern) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> pc_factory_;
|
||||
rust::Box<PeerConnectionObserverWrapper> observer_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<PeerConnection> _shared_peer_connection() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/environment/environment_factory.h"
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/task_queue/task_queue_factory.h"
|
||||
#include "livekit/adm_proxy.h"
|
||||
#include "livekit/audio_device_controller.h"
|
||||
#include "media_stream.h"
|
||||
#include "rtp_parameters.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "webrtc.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class PeerConnectionFactory;
|
||||
class AudioDeviceController;
|
||||
class PeerConnectionObserverWrapper;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/peer_connection_factory.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class PeerConnection;
|
||||
struct RtcConfiguration;
|
||||
|
||||
webrtc::PeerConnectionInterface::RTCConfiguration to_native_rtc_configuration(
|
||||
RtcConfiguration config);
|
||||
|
||||
class PeerConnectionFactory {
|
||||
public:
|
||||
explicit PeerConnectionFactory(std::shared_ptr<RtcRuntime> rtc_runtime);
|
||||
~PeerConnectionFactory();
|
||||
|
||||
std::shared_ptr<PeerConnection> create_peer_connection(
|
||||
RtcConfiguration config,
|
||||
rust::Box<PeerConnectionObserverWrapper> observer) const;
|
||||
|
||||
std::shared_ptr<VideoTrack> create_video_track(
|
||||
rust::String label,
|
||||
std::shared_ptr<VideoTrackSource> source) const;
|
||||
|
||||
std::shared_ptr<AudioTrack> create_audio_track(
|
||||
rust::String label,
|
||||
std::shared_ptr<AudioTrackSource> source) const;
|
||||
|
||||
// Create an audio track that uses the ADM for capture (microphone)
|
||||
// This creates a track that captures from the selected recording device
|
||||
std::shared_ptr<AudioTrack> create_device_audio_track(
|
||||
rust::String label) const;
|
||||
|
||||
RtpCapabilities rtp_sender_capabilities(MediaType type) const;
|
||||
|
||||
RtpCapabilities rtp_receiver_capabilities(MediaType type) const;
|
||||
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime() const { return rtc_runtime_; }
|
||||
std::shared_ptr<AudioDeviceController> audio_device() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<AdmProxy> adm_proxy_;
|
||||
std::shared_ptr<AudioDeviceController> audio_device_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_factory_;
|
||||
webrtc::Environment env_;
|
||||
};
|
||||
|
||||
std::shared_ptr<PeerConnectionFactory> create_peer_connection_factory();
|
||||
} // namespace livekit_ffi
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace livekit_ffi {
|
||||
void ProhibitLibsrtpInitialization();
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2026 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include "api/audio/audio_device_defines.h"
|
||||
#include "api/audio/audio_frame.h"
|
||||
#include "common_audio/resampler/include/push_resampler.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
struct RecordedAudioSinkWrapper;
|
||||
|
||||
// Installs the process-global recorded-audio sink. The platform ADM delivers
|
||||
// 10ms PCM frames on its capture thread; while a sink is installed each frame
|
||||
// is resampled to 48kHz mono and handed to Rust. Returns a generation token so
|
||||
// a later clear can target exactly this installation and never clobber a sink
|
||||
// that a subsequent caller installed in the meantime.
|
||||
uint64_t set_recorded_audio_sink(rust::Box<RecordedAudioSinkWrapper> sink);
|
||||
|
||||
// Removes the global recorded-audio sink only if `generation` matches the
|
||||
// currently-installed sink. A stale token is a no-op.
|
||||
void clear_recorded_audio_sink(uint64_t generation);
|
||||
|
||||
// AudioTransport interposer registered with the platform ADM in place of the
|
||||
// real transport. It tees recorded microphone frames to the global sink and
|
||||
// forwards every call unchanged to the real transport so the normal send and
|
||||
// playout pipelines are unaffected.
|
||||
class RecordingTransportProxy : public webrtc::AudioTransport {
|
||||
public:
|
||||
RecordingTransportProxy();
|
||||
~RecordingTransportProxy();
|
||||
|
||||
void set_real_transport(webrtc::AudioTransport* transport);
|
||||
|
||||
int32_t RecordedDataIsAvailable(const void* audioSamples,
|
||||
size_t nSamples,
|
||||
size_t nBytesPerSample,
|
||||
size_t nChannels,
|
||||
uint32_t samplesPerSec,
|
||||
uint32_t totalDelayMS,
|
||||
int32_t clockDrift,
|
||||
uint32_t currentMicLevel,
|
||||
bool keyPressed,
|
||||
uint32_t& newMicLevel) override;
|
||||
|
||||
int32_t RecordedDataIsAvailable(
|
||||
const void* audioSamples,
|
||||
size_t nSamples,
|
||||
size_t nBytesPerSample,
|
||||
size_t nChannels,
|
||||
uint32_t samplesPerSec,
|
||||
uint32_t totalDelayMS,
|
||||
int32_t clockDrift,
|
||||
uint32_t currentMicLevel,
|
||||
bool keyPressed,
|
||||
uint32_t& newMicLevel,
|
||||
std::optional<int64_t> estimatedCaptureTimeNS) override;
|
||||
|
||||
int32_t NeedMorePlayData(size_t nSamples,
|
||||
size_t nBytesPerSample,
|
||||
size_t nChannels,
|
||||
uint32_t samplesPerSec,
|
||||
void* audioSamples,
|
||||
size_t& nSamplesOut,
|
||||
int64_t* elapsed_time_ms,
|
||||
int64_t* ntp_time_ms) override;
|
||||
|
||||
void PullRenderData(int bits_per_sample,
|
||||
int sample_rate,
|
||||
size_t number_of_channels,
|
||||
size_t number_of_frames,
|
||||
void* audio_data,
|
||||
int64_t* elapsed_time_ms,
|
||||
int64_t* ntp_time_ms) override;
|
||||
|
||||
private:
|
||||
void TeeRecordedData(const void* audioSamples,
|
||||
size_t nSamples,
|
||||
size_t nBytesPerSample,
|
||||
size_t nChannels,
|
||||
uint32_t samplesPerSec);
|
||||
|
||||
std::atomic<webrtc::AudioTransport*> real_transport_{nullptr};
|
||||
|
||||
// Touched only on the ADM capture thread inside RecordedDataIsAvailable,
|
||||
// which WebRTC serializes, so neither member needs a lock.
|
||||
webrtc::AudioFrame capture_frame_;
|
||||
webrtc::PushResampler<int16_t> capture_resampler_;
|
||||
};
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/rtc_error.h"
|
||||
#include "rust/cxx.h"
|
||||
#include "webrtc-sys/src/rtc_error.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
RtcError to_error(const webrtc::RTCError& error);
|
||||
std::string serialize_error(
|
||||
const RtcError& error); // to be used inside cxx::Exception msg
|
||||
|
||||
#ifdef LIVEKIT_TEST
|
||||
rust::String serialize_deserialize();
|
||||
#endif
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_types.h"
|
||||
#include "api/priority.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_direction.h"
|
||||
#include "webrtc-sys/src/rtp_parameters.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
webrtc::RtcpFeedback to_native_rtcp_feedback(RtcpFeedback feedback);
|
||||
webrtc::RtpCodecCapability to_native_rtp_codec_capability(
|
||||
RtpCodecCapability capability);
|
||||
webrtc::RtpHeaderExtensionCapability to_native_rtp_header_extension_capability(
|
||||
RtpHeaderExtensionCapability header);
|
||||
webrtc::RtpExtension to_native_rtp_extension(RtpExtension ext);
|
||||
webrtc::RtpFecParameters to_rtp_fec_parameters(RtpFecParameters fec);
|
||||
webrtc::RtpRtxParameters to_rtp_rtx_parameters(RtpRtxParameters rtx);
|
||||
webrtc::RtpEncodingParameters to_native_rtp_encoding_paramters(
|
||||
RtpEncodingParameters parameters);
|
||||
webrtc::RtpCodecParameters to_native_rtp_codec_parameters(
|
||||
RtpCodecParameters params);
|
||||
webrtc::RtpCapabilities to_rtp_capabilities(RtpCapabilities capabilities);
|
||||
webrtc::RtcpParameters to_native_rtcp_paramaters(RtcpParameters params);
|
||||
webrtc::RtpParameters to_native_rtp_parameters(RtpParameters params);
|
||||
|
||||
RtcpFeedback to_rust_rtcp_feedback(webrtc::RtcpFeedback feedback);
|
||||
RtpCodecCapability to_rust_rtp_codec_capability(
|
||||
webrtc::RtpCodecCapability capability);
|
||||
RtpHeaderExtensionCapability to_rust_rtp_header_extension_capability(
|
||||
webrtc::RtpHeaderExtensionCapability header);
|
||||
RtpExtension to_rust_rtp_extension(webrtc::RtpExtension ext);
|
||||
RtpFecParameters to_rust_rtp_fec_parameters(webrtc::RtpFecParameters fec);
|
||||
RtpRtxParameters to_rust_rtp_rtx_parameters(webrtc::RtpRtxParameters param);
|
||||
RtpEncodingParameters to_rust_rtp_encoding_parameters(
|
||||
webrtc::RtpEncodingParameters params);
|
||||
RtpCodecParameters to_rust_rtp_codec_parameters(
|
||||
webrtc::RtpCodecParameters params);
|
||||
RtpCapabilities to_rust_rtp_capabilities(webrtc::RtpCapabilities capabilities);
|
||||
RtcpParameters to_rust_rtcp_parameters(webrtc::RtcpParameters params);
|
||||
RtpParameters to_rust_rtp_parameters(webrtc::RtpParameters params);
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/rtp_receiver_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class RtpReceiver;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_receiver.rs.h"
|
||||
namespace livekit_ffi {
|
||||
|
||||
// TODO(theomonnom): Implement RtpReceiverObserverInterface?
|
||||
// TODO(theomonnom): RtpSource
|
||||
// TODO(theomonnom): FrameTransformer & FrameDecryptor interface
|
||||
class RtpReceiver {
|
||||
public:
|
||||
RtpReceiver(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> track() const;
|
||||
|
||||
void get_stats(
|
||||
rust::Box<ReceiverContext> ctx,
|
||||
rust::Fn<void(rust::Box<ReceiverContext>, rust::String)> on_stats) const;
|
||||
|
||||
rust::Vec<rust::String> stream_ids() const;
|
||||
rust::Vec<MediaStreamPtr> streams() const;
|
||||
|
||||
MediaType media_type() const;
|
||||
rust::String id() const;
|
||||
|
||||
RtpParameters get_parameters() const;
|
||||
|
||||
// bool set_parameters(RtpParameters parameters) const; // Seems unsupported
|
||||
|
||||
void set_jitter_buffer_minimum_delay(bool is_some,
|
||||
double delay_seconds) const;
|
||||
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> rtc_receiver() const {
|
||||
return receiver_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<RtpReceiver> _shared_rtp_receiver() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/rtp_sender_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/media_stream.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class RtpSender;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_sender.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
// TODO(theomonnom): FrameTransformer & FrameEncryptor interface
|
||||
class RtpSender {
|
||||
public:
|
||||
RtpSender(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender,
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
|
||||
|
||||
bool set_track(std::shared_ptr<MediaStreamTrack> track) const;
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> track() const;
|
||||
|
||||
uint32_t ssrc() const;
|
||||
|
||||
void get_stats(
|
||||
rust::Box<SenderContext> ctx,
|
||||
rust::Fn<void(rust::Box<SenderContext>, rust::String)> on_stats) const;
|
||||
|
||||
MediaType media_type() const;
|
||||
|
||||
rust::String id() const;
|
||||
|
||||
rust::Vec<rust::String> stream_ids() const;
|
||||
|
||||
void set_streams(const rust::Vec<rust::String>& stream_ids) const;
|
||||
|
||||
rust::Vec<RtpEncodingParameters> init_send_encodings() const;
|
||||
|
||||
RtpParameters get_parameters() const;
|
||||
|
||||
void set_parameters(RtpParameters params) const;
|
||||
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> rtc_sender() const {
|
||||
return sender_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::RtpSenderInterface> sender_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<RtpSender> _shared_rtp_sender() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
} // namespace livekit_ffi
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/peer_connection_interface.h"
|
||||
#include "api/rtp_parameters.h"
|
||||
#include "api/rtp_transceiver_direction.h"
|
||||
#include "api/rtp_transceiver_interface.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "livekit/rtc_error.h"
|
||||
#include "livekit/rtp_parameters.h"
|
||||
#include "livekit/rtp_receiver.h"
|
||||
#include "livekit/rtp_sender.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class RtpTransceiver;
|
||||
}
|
||||
#include "webrtc-sys/src/rtp_transceiver.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
webrtc::RtpTransceiverInit to_native_rtp_transceiver_init(
|
||||
RtpTransceiverInit init);
|
||||
|
||||
class RtpTransceiver {
|
||||
public:
|
||||
RtpTransceiver(
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver,
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection);
|
||||
|
||||
MediaType media_type() const;
|
||||
|
||||
rust::String mid() const;
|
||||
|
||||
std::shared_ptr<RtpSender> sender() const;
|
||||
|
||||
std::shared_ptr<RtpReceiver> receiver() const;
|
||||
|
||||
bool stopped() const;
|
||||
|
||||
bool stopping() const;
|
||||
|
||||
RtpTransceiverDirection direction() const;
|
||||
|
||||
void set_direction(RtpTransceiverDirection direction) const;
|
||||
|
||||
RtpTransceiverDirection current_direction() const;
|
||||
|
||||
RtpTransceiverDirection fired_direction() const;
|
||||
|
||||
void stop_standard() const;
|
||||
|
||||
void set_codec_preferences(rust::Vec<RtpCodecCapability> codecs) const;
|
||||
|
||||
rust::Vec<RtpCodecCapability> codec_preferences() const;
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_negotiate()
|
||||
const;
|
||||
|
||||
rust::Vec<RtpHeaderExtensionCapability> negotiated_header_extensions() const;
|
||||
|
||||
void set_header_extensions_to_negotiate(
|
||||
rust::Vec<RtpHeaderExtensionCapability> header_extensions_to_offer) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<RtcRuntime> rtc_runtime_;
|
||||
webrtc::scoped_refptr<webrtc::RtpTransceiverInterface> transceiver_;
|
||||
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
|
||||
};
|
||||
|
||||
static std::shared_ptr<RtpTransceiver> _shared_rtp_transceiver() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
Vendored
+129
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "api/environment/environment.h"
|
||||
#include "api/task_queue/task_queue_base.h"
|
||||
#include "modules/audio_device/include/audio_device.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/task_utils/repeating_task.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class SyntheticAudioDevice : public webrtc::AudioDeviceModule {
|
||||
public:
|
||||
SyntheticAudioDevice(const webrtc::Environment& env);
|
||||
~SyntheticAudioDevice() override;
|
||||
|
||||
int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override;
|
||||
int32_t RegisterAudioCallback(webrtc::AudioTransport* transport) override;
|
||||
|
||||
int32_t Init() override;
|
||||
int32_t Terminate() override;
|
||||
bool Initialized() const override;
|
||||
|
||||
int16_t PlayoutDevices() override;
|
||||
int16_t RecordingDevices() override;
|
||||
int32_t PlayoutDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
|
||||
int32_t RecordingDeviceName(uint16_t index,
|
||||
char name[webrtc::kAdmMaxDeviceNameSize],
|
||||
char guid[webrtc::kAdmMaxGuidSize]) override;
|
||||
|
||||
int32_t SetPlayoutDevice(uint16_t index) override;
|
||||
int32_t SetPlayoutDevice(WindowsDeviceType device) override;
|
||||
int32_t SetRecordingDevice(uint16_t index) override;
|
||||
int32_t SetRecordingDevice(WindowsDeviceType device) override;
|
||||
|
||||
int32_t PlayoutIsAvailable(bool* available) override;
|
||||
int32_t InitPlayout() override;
|
||||
bool PlayoutIsInitialized() const override;
|
||||
int32_t RecordingIsAvailable(bool* available) override;
|
||||
int32_t InitRecording() override;
|
||||
bool RecordingIsInitialized() const override;
|
||||
|
||||
int32_t StartPlayout() override;
|
||||
int32_t StopPlayout() override;
|
||||
bool Playing() const override;
|
||||
int32_t StartRecording() override;
|
||||
int32_t StopRecording() override;
|
||||
bool Recording() const override;
|
||||
|
||||
int32_t InitSpeaker() override;
|
||||
bool SpeakerIsInitialized() const override;
|
||||
int32_t InitMicrophone() override;
|
||||
bool MicrophoneIsInitialized() const override;
|
||||
|
||||
int32_t SpeakerVolumeIsAvailable(bool* available) override;
|
||||
int32_t SetSpeakerVolume(uint32_t volume) override;
|
||||
int32_t SpeakerVolume(uint32_t* volume) const override;
|
||||
int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override;
|
||||
int32_t MinSpeakerVolume(uint32_t* minVolume) const override;
|
||||
|
||||
int32_t MicrophoneVolumeIsAvailable(bool* available) override;
|
||||
int32_t SetMicrophoneVolume(uint32_t volume) override;
|
||||
int32_t MicrophoneVolume(uint32_t* volume) const override;
|
||||
int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override;
|
||||
int32_t MinMicrophoneVolume(uint32_t* minVolume) const override;
|
||||
|
||||
int32_t SpeakerMuteIsAvailable(bool* available) override;
|
||||
int32_t SetSpeakerMute(bool enable) override;
|
||||
int32_t SpeakerMute(bool* enabled) const override;
|
||||
|
||||
int32_t MicrophoneMuteIsAvailable(bool* available) override;
|
||||
int32_t SetMicrophoneMute(bool enable) override;
|
||||
int32_t MicrophoneMute(bool* enabled) const override;
|
||||
|
||||
int32_t StereoPlayoutIsAvailable(bool* available) const override;
|
||||
int32_t SetStereoPlayout(bool enable) override;
|
||||
int32_t StereoPlayout(bool* enabled) const override;
|
||||
int32_t StereoRecordingIsAvailable(bool* available) const override;
|
||||
int32_t SetStereoRecording(bool enable) override;
|
||||
int32_t StereoRecording(bool* enabled) const override;
|
||||
|
||||
int32_t PlayoutDelay(uint16_t* delayMS) const override;
|
||||
|
||||
bool BuiltInAECIsAvailable() const override;
|
||||
bool BuiltInAGCIsAvailable() const override;
|
||||
bool BuiltInNSIsAvailable() const override;
|
||||
|
||||
int32_t EnableBuiltInAEC(bool enable) override;
|
||||
int32_t EnableBuiltInAGC(bool enable) override;
|
||||
int32_t EnableBuiltInNS(bool enable) override;
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(webrtc::AudioParameters* params) const override;
|
||||
int GetRecordAudioParameters(webrtc::AudioParameters* params) const override;
|
||||
#endif // WEBRTC_IOS
|
||||
|
||||
int32_t SetObserver(webrtc::AudioDeviceObserver* sink) override;
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex mutex_;
|
||||
std::vector<int16_t> data_;
|
||||
std::unique_ptr<webrtc::TaskQueueBase, webrtc::TaskQueueDeleter> audio_queue_;
|
||||
webrtc::RepeatingTaskHandle audio_task_;
|
||||
webrtc::AudioTransport* audio_transport_;
|
||||
const webrtc::Environment& env_;
|
||||
bool playing_{false};
|
||||
bool initialized_{false};
|
||||
};
|
||||
} // namespace livekit_ffi
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/video_codecs/video_decoder.h"
|
||||
#include "api/video_codecs/video_decoder_factory.h"
|
||||
#include "absl/strings/match.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class VideoDecoderFactory : public webrtc::VideoDecoderFactory {
|
||||
public:
|
||||
VideoDecoderFactory();
|
||||
|
||||
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
|
||||
|
||||
CodecSupport QueryCodecSupport(const webrtc::SdpVideoFormat& format,
|
||||
bool reference_scaling) const override;
|
||||
|
||||
std::unique_ptr<webrtc::VideoDecoder> Create(
|
||||
const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<webrtc::VideoDecoderFactory>> factories_;
|
||||
};
|
||||
} // namespace livekit_ffi
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/video_codecs/video_encoder.h"
|
||||
#include "api/video_codecs/video_encoder_factory.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class VideoEncoderFactory : public webrtc::VideoEncoderFactory {
|
||||
class InternalFactory : public webrtc::VideoEncoderFactory {
|
||||
public:
|
||||
InternalFactory();
|
||||
|
||||
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
|
||||
|
||||
CodecSupport QueryCodecSupport(
|
||||
const webrtc::SdpVideoFormat& format,
|
||||
std::optional<std::string> scalability_mode) const override;
|
||||
|
||||
std::unique_ptr<webrtc::VideoEncoder> Create(
|
||||
const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override;
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<webrtc::VideoEncoderFactory>> factories_;
|
||||
};
|
||||
|
||||
public:
|
||||
VideoEncoderFactory();
|
||||
|
||||
std::vector<webrtc::SdpVideoFormat> GetSupportedFormats() const override;
|
||||
|
||||
CodecSupport QueryCodecSupport(
|
||||
const webrtc::SdpVideoFormat& format,
|
||||
std::optional<std::string> scalability_mode) const override;
|
||||
|
||||
std::unique_ptr<webrtc::VideoEncoder> Create(
|
||||
const webrtc::Environment& env, const webrtc::SdpVideoFormat& format) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<InternalFactory> internal_factory_;
|
||||
};
|
||||
} // namespace livekit_ffi
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/video/video_frame.h"
|
||||
#include "livekit/video_frame_buffer.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class VideoFrame;
|
||||
class VideoFrameBuilder;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/video_frame.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class VideoFrame {
|
||||
public:
|
||||
explicit VideoFrame(const webrtc::VideoFrame& frame);
|
||||
|
||||
unsigned int width() const;
|
||||
unsigned int height() const;
|
||||
uint32_t size() const;
|
||||
uint16_t id() const;
|
||||
int64_t timestamp_us() const;
|
||||
int64_t ntp_time_ms() const;
|
||||
uint32_t timestamp() const;
|
||||
|
||||
VideoRotation rotation() const;
|
||||
std::unique_ptr<VideoFrameBuffer> video_frame_buffer() const;
|
||||
|
||||
webrtc::VideoFrame get() const;
|
||||
|
||||
private:
|
||||
webrtc::VideoFrame frame_;
|
||||
};
|
||||
|
||||
// Allow to create VideoFrames from Rust,
|
||||
// the builder pattern will be redone in Rust
|
||||
class VideoFrameBuilder {
|
||||
public:
|
||||
VideoFrameBuilder() = default;
|
||||
|
||||
// TODO(theomonnom): other setters?
|
||||
void set_video_frame_buffer(const VideoFrameBuffer& buffer);
|
||||
void set_timestamp_us(int64_t timestamp_us);
|
||||
void set_rotation(VideoRotation rotation);
|
||||
void set_id(uint16_t id);
|
||||
std::unique_ptr<VideoFrame> build();
|
||||
|
||||
private:
|
||||
webrtc::VideoFrame::Builder builder_;
|
||||
};
|
||||
|
||||
std::unique_ptr<VideoFrameBuilder> new_video_frame_builder();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+369
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "api/video/i420_buffer.h"
|
||||
#include "api/video/i422_buffer.h"
|
||||
#include "api/video/i444_buffer.h"
|
||||
#include "api/video/i010_buffer.h"
|
||||
#include "api/video/nv12_buffer.h"
|
||||
#include "api/video/video_frame_buffer.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class VideoFrameBuffer;
|
||||
class FluxerGpuFrameBuffer;
|
||||
class PlanarYuvBuffer;
|
||||
class PlanarYuv8Buffer;
|
||||
class PlanarYuv16BBuffer;
|
||||
class BiplanarYuvBuffer;
|
||||
class BiplanarYuv8Buffer;
|
||||
class I420Buffer;
|
||||
class I420ABuffer;
|
||||
class I422Buffer;
|
||||
class I444Buffer;
|
||||
class I010Buffer;
|
||||
class NV12Buffer;
|
||||
} // namespace livekit_ffi
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
namespace livekit_ffi {
|
||||
typedef __CVBuffer PlatformImageBuffer;
|
||||
} // namespace livekit_ffi
|
||||
#else
|
||||
namespace livekit_ffi {
|
||||
typedef void PlatformImageBuffer;
|
||||
} // namespace livekit_ffi
|
||||
#endif
|
||||
|
||||
#include "webrtc-sys/src/video_frame_buffer.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class VideoFrameBuffer {
|
||||
public:
|
||||
explicit VideoFrameBuffer(
|
||||
webrtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer);
|
||||
|
||||
VideoFrameBufferType buffer_type() const;
|
||||
|
||||
unsigned int width() const;
|
||||
unsigned int height() const;
|
||||
|
||||
std::unique_ptr<I420Buffer> to_i420() const;
|
||||
|
||||
// Requires ownership
|
||||
std::unique_ptr<I420Buffer> get_i420();
|
||||
std::unique_ptr<I420ABuffer> get_i420a();
|
||||
std::unique_ptr<I422Buffer> get_i422();
|
||||
std::unique_ptr<I444Buffer> get_i444();
|
||||
std::unique_ptr<I010Buffer> get_i010();
|
||||
std::unique_ptr<NV12Buffer> get_nv12();
|
||||
webrtc::scoped_refptr<webrtc::VideoFrameBuffer> get() const;
|
||||
|
||||
protected:
|
||||
webrtc::scoped_refptr<webrtc::VideoFrameBuffer> buffer_;
|
||||
};
|
||||
|
||||
class FluxerGpuFrameBuffer : public webrtc::VideoFrameBuffer {
|
||||
public:
|
||||
enum class Kind {
|
||||
kD3D11Texture,
|
||||
kDmaBuf,
|
||||
};
|
||||
|
||||
FluxerGpuFrameBuffer(uint64_t handle,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t dxgi_format);
|
||||
FluxerGpuFrameBuffer(int fd0,
|
||||
int fd1,
|
||||
int fd2,
|
||||
int fd3,
|
||||
uint32_t plane_count,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t drm_format,
|
||||
uint64_t modifier,
|
||||
uint32_t stride0,
|
||||
uint32_t stride1,
|
||||
uint32_t stride2,
|
||||
uint32_t stride3,
|
||||
uint32_t offset0,
|
||||
uint32_t offset1,
|
||||
uint32_t offset2,
|
||||
uint32_t offset3,
|
||||
uint64_t device_uuid_hi,
|
||||
uint64_t device_uuid_lo);
|
||||
~FluxerGpuFrameBuffer() override;
|
||||
|
||||
Type type() const override;
|
||||
int width() const override;
|
||||
int height() const override;
|
||||
webrtc::scoped_refptr<webrtc::I420BufferInterface> ToI420() override;
|
||||
webrtc::scoped_refptr<webrtc::VideoFrameBuffer> CropAndScale(
|
||||
int offset_x,
|
||||
int offset_y,
|
||||
int crop_width,
|
||||
int crop_height,
|
||||
int scaled_width,
|
||||
int scaled_height) override;
|
||||
webrtc::scoped_refptr<webrtc::VideoFrameBuffer> GetMappedFrameBuffer(
|
||||
webrtc::ArrayView<Type> types) override;
|
||||
std::string storage_representation() const override;
|
||||
|
||||
Kind kind() const { return kind_; }
|
||||
uint64_t d3d11_handle() const { return d3d11_handle_; }
|
||||
uint32_t dxgi_format() const { return dxgi_format_; }
|
||||
uint32_t drm_format() const { return drm_format_; }
|
||||
uint64_t modifier() const { return modifier_; }
|
||||
uint32_t plane_count() const { return plane_count_; }
|
||||
int fd(uint32_t plane) const;
|
||||
uint32_t stride(uint32_t plane) const;
|
||||
uint32_t offset(uint32_t plane) const;
|
||||
uint64_t device_uuid_hi() const { return device_uuid_hi_; }
|
||||
uint64_t device_uuid_lo() const { return device_uuid_lo_; }
|
||||
|
||||
private:
|
||||
Kind kind_;
|
||||
uint32_t width_;
|
||||
uint32_t height_;
|
||||
uint64_t d3d11_handle_ = 0;
|
||||
uint32_t dxgi_format_ = 0;
|
||||
int fds_[4] = {-1, -1, -1, -1};
|
||||
uint32_t plane_count_ = 0;
|
||||
uint32_t drm_format_ = 0;
|
||||
uint64_t modifier_ = 0;
|
||||
uint32_t strides_[4] = {0, 0, 0, 0};
|
||||
uint32_t offsets_[4] = {0, 0, 0, 0};
|
||||
uint64_t device_uuid_hi_ = 0;
|
||||
uint64_t device_uuid_lo_ = 0;
|
||||
};
|
||||
|
||||
const FluxerGpuFrameBuffer* AsFluxerGpuFrameBuffer(
|
||||
const webrtc::VideoFrameBuffer* buffer);
|
||||
|
||||
class PlanarYuvBuffer : public VideoFrameBuffer {
|
||||
public:
|
||||
explicit PlanarYuvBuffer(webrtc::scoped_refptr<webrtc::PlanarYuvBuffer> buffer);
|
||||
|
||||
unsigned int chroma_width() const;
|
||||
unsigned int chroma_height() const;
|
||||
|
||||
unsigned int stride_y() const;
|
||||
unsigned int stride_u() const;
|
||||
unsigned int stride_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuvBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class PlanarYuv8Buffer : public PlanarYuvBuffer {
|
||||
public:
|
||||
explicit PlanarYuv8Buffer(
|
||||
webrtc::scoped_refptr<webrtc::PlanarYuv8Buffer> buffer);
|
||||
|
||||
const uint8_t* data_y() const;
|
||||
const uint8_t* data_u() const;
|
||||
const uint8_t* data_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuv8Buffer* buffer() const;
|
||||
};
|
||||
|
||||
class PlanarYuv16BBuffer : public PlanarYuvBuffer {
|
||||
public:
|
||||
explicit PlanarYuv16BBuffer(
|
||||
webrtc::scoped_refptr<webrtc::PlanarYuv16BBuffer> buffer);
|
||||
|
||||
const uint16_t* data_y() const;
|
||||
const uint16_t* data_u() const;
|
||||
const uint16_t* data_v() const;
|
||||
|
||||
private:
|
||||
webrtc::PlanarYuv16BBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class BiplanarYuvBuffer : public VideoFrameBuffer {
|
||||
public:
|
||||
explicit BiplanarYuvBuffer(
|
||||
webrtc::scoped_refptr<webrtc::BiplanarYuvBuffer> buffer);
|
||||
|
||||
unsigned int chroma_width() const;
|
||||
unsigned int chroma_height() const;
|
||||
|
||||
unsigned int stride_y() const;
|
||||
unsigned int stride_uv() const;
|
||||
|
||||
private:
|
||||
webrtc::BiplanarYuvBuffer* buffer() const;
|
||||
};
|
||||
|
||||
class BiplanarYuv8Buffer : public BiplanarYuvBuffer {
|
||||
public:
|
||||
explicit BiplanarYuv8Buffer(
|
||||
webrtc::scoped_refptr<webrtc::BiplanarYuv8Buffer> buffer);
|
||||
|
||||
const uint8_t* data_y() const;
|
||||
const uint8_t* data_uv() const;
|
||||
|
||||
private:
|
||||
webrtc::BiplanarYuv8Buffer* buffer() const;
|
||||
};
|
||||
|
||||
class I420Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I420Buffer(webrtc::scoped_refptr<webrtc::I420BufferInterface> buffer);
|
||||
|
||||
std::unique_ptr<I420Buffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::I420BufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
class I420ABuffer : public I420Buffer {
|
||||
public:
|
||||
explicit I420ABuffer(webrtc::scoped_refptr<webrtc::I420ABufferInterface> buffer);
|
||||
|
||||
unsigned int stride_a() const;
|
||||
const uint8_t* data_a() const;
|
||||
|
||||
std::unique_ptr<I420ABuffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::I420ABufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
class I422Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I422Buffer(webrtc::scoped_refptr<webrtc::I422BufferInterface> buffer);
|
||||
|
||||
std::unique_ptr<I422Buffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::I422BufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
class I444Buffer : public PlanarYuv8Buffer {
|
||||
public:
|
||||
explicit I444Buffer(webrtc::scoped_refptr<webrtc::I444BufferInterface> buffer);
|
||||
|
||||
std::unique_ptr<I444Buffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::I444BufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
class I010Buffer : public PlanarYuv16BBuffer {
|
||||
public:
|
||||
explicit I010Buffer(webrtc::scoped_refptr<webrtc::I010BufferInterface> buffer);
|
||||
|
||||
std::unique_ptr<I010Buffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::I010BufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
class NV12Buffer : public BiplanarYuv8Buffer {
|
||||
public:
|
||||
explicit NV12Buffer(webrtc::scoped_refptr<webrtc::NV12BufferInterface> buffer);
|
||||
|
||||
std::unique_ptr<NV12Buffer> scale(int scaled_width, int scaled_height) const;
|
||||
|
||||
private:
|
||||
webrtc::NV12BufferInterface* buffer() const;
|
||||
};
|
||||
|
||||
std::unique_ptr<I420Buffer> copy_i420_buffer(
|
||||
const std::unique_ptr<I420Buffer>& i420);
|
||||
std::unique_ptr<I420Buffer> new_i420_buffer(int width, int height, int stride_y, int stride_u, int stride_v);
|
||||
std::unique_ptr<I422Buffer> new_i422_buffer(int width, int height, int stride_y, int stride_u, int stride_v);
|
||||
std::unique_ptr<I444Buffer> new_i444_buffer(int width, int height, int stride_y, int stride_u, int stride_v);
|
||||
std::unique_ptr<I010Buffer> new_i010_buffer(int width, int height, int stride_y, int stride_u, int stride_v);
|
||||
std::unique_ptr<NV12Buffer> new_nv12_buffer(int width, int height, int stride_y, int stride_uv);
|
||||
|
||||
std::unique_ptr<VideoFrameBuffer> new_fluxer_d3d11_texture_buffer(
|
||||
uint64_t handle, uint32_t width, uint32_t height, uint32_t dxgi_format);
|
||||
std::unique_ptr<VideoFrameBuffer> new_fluxer_dmabuf_texture_buffer(
|
||||
int fd0, int fd1, int fd2, int fd3, uint32_t plane_count,
|
||||
uint32_t width, uint32_t height, uint32_t drm_format, uint64_t modifier,
|
||||
uint32_t stride0, uint32_t stride1, uint32_t stride2, uint32_t stride3,
|
||||
uint32_t offset0, uint32_t offset1, uint32_t offset2, uint32_t offset3,
|
||||
uint64_t device_uuid_hi, uint64_t device_uuid_lo);
|
||||
bool is_fluxer_gpu_buffer(const std::unique_ptr<VideoFrameBuffer>& buffer);
|
||||
uint64_t fluxer_d3d11_texture_handle(const std::unique_ptr<VideoFrameBuffer>& buffer);
|
||||
uint32_t fluxer_gpu_buffer_width(const std::unique_ptr<VideoFrameBuffer>& buffer);
|
||||
uint32_t fluxer_gpu_buffer_height(const std::unique_ptr<VideoFrameBuffer>& buffer);
|
||||
uint32_t fluxer_gpu_buffer_format(const std::unique_ptr<VideoFrameBuffer>& buffer);
|
||||
|
||||
std::unique_ptr<VideoFrameBuffer> new_native_buffer_from_platform_image_buffer(PlatformImageBuffer *buffer);
|
||||
PlatformImageBuffer* native_buffer_to_platform_image_buffer(const std::unique_ptr<VideoFrameBuffer> &);
|
||||
|
||||
static const VideoFrameBuffer* yuv_to_vfb(const PlanarYuvBuffer* yuv) {
|
||||
return yuv;
|
||||
}
|
||||
|
||||
static const VideoFrameBuffer* biyuv_to_vfb(const BiplanarYuvBuffer* biyuv) {
|
||||
return biyuv;
|
||||
}
|
||||
|
||||
static const PlanarYuvBuffer* yuv8_to_yuv(const PlanarYuv8Buffer* yuv8) {
|
||||
return yuv8;
|
||||
}
|
||||
|
||||
static const PlanarYuvBuffer* yuv16b_to_yuv(const PlanarYuv16BBuffer* yuv16) {
|
||||
return yuv16;
|
||||
}
|
||||
|
||||
static const BiplanarYuvBuffer* biyuv8_to_biyuv(
|
||||
const BiplanarYuv8Buffer* biyuv8) {
|
||||
return biyuv8;
|
||||
}
|
||||
|
||||
static const PlanarYuv8Buffer* i420_to_yuv8(const I420Buffer* i420) {
|
||||
return i420;
|
||||
}
|
||||
|
||||
static const PlanarYuv8Buffer* i420a_to_yuv8(const I420ABuffer* i420a) {
|
||||
return i420a;
|
||||
}
|
||||
|
||||
static const PlanarYuv8Buffer* i422_to_yuv8(const I422Buffer* i422) {
|
||||
return i422;
|
||||
}
|
||||
|
||||
static const PlanarYuv8Buffer* i444_to_yuv8(const I444Buffer* i444) {
|
||||
return i444;
|
||||
}
|
||||
|
||||
static const PlanarYuv16BBuffer* i010_to_yuv16b(const I010Buffer* i010) {
|
||||
return i010;
|
||||
}
|
||||
|
||||
static const BiplanarYuv8Buffer* nv12_to_biyuv8(const NV12Buffer* nv12) {
|
||||
return nv12;
|
||||
}
|
||||
|
||||
static std::unique_ptr<VideoFrameBuffer> _unique_video_frame_buffer() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/video/video_frame.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "livekit/media_stream_track.h"
|
||||
#include "livekit/video_frame.h"
|
||||
#include "livekit/webrtc.h"
|
||||
#include "media/base/adapted_video_track_source.h"
|
||||
#include "rtc_base/synchronization/mutex.h"
|
||||
#include "rtc_base/timestamp_aligner.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
class VideoTrack;
|
||||
class NativeVideoSink;
|
||||
class VideoTrackSource;
|
||||
class PacketTrailerHandler; // forward declaration to avoid circular include
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/video_track.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class VideoTrack : public MediaStreamTrack {
|
||||
private:
|
||||
friend RtcRuntime;
|
||||
VideoTrack(std::shared_ptr<RtcRuntime> rtc_runtime,
|
||||
webrtc::scoped_refptr<webrtc::VideoTrackInterface> track);
|
||||
|
||||
public:
|
||||
~VideoTrack();
|
||||
|
||||
void add_sink(const std::shared_ptr<NativeVideoSink>& sink) const;
|
||||
void remove_sink(const std::shared_ptr<NativeVideoSink>& sink) const;
|
||||
|
||||
void set_should_receive(bool should_receive) const;
|
||||
bool should_receive() const;
|
||||
ContentHint content_hint() const;
|
||||
void set_content_hint(ContentHint hint) const;
|
||||
|
||||
private:
|
||||
webrtc::VideoTrackInterface* track() const {
|
||||
return static_cast<webrtc::VideoTrackInterface*>(track_.get());
|
||||
}
|
||||
|
||||
mutable webrtc::Mutex mutex_;
|
||||
|
||||
// Same for AudioTrack:
|
||||
// Keep a strong reference to the added sinks, so we don't need to
|
||||
// manage the lifetime safety on the Rust side
|
||||
mutable std::vector<std::shared_ptr<NativeVideoSink>> sinks_;
|
||||
};
|
||||
|
||||
class NativeVideoSink : public webrtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
explicit NativeVideoSink(rust::Box<VideoSinkWrapper> observer);
|
||||
|
||||
void OnFrame(const webrtc::VideoFrame& frame) override;
|
||||
void OnDiscardedFrame() override;
|
||||
void OnConstraintsChanged(
|
||||
const webrtc::VideoTrackSourceConstraints& constraints) override;
|
||||
|
||||
private:
|
||||
rust::Box<VideoSinkWrapper> observer_;
|
||||
};
|
||||
|
||||
std::shared_ptr<NativeVideoSink> new_native_video_sink(
|
||||
rust::Box<VideoSinkWrapper> observer);
|
||||
|
||||
class VideoTrackSource {
|
||||
class InternalSource : public webrtc::AdaptedVideoTrackSource {
|
||||
public:
|
||||
InternalSource(const VideoResolution& resolution,
|
||||
bool is_screencast); // (0, 0) means no resolution/optional, the
|
||||
// source will guess the resolution at the
|
||||
// first captured frame
|
||||
~InternalSource() override;
|
||||
|
||||
bool is_screencast() const override;
|
||||
std::optional<bool> needs_denoising() const override;
|
||||
SourceState state() const override;
|
||||
bool remote() const override;
|
||||
VideoResolution video_resolution() const;
|
||||
bool on_captured_frame(const webrtc::VideoFrame& frame,
|
||||
const FrameMetadata& frame_metadata);
|
||||
|
||||
void set_packet_trailer_handler(
|
||||
std::shared_ptr<PacketTrailerHandler> handler);
|
||||
|
||||
private:
|
||||
mutable webrtc::Mutex mutex_;
|
||||
webrtc::TimestampAligner timestamp_aligner_;
|
||||
VideoResolution resolution_;
|
||||
std::shared_ptr<PacketTrailerHandler> packet_trailer_handler_;
|
||||
bool is_screencast_;
|
||||
};
|
||||
|
||||
public:
|
||||
VideoTrackSource(const VideoResolution& resolution, bool is_screencast);
|
||||
|
||||
VideoResolution video_resolution() const;
|
||||
|
||||
bool on_captured_frame(const std::unique_ptr<VideoFrame>& frame,
|
||||
const FrameMetadata& frame_metadata)
|
||||
const; // frames pushed from Rust (+interior mutability)
|
||||
|
||||
void set_packet_trailer_handler(
|
||||
std::shared_ptr<PacketTrailerHandler> handler) const;
|
||||
|
||||
webrtc::scoped_refptr<InternalSource> get() const;
|
||||
|
||||
private:
|
||||
webrtc::scoped_refptr<InternalSource> source_;
|
||||
};
|
||||
|
||||
std::shared_ptr<VideoTrackSource> new_video_track_source(
|
||||
const VideoResolution& resolution, bool is_screencast);
|
||||
|
||||
static std::shared_ptr<MediaStreamTrack> video_to_media(
|
||||
std::shared_ptr<VideoTrack> track) {
|
||||
return track;
|
||||
}
|
||||
|
||||
static std::shared_ptr<VideoTrack> media_to_video(
|
||||
std::shared_ptr<MediaStreamTrack> track) {
|
||||
return std::static_pointer_cast<VideoTrack>(track);
|
||||
}
|
||||
|
||||
static std::shared_ptr<VideoTrack> _shared_video_track() {
|
||||
return nullptr; // Ignore
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "api/media_stream_interface.h"
|
||||
#include "api/rtp_receiver_interface.h"
|
||||
#include "api/rtp_sender_interface.h"
|
||||
#include "livekit/helper.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "rtc_base/physical_socket_server.h"
|
||||
#include "rtc_base/ssl_adapter.h"
|
||||
#include "rtc_base/thread.h"
|
||||
#include "rust/cxx.h"
|
||||
|
||||
#ifdef WEBRTC_WIN
|
||||
#include "rtc_base/win32_socket_init.h"
|
||||
#endif
|
||||
|
||||
namespace livekit_ffi {
|
||||
class RtcRuntime;
|
||||
class LogSink;
|
||||
} // namespace livekit_ffi
|
||||
#include "webrtc-sys/src/webrtc.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
class MediaStreamTrack;
|
||||
class RtpReceiver;
|
||||
class RtpSender;
|
||||
|
||||
// Using a shared_ptr in RtcRuntime allows us to keep a strong reference to it
|
||||
// on resources that depend on it. (e.g: AudioTrack, VideoTrack).
|
||||
class RtcRuntime : public std::enable_shared_from_this<RtcRuntime> {
|
||||
public:
|
||||
[[nodiscard]] static std::shared_ptr<RtcRuntime> create() {
|
||||
return std::shared_ptr<RtcRuntime>(new RtcRuntime());
|
||||
}
|
||||
|
||||
RtcRuntime(const RtcRuntime&) = delete;
|
||||
RtcRuntime& operator=(const RtcRuntime&) = delete;
|
||||
~RtcRuntime();
|
||||
|
||||
webrtc::Thread* network_thread() const;
|
||||
webrtc::Thread* worker_thread() const;
|
||||
webrtc::Thread* signaling_thread() const;
|
||||
|
||||
std::shared_ptr<MediaStreamTrack> get_or_create_media_stream_track(
|
||||
webrtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track);
|
||||
|
||||
std::shared_ptr<AudioTrack> get_or_create_audio_track(
|
||||
webrtc::scoped_refptr<webrtc::AudioTrackInterface> track);
|
||||
|
||||
std::shared_ptr<VideoTrack> get_or_create_video_track(
|
||||
webrtc::scoped_refptr<webrtc::VideoTrackInterface> track);
|
||||
|
||||
private:
|
||||
RtcRuntime();
|
||||
|
||||
std::unique_ptr<webrtc::Thread> network_thread_;
|
||||
std::unique_ptr<webrtc::Thread> worker_thread_;
|
||||
std::unique_ptr<webrtc::Thread> signaling_thread_;
|
||||
|
||||
// Lists used to make sure we don't create multiple wrappers for one
|
||||
// underlying webrtc object. (e.g: webrtc::VideoTrackInterface should only
|
||||
// have one livekit_ffi::VideoTrack associated with it).
|
||||
// The only reason we to do that is to allow to add states inside our
|
||||
// wrappers (e.g: the sinks_ member inside AudioTrack)
|
||||
// DataChannel and the PeerConnectionFactory don't need to do this (There's no
|
||||
// way to retrieve them after creation)
|
||||
webrtc::Mutex mutex_;
|
||||
std::vector<std::weak_ptr<MediaStreamTrack>> media_stream_tracks_;
|
||||
// We don't have additonal state in RtpReceiver and RtpSender atm..
|
||||
// std::vector<std::weak_ptr<RtpReceiver>> rtp_receivers_;
|
||||
// std::vector<std::weak_ptr<RtpSender>> rtp_senders_;
|
||||
|
||||
#ifdef WEBRTC_WIN
|
||||
// webrtc::WinsockInitializer winsock_;
|
||||
// webrtc::PhysicalSocketServer ss_;
|
||||
// webrtc::AutoSocketServerThread main_thread_{&ss_};
|
||||
#endif
|
||||
};
|
||||
|
||||
class LogSink : public webrtc::LogSink {
|
||||
public:
|
||||
LogSink(rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc);
|
||||
~LogSink();
|
||||
|
||||
void OnLogMessage(const std::string& message,
|
||||
webrtc::LoggingSeverity severity) override;
|
||||
|
||||
void OnLogMessage(const std::string& message) override {}
|
||||
|
||||
private:
|
||||
rust::Fn<void(rust::String message, LoggingSeverity severity)> fnc_;
|
||||
};
|
||||
|
||||
std::unique_ptr<LogSink> new_log_sink(
|
||||
rust::Fn<void(rust::String, LoggingSeverity)> fnc);
|
||||
|
||||
rust::String create_random_uuid();
|
||||
|
||||
} // namespace livekit_ffi
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
/*
|
||||
* Copyright 2025 LiveKit, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "api/video/yuv_helper.h"
|
||||
#include "webrtc-sys/src/yuv_helper.rs.h"
|
||||
|
||||
namespace livekit_ffi {
|
||||
|
||||
#define THROW_ON_ERROR(ret) \
|
||||
if (ret != 0) { \
|
||||
throw std::runtime_error("libyuv error: " + std::to_string(ret)); \
|
||||
}
|
||||
|
||||
static void i420_to_argb(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_argb,
|
||||
int dst_stride_argb,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I420ToARGB(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_argb,
|
||||
dst_stride_argb, width, height));
|
||||
}
|
||||
|
||||
static void i420_to_bgra(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_bgra,
|
||||
int dst_stride_bgra,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I420ToBGRA(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_bgra,
|
||||
dst_stride_bgra, width, height));
|
||||
}
|
||||
|
||||
static void i420_to_abgr(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I420ToABGR(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_abgr,
|
||||
dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void i420_to_rgba(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_rgba,
|
||||
int dst_stride_rgba,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I420ToRGBA(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_rgba,
|
||||
dst_stride_rgba, width, height));
|
||||
}
|
||||
|
||||
static void argb_to_i420(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::ARGBToI420(src_argb, src_stride_argb, dst_y,
|
||||
dst_stride_y, dst_u, dst_stride_u, dst_v,
|
||||
dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void abgr_to_i420(const uint8_t* src_abgr,
|
||||
int src_stride_abgr,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::ABGRToI420(src_abgr, src_stride_abgr, dst_y,
|
||||
dst_stride_y, dst_u, dst_stride_u, dst_v,
|
||||
dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void argb_to_rgb24(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_rgb24,
|
||||
int dst_stride_rgb24,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::ARGBToRGB24(src_argb, src_stride_argb, dst_rgb24,
|
||||
dst_stride_rgb24, width, height));
|
||||
}
|
||||
|
||||
static void i420_to_nv12(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_y, dst_stride_y,
|
||||
dst_uv, dst_stride_uv, width, height));
|
||||
}
|
||||
|
||||
static void nv12_to_i420(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_uv,
|
||||
int src_stride_uv,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv,
|
||||
dst_y, dst_stride_y, dst_u, dst_stride_u,
|
||||
dst_v, dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void i420_to_nv12(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_y, dst_stride_y,
|
||||
dst_uv, dst_stride_uv, width, height));
|
||||
}
|
||||
|
||||
static void i444_to_i420(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I444ToI420(
|
||||
src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, dst_y,
|
||||
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void i422_to_i420(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I422ToI420(
|
||||
src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, dst_y,
|
||||
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void i010_to_i420(const uint16_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint16_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint16_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I010ToI420(
|
||||
src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v, dst_y,
|
||||
dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, width, height));
|
||||
}
|
||||
|
||||
static void nv12_to_argb(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_uv,
|
||||
int src_stride_uv,
|
||||
uint8_t* dst_argb,
|
||||
int dst_stride_argb,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::NV12ToARGB(src_y, src_stride_y, src_uv, src_stride_uv,
|
||||
dst_argb, dst_stride_argb, width, height));
|
||||
}
|
||||
|
||||
static void nv12_to_abgr(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_uv,
|
||||
int src_stride_uv,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::NV12ToABGR(src_y, src_stride_y, src_uv, src_stride_uv,
|
||||
dst_abgr, dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void i444_to_argb(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I444ToARGB(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_abgr,
|
||||
dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void i444_to_abgr(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I444ToABGR(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_abgr,
|
||||
dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void i422_to_argb(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_argb,
|
||||
int dst_stride_argb,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I422ToARGB(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_argb,
|
||||
dst_stride_argb, width, height));
|
||||
}
|
||||
|
||||
static void i422_to_abgr(const uint8_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint8_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint8_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I422ToABGR(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_abgr,
|
||||
dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void i010_to_argb(const uint16_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint16_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint16_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_argb,
|
||||
int dst_stride_argb,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I010ToARGB(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_argb,
|
||||
dst_stride_argb, width, height));
|
||||
}
|
||||
|
||||
static void i010_to_abgr(const uint16_t* src_y,
|
||||
int src_stride_y,
|
||||
const uint16_t* src_u,
|
||||
int src_stride_u,
|
||||
const uint16_t* src_v,
|
||||
int src_stride_v,
|
||||
uint8_t* dst_abgr,
|
||||
int dst_stride_abgr,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::I010ToABGR(src_y, src_stride_y, src_u, src_stride_u,
|
||||
src_v, src_stride_v, dst_abgr,
|
||||
dst_stride_abgr, width, height));
|
||||
}
|
||||
|
||||
static void abgr_to_nv12(const uint8_t* src_abgr,
|
||||
int src_stride_abgr,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::ABGRToNV12(src_abgr, src_stride_abgr, dst_y,
|
||||
dst_stride_y, dst_uv, dst_stride_uv, width,
|
||||
height));
|
||||
}
|
||||
|
||||
static void argb_to_nv12(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_uv,
|
||||
int dst_stride_uv,
|
||||
int width,
|
||||
int height) {
|
||||
THROW_ON_ERROR(webrtc::ARGBToNV12(src_argb, src_stride_argb, dst_y,
|
||||
dst_stride_y, dst_uv, dst_stride_uv, width,
|
||||
height));
|
||||
}
|
||||
|
||||
} // namespace livekit_ffi
|
||||
Reference in New Issue
Block a user