Skip to content

Commit a207bc4

Browse files
remove the debug logs
1 parent b240785 commit a207bc4

File tree

8 files changed

+108
-25
lines changed

8 files changed

+108
-25
lines changed

examples/simple_room/main.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <csignal>
44
#include <cstdlib>
55
#include <iostream>
6+
#include <random>
67
#include <string>
78
#include <thread>
89
#include <vector>
@@ -28,7 +29,7 @@ void print_usage(const char *prog) {
2829
<< " LIVEKIT_URL, LIVEKIT_TOKEN\n";
2930
}
3031

31-
void handle_sigint(int) { g_running = false; }
32+
void handle_sigint(int) { g_running.store(false); }
3233

3334
bool parse_args(int argc, char *argv[], std::string &url, std::string &token) {
3435
// 1) --help
@@ -118,6 +119,47 @@ class SimpleRoomDelegate : public livekit::RoomDelegate {
118119
}
119120
};
120121

122+
// Test utils to run a capture loop to publish noisy audio frames to the room
123+
void runNoiseCaptureLoop(const std::shared_ptr<AudioSource> &source) {
124+
const int sample_rate = source->sample_rate();
125+
const int num_channels = source->num_channels();
126+
const int frame_ms = 10;
127+
const int samples_per_channel = sample_rate * frame_ms / 1000;
128+
129+
std::mt19937 rng(std::random_device{}());
130+
std::uniform_int_distribution<int16_t> noise_dist(-5000, 5000);
131+
using Clock = std::chrono::steady_clock;
132+
auto next_deadline = Clock::now();
133+
while (g_running.load(std::memory_order_relaxed)) {
134+
AudioFrame frame =
135+
AudioFrame::create(sample_rate, num_channels, samples_per_channel);
136+
const std::size_t total_samples =
137+
static_cast<std::size_t>(num_channels) *
138+
static_cast<std::size_t>(samples_per_channel);
139+
for (std::size_t i = 0; i < total_samples; ++i) {
140+
frame.data()[i] = noise_dist(rng);
141+
}
142+
try {
143+
source->captureFrame(frame);
144+
} catch (const std::exception &e) {
145+
// If something goes wrong, log and break out
146+
std::cerr << "Error in captureFrame: " << e.what() << std::endl;
147+
break;
148+
}
149+
150+
// Pace the loop to roughly real-time
151+
next_deadline += std::chrono::milliseconds(frame_ms);
152+
std::this_thread::sleep_until(next_deadline);
153+
}
154+
155+
// Optionally clear queued audio on exit
156+
try {
157+
source->clearQueue();
158+
} catch (...) {
159+
// ignore errors on shutdown
160+
std::cout << "Error in clearQueue" << std::endl;
161+
}
162+
}
121163
} // namespace
122164

