Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ All `RoomDelegate` callbacks and stream handler callbacks (e.g., `registerTextSt
| `SubscriptionThreadDispatcher` | Yes | Internal `std::mutex` protects registrations and active readers. Thread joins happen outside the lock. |
| `AudioStream` / `VideoStream` / `DataTrackStream` | Yes | Internal `std::mutex` + `condition_variable` coordinate the FFI producer thread and the consumer reader thread. |
| `AudioSource::captureFrame` | No | Not safe to call concurrently from multiple threads. |
| `PlatformAudio` / `PlatformAudioSource` | Yes | Thin `sendRequest` wrappers over immutable FFI handle state; destruction and move operations must be externally synchronized. |
| `VideoSource::captureFrame` | No | Not safe to call concurrently from multiple threads. |
| `LocalAudioTrack` / `LocalVideoTrack` | No | Thin `sendRequest` wrappers with no internal synchronization. |
| `LocalDataTrack::tryPush` | No | Thin `sendRequest` wrapper with no internal synchronization. |
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ add_library(livekit SHARED
src/logging.cpp
src/local_audio_track.cpp
src/local_data_track.cpp
src/platform_audio.cpp
src/remote_audio_track.cpp
src/remote_data_track.cpp
src/room.cpp
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,35 @@ If the E2EE keys do not match between participants:

Press Ctrl-C to exit the example.

## Platform Audio

For normal microphone publishing, use `PlatformAudio`. It uses WebRTC's platform
Audio Device Module for microphone capture and speaker playout, with built-in
echo cancellation, noise suppression, and automatic gain control. Use
`AudioSource` instead when you need to push raw PCM frames yourself, such as TTS,
file playback, synthesis, or custom processing.

```cpp
livekit::PlatformAudio platform_audio;

// Optional: choose devices by stable AudioDeviceInfo::id.
for (const auto& device : platform_audio.recordingDevices()) {
// device.name, device.id
}

livekit::PlatformAudioOptions audio_options;
audio_options.echo_cancellation = true;
audio_options.noise_suppression = true;
audio_options.auto_gain_control = true;

auto source = platform_audio.createAudioSource(audio_options);
auto track = livekit::LocalAudioTrack::createLocalAudioTrack("microphone", source);

livekit::TrackPublishOptions publish_options;
publish_options.source = livekit::TrackSource::SOURCE_MICROPHONE;
room->localParticipant()->publishTrack(track, publish_options);
```

### SimpleRpc
The SimpleRpc example demonstrates how to:
- Connect multiple participants to the same LiveKit room
Expand Down
3 changes: 2 additions & 1 deletion include/livekit/livekit.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "livekit/local_video_track.h"
#include "livekit/logging.h"
#include "livekit/participant.h"
#include "livekit/platform_audio.h"
#include "livekit/remote_participant.h"
#include "livekit/remote_track_publication.h"
#include "livekit/room.h"
Expand Down Expand Up @@ -67,4 +68,4 @@ LIVEKIT_API bool initialize(const LogLevel& level = LogLevel::Info, const LogSin
/// After shutdown, you may call initialize() again.
LIVEKIT_API void shutdown();

} // namespace livekit
} // namespace livekit
75 changes: 47 additions & 28 deletions include/livekit/local_audio_track.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,66 +31,85 @@ class OwnedTrack;
}

class AudioSource;
class PlatformAudioSource;

/// Represents a user-provided audio track sourced from the local device.
///
/// `LocalAudioTrack` is used to publish microphone audio (or any custom
/// audio source) to a LiveKit room. It wraps a platform-specific audio
/// source and exposes simple controls such as `mute()` and `unmute()`.
/// `LocalAudioTrack` is used to publish microphone audio or any custom audio
/// source to a LiveKit room. It wraps a platform-specific audio
/// source and exposes simple controls such as `mute()` and `unmute()`.
/// Muting a local audio track stops transmitting audio to the room, but
/// the underlying source may continue capturing depending on platform behavior.
///
/// Typical usage:
///
/// auto source = AudioSource::create(...);
/// auto track = LocalAudioTrack::createLocalAudioTrack("mic", source);
/// room->localParticipant()->publishTrack(track);
///
/// Muting a local audio track stops transmitting audio to the room, but
/// the underlying source may continue capturing depending on platform
/// behavior.
///
/// The track name provided during creation is visible to remote
/// participants and can be used for debugging or UI display.
/// @note Thread-safety: Not thread-safe. This is a thin FFI wrapper with no
/// internal synchronization.
class LIVEKIT_API LocalAudioTrack : public Track {
public:
/// Creates a new local audio track backed by the given `AudioSource`.
///
/// @param name Human-readable name for the track. This may appear to
/// remote participants and in analytics/debug logs.
/// @param source The audio source that produces PCM frames for this track.
/// @param source The audio source that produces PCM frames for this track.
/// The caller retains ownership and should use this source
/// directly for frame capture.
///
/// @return A shared pointer to the newly constructed `LocalAudioTrack`.
/// @throws std::invalid_argument If \p source is null.
/// @throws std::runtime_error If the FFI request fails.
static std::shared_ptr<LocalAudioTrack> createLocalAudioTrack(const std::string& name,
const std::shared_ptr<AudioSource>& source);

/// Creates a new local audio track backed by the given `PlatformAudioSource`.
///
/// @param name Human-readable name for the track. This may appear to
/// remote participants and in analytics/debug logs.
/// @param source The platform source that captures microphone audio
/// automatically through WebRTC's Audio Device Module.
///
/// @return A shared pointer to the newly constructed `LocalAudioTrack`.
/// @throws std::invalid_argument If \p source is null.
/// @throws std::runtime_error If the FFI request fails.
///
/// @note Thread-safety: Not thread-safe. This is a thin FFI wrapper with no
/// internal synchronization.
static std::shared_ptr<LocalAudioTrack> createLocalAudioTrack(const std::string& name,
const std::shared_ptr<PlatformAudioSource>& source);

/// Mutes the audio track.
///
/// A muted track stops sending audio to the room, but the track remains
/// published and can be unmuted later without renegotiation.
///
/// @throws std::runtime_error If the FFI request fails.
void mute();

/// Unmutes the audio track and resumes sending audio to the room.
/// Unmute the audio track.
///
/// Resumes sending audio to the room.
///
/// @throws std::runtime_error If the FFI request fails.
void unmute();

/// Returns a human-readable string representation of the track,
/// including its SID and name. Useful for debugging and logging.
/// Return a human-readable string representation of the track.
///
/// @return String containing the track SID and name.
std::string toString() const;

/// @return String containing the track SID and name.
/// @deprecated Use toString() instead.
// NOLINTBEGIN(readability-identifier-naming)
[[deprecated("LocalAudioTrack::to_string is deprecated; use LocalAudioTrack::toString instead")]]
std::string to_string() const;
// NOLINTEND(readability-identifier-naming)
std::string to_string() const; // NOLINT(readability-identifier-naming)

/// Returns the publication that owns this track, or nullptr if the track is
/// not published.
/// Return the publication that owns this track.
///
/// @return Publication that owns this track, or nullptr if the track is not
/// published.
std::shared_ptr<LocalTrackPublication> publication() const noexcept { return local_publication_; }

/// Sets the publication that owns this track.
/// Note: std::move on a const& silently falls back to a copy, so we assign
/// directly. Changing the virtual signature to take by value would enable
/// a true move but is an API-breaking change hence left for a future revision.
/// Set the publication that owns this track.
///
/// @param publication Publication that owns this track, or nullptr to clear
/// the association.
void setPublication(const std::shared_ptr<LocalTrackPublication>& publication) noexcept override {
local_publication_ = publication;
}
Expand Down
Loading
Loading