123165
int main(int argc, char *argv[]) {
@@ -194,12 +236,20 @@ int main(int argc, char *argv[]) {
194236
std::cerr << "Failed to publish track: " << e.what() << std::endl;
195237
}
196238

239+
// TODO, if we have pre-buffering feature, we might consider starting the
240+
// thread right after creating the source.
241+
std::thread audioThread(runNoiseCaptureLoop, audioSource);
197242
// Keep the app alive until Ctrl-C so we continue receiving events,
198243
// similar to asyncio.run(main()) keeping the loop running.
199244
while (g_running.load()) {
200245
std::this_thread::sleep_for(std::chrono::milliseconds(100));
201246
}
202247

248+
// Shutdown the audio thread.
249+
if (audioThread.joinable()) {
250+
audioThread.join();
251+
}
252+
203253
FfiClient::instance().shutdown();
204254
std::cout << "Exiting.\n";
205255
return 0;

include/livekit/audio_source.h

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,36 @@ class AudioSource {
7272
void clearQueue();
7373

7474
/**
75-
* Push an AudioFrame into the audio source.
75+
* Push an AudioFrame into the audio source and BLOCK until the FFI callback
76+
* confirms that the native side has finished processing (consuming) the
77+
* frame. Safe usage: The frame's internal buffer must remain valid only until
78+
* this function returns. Because this call blocks until the corresponding FFI
79+
* callback arrives, the caller may safely destroy or reuse the frame
80+
* afterward.
81+
* @param frame The audio frame to send. No-op if the frame contains
82+
* zero samples.
83+
* @param timeout_ms Maximum time to wait for the FFI callback.
84+
* - If timeout_ms > 0: block up to this duration.
85+
* A timeout will cause std::runtime_error.
86+
* - If timeout_ms == 0: wait indefinitely until the
87+
* callback arrives (recommended for production unless the caller needs
88+
* explicit timeout control).
7689
*
77-
* It sends a capture_audio_frame FFI request and may throw on error
78-
* (depending on what the FFI response exposes).
90+
* Notes:
91+
* - This is a blocking call.
92+
* - timeout_ms == 0 (infinite wait) is the safest mode because it
93+
* guarantees the callback completes before the function returns, which in
94+
* turn guarantees that the audio buffer lifetime is fully protected. The
95+
* caller does not need to manage or extend the frame lifetime manually.
7996
*
80-
* If the frame has zero samples, this method is a no-op.
97+
* - May throw std::runtime_error if:
98+
* • the FFI reports an error
8199
*
82-
* @throws std::runtime_error on FFI-reported error (if available).
100+
* - The underlying FFI request *must* eventually produce a callback for
101+
* each frame. If the FFI layer is misbehaving or the event loop is stalled,
102+
* a timeout may occur in bounded-wait mode.
83103
*/
84-
void captureFrame(const AudioFrame &frame);
104+
void captureFrame(const AudioFrame &frame, int timeout_ms = 20);
85105

86106
/**
87107
* Block until the currently queued audio has (roughly) played out.

src/audio_frame.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*
2+
* Copyright 2025 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an “AS IS” BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
117
#include "livekit/audio_frame.h"
218

319
#include <cstddef>

src/audio_source.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ void AudioSource::clearQueue() {
9393
resetQueueTracking();
9494
}
9595

96-
void AudioSource::captureFrame(const AudioFrame &frame) {
96+
void AudioSource::captureFrame(const AudioFrame &frame, int timeout_ms) {
97+
using namespace std::chrono_literals;
9798
if (!handle_) {
9899
return;
99100
}
@@ -105,10 +106,8 @@ void AudioSource::captureFrame(const AudioFrame &frame) {
105106
// Queue tracking, same logic as before
106107
double now = now_seconds();
107108
double elapsed = (last_capture_ == 0.0) ? 0.0 : (now - last_capture_);
108-
109109
double frame_duration = static_cast<double>(frame.samples_per_channel()) /
110110
static_cast<double>(sample_rate_);
111-
112111
q_size_ += frame_duration - elapsed;
113112
if (q_size_ < 0.0) {
114113
q_size_ = 0.0; // clamp
@@ -117,12 +116,21 @@ void AudioSource::captureFrame(const AudioFrame &frame) {
117116

118117
// Build AudioFrameBufferInfo from the wrapper
119118
proto::AudioFrameBufferInfo buf = frame.toProto();
120-
121119
// Use async FFI API and block until the callback completes
122120
auto fut = FfiClient::instance().captureAudioFrameAsync(handle_.get(), buf);
123-
121+
if (timeout_ms == 0) {
122+
fut.get(); // may throw std::runtime_error from async layer
123+
return;
124+
}
124125
// This will throw std::runtime_error if the callback reported an error
125-
fut.get();
126+
auto status = fut.wait_for(std::chrono::milliseconds(timeout_ms));
127+
if (status == std::future_status::ready ||
128+
status == std::future_status::deferred) {
129+
fut.get();
130+
} else { // std::future_status::timeout
131+
std::cerr << "captureAudioFrameAsync timed out after " << timeout_ms
132+
<< " ms\n";
133+
}
126134
}
127135

128136
void AudioSource::waitForPlayout() const {

src/ffi_client.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ FfiClient::sendRequest(const proto::FfiRequest &request) const {
5757
FfiHandleId handle =
5858
livekit_ffi_request(reinterpret_cast<const uint8_t *>(bytes.data()),
5959
bytes.size(), &resp_ptr, &resp_len);
60-
std::cout << "receive a handle " << handle << std::endl;
61-
6260
if (handle == INVALID_HANDLE) {
6361
throw std::runtime_error(
6462
"failed to send request, received an invalid handle");

src/local_audio_track.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ LocalAudioTrack::LocalAudioTrack(FfiHandle handle,
2929
: Track(std::move(handle), track.info().sid(), track.info().name(),
3030
fromProto(track.info().kind()),
3131
fromProto(track.info().stream_state()), track.info().muted(),
32-
false) {
33-
std::cout << "LocalAudioTrack handle is " << ffi_handle_id() << std::endl;
34-
}
32+
false) {}
3533

3634
std::shared_ptr<LocalAudioTrack> LocalAudioTrack::createLocalAudioTrack(
3735
const std::string &name, const std::shared_ptr<AudioSource> &source) {
@@ -43,8 +41,6 @@ std::shared_ptr<LocalAudioTrack> LocalAudioTrack::createLocalAudioTrack(
4341
proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
4442
const proto::OwnedTrack &owned = resp.create_audio_track().track();
4543
FfiHandle handle(static_cast<uintptr_t>(owned.handle().id()));
46-
std::cout << "createLocalAudioTrack handle is " << owned.handle().id()
47-
<< std::endl;
4844
return std::make_shared<LocalAudioTrack>(std::move(handle), owned);
4945
}
5046

src/local_participant.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -204,20 +204,16 @@ LocalParticipant::publishTrack(const std::shared_ptr<Track> &track,
204204
}
205205

206206
auto participant_handle = ffiHandleId();
207-
std::cout << "participant_handle is " << participant_handle << std::endl;
208207
if (participant_handle == 0) {
209208
throw std::runtime_error(
210209
"LocalParticipant::publishTrack: invalid participant FFI handle");
211210
}
212211

213212
auto track_handle = track->ffi_handle_id();
214-
std::cout << "track_handle is " << track_handle << std::endl;
215-
216213
if (track_handle == 0) {
217214
throw std::runtime_error(
218215
"LocalParticipant::publishTrack: invalid track FFI handle");
219216
}
220-
std::cout << "calling publishTrackAsync" << std::endl;
221217
auto fut = FfiClient::instance().publishTrackAsync(
222218
static_cast<std::uint64_t>(participant_handle),
223219
static_cast<std::uint64_t>(track_handle), options);

src/room.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ bool Room::Connect(const std::string &url, const std::string &token) {
8686
local_participant_ = std::make_unique<LocalParticipant>(
8787
std::move(participant_handle), pinfo.sid(), pinfo.name(),
8888
pinfo.identity(), pinfo.metadata(), std::move(attrs), kind, reason);
89-
std::cout << "creating local participant " << std::endl;
9089
}
9190
// Setup remote particpants
9291
{

0 commit comments

Comments
 (0)