Skip to content

Commit 51d535d

Browse files
result.h file for floating up specific errors provided by the FFI
1 parent c138e66 commit 51d535d

17 files changed

Lines changed: 589 additions & 166 deletions

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,9 @@ add_library(livekit SHARED
324324
src/audio_processing_module.cpp
325325
src/audio_source.cpp
326326
src/audio_stream.cpp
327+
src/data_frame.cpp
327328
src/data_stream.cpp
329+
src/data_track_error.cpp
328330
src/data_track_subscription.cpp
329331
src/e2ee.cpp
330332
src/ffi_handle.cpp

examples/hello_livekit/sender.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,17 @@ int main(int argc, char *argv[]) {
9595
std::shared_ptr<LocalVideoTrack> video_track = lp->publishVideoTrack(
9696
kVideoTrackName, video_source, TrackSource::SOURCE_CAMERA);
9797

98-
std::shared_ptr<LocalDataTrack> data_track =
99-
lp->publishDataTrack(kDataTrackName);
98+
auto publish_result = lp->publishDataTrack(kDataTrackName);
99+
if (!publish_result) {
100+
const auto &error = publish_result.error();
101+
LK_LOG_ERROR("Failed to publish data track: code={} retryable={} message={}",
102+
static_cast<std::uint32_t>(error.code), error.retryable,
103+
error.message);
104+
room.reset();
105+
livekit::shutdown();
106+
return 1;
107+
}
108+
std::shared_ptr<LocalDataTrack> data_track = publish_result.value();
100109

101110
const auto t0 = std::chrono::steady_clock::now();
102111
std::uint64_t count = 0;
@@ -115,7 +124,14 @@ int main(int argc, char *argv[]) {
115124
std::ostringstream oss;
116125
oss << std::fixed << std::setprecision(2) << ms << " ms, count: " << count;
117126
const std::string msg = oss.str();
118-
data_track->tryPush(std::vector<std::uint8_t>(msg.begin(), msg.end()));
127+
auto push_result =
128+
data_track->tryPush(std::vector<std::uint8_t>(msg.begin(), msg.end()));
129+
if (!push_result) {
130+
const auto &error = push_result.error();
131+
LK_LOG_WARN("Failed to push data frame: code={} retryable={} message={}",
132+
static_cast<std::uint32_t>(error.code), error.retryable,
133+
error.message);
134+
}
119135

120136
++count;
121137
std::this_thread::sleep_for(std::chrono::milliseconds(100));

examples/simple_status/producer.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,18 @@ int main(int argc, char *argv[]) {
9494
room->room_info().name);
9595

9696
std::shared_ptr<LocalDataTrack> data_track;
97-
try {
98-
data_track = lp->publishDataTrack(kTrackName);
99-
} catch (const std::exception &e) {
100-
LK_LOG_ERROR("Failed to publish data track: {}", e.what());
97+
auto publish_result = lp->publishDataTrack(kTrackName);
98+
if (!publish_result) {
99+
const auto &error = publish_result.error();
100+
LK_LOG_ERROR("Failed to publish data track: code={} retryable={} message={}",
101+
static_cast<std::uint32_t>(error.code), error.retryable,
102+
error.message);
101103
room->setDelegate(nullptr);
102104
room.reset();
103105
livekit::shutdown();
104106
return 1;
105107
}
108+
data_track = publish_result.value();
106109

107110
LK_LOG_INFO("published data track '{}'", kTrackName);
108111

@@ -123,8 +126,12 @@ int main(int argc, char *argv[]) {
123126
" count: " + std::to_string(count);
124127

125128
std::vector<std::uint8_t> payload(text.begin(), text.end());
126-
if (!data_track->tryPush(payload)) {
127-
LK_LOG_WARN("Failed to push data frame");
129+
auto push_result = data_track->tryPush(payload);
130+
if (!push_result) {
131+
const auto &error = push_result.error();
132+
LK_LOG_WARN("Failed to push data frame: code={} retryable={} message={}",
133+
static_cast<std::uint32_t>(error.code), error.retryable,
134+
error.message);
128135
}
129136

130137
LK_LOG_DEBUG("sent: {}", text);

include/livekit/data_track_error.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2026 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+
17+
#ifndef LIVEKIT_DATA_TRACK_ERROR_H
18+
#define LIVEKIT_DATA_TRACK_ERROR_H
19+
20+
#include <cstdint>
21+
#include <string>
22+
23+
namespace livekit {
24+
25+
namespace proto {
26+
class DataTrackError;
27+
}
28+
29+
/// Stable error codes for data-track operations.
30+
enum class DataTrackErrorCode : std::uint32_t {
31+
UNKNOWN = 0,
32+
INVALID_HANDLE = 1,
33+
DUPLICATE_TRACK_NAME = 2,
34+
TRACK_UNPUBLISHED = 3,
35+
BUFFER_FULL = 4,
36+
SUBSCRIPTION_CLOSED = 5,
37+
CANCELLED = 6,
38+
PROTOCOL_ERROR = 7,
39+
INTERNAL = 8,
40+
};
41+
42+
/// Structured failure returned by non-throwing data-track APIs.
43+
struct DataTrackError {
44+
/// Machine-readable error code.
45+
DataTrackErrorCode code{DataTrackErrorCode::UNKNOWN};
46+
/// Human-readable description from the backend or SDK.
47+
std::string message;
48+
/// Whether retrying the operation may succeed.
49+
bool retryable{false};
50+
51+
/// Convert the FFI proto representation into the public SDK type.
52+
static DataTrackError fromProto(const proto::DataTrackError &error);
53+
};
54+
55+
} // namespace livekit
56+
57+
#endif // LIVEKIT_DATA_TRACK_ERROR_H

include/livekit/data_track_subscription.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ class FfiEvent;
4343
*
4444
* Typical usage:
4545
*
46-
* auto sub = remoteDataTrack->subscribe();
47-
* DataFrame frame;
48-
* while (sub->read(frame)) {
49-
* // process frame.payload
46+
* auto sub_result = remoteDataTrack->subscribe();
47+
* if (sub_result) {
48+
* auto sub = sub_result.value();
49+
* DataFrame frame;
50+
* while (sub->read(frame)) {
51+
* // process frame.payload
52+
* }
5053
* }
5154
*/
5255
class DataTrackSubscription {

include/livekit/local_data_track.h

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#pragma once
1818

1919
#include "livekit/data_frame.h"
20+
#include "livekit/data_track_error.h"
2021
#include "livekit/data_track_info.h"
2122
#include "livekit/ffi_handle.h"
23+
#include "livekit/result.h"
2224

2325
#include <cstddef>
2426
#include <memory>
@@ -44,11 +46,14 @@ class OwnedLocalDataTrack;
4446
* Typical usage:
4547
*
4648
* auto lp = room->localParticipant();
47-
* auto dt = lp->publishDataTrack("sensor-data");
48-
* DataFrame frame;
49-
* frame.payload = {0x01, 0x02, 0x03};
50-
* dt->tryPush(frame);
51-
* dt->unpublishDataTrack();
49+
* auto result = lp->publishDataTrack("sensor-data");
50+
* if (result) {
51+
* auto dt = result.value();
52+
* DataFrame frame;
53+
* frame.payload = {0x01, 0x02, 0x03};
54+
* (void)dt->tryPush(frame);
55+
* dt->unpublishDataTrack();
56+
* }
5257
*/
5358
class LocalDataTrack {
5459
public:
@@ -63,29 +68,32 @@ class LocalDataTrack {
6368
/**
6469
* Try to push a frame to all subscribers of this track.
6570
*
66-
* @return true on success, false if the push failed (e.g. back-pressure
67-
* or the track has been unpublished).
71+
* @return success on delivery acceptance, or a typed error describing why
72+
* the frame could not be queued.
6873
*/
69-
bool tryPush(const DataFrame &frame);
74+
Result<void, DataTrackError> tryPush(const DataFrame &frame);
7075

7176
/**
7277
* Try to push a frame to all subscribers of this track.
7378
*
74-
* @return true on success, false if the push failed (e.g. back-pressure
75-
* or the track has been unpublished).
79+
* @return success on delivery acceptance, or a typed error describing why
80+
* the frame could not be queued.
7681
*/
77-
bool tryPush(const std::vector<std::uint8_t> &payload,
78-
std::optional<std::uint64_t> user_timestamp = std::nullopt);
79-
bool tryPush(std::vector<std::uint8_t> &&payload,
80-
std::optional<std::uint64_t> user_timestamp = std::nullopt);
82+
Result<void, DataTrackError>
83+
tryPush(const std::vector<std::uint8_t> &payload,
84+
std::optional<std::uint64_t> user_timestamp = std::nullopt);
85+
Result<void, DataTrackError>
86+
tryPush(std::vector<std::uint8_t> &&payload,
87+
std::optional<std::uint64_t> user_timestamp = std::nullopt);
8188
/**
8289
* Try to push a frame to all subscribers of this track.
8390
*
84-
* @return true on success, false if the push failed (e.g. back-pressure
85-
* or the track has been unpublished).
91+
* @return success on delivery acceptance, or a typed error describing why
92+
* the frame could not be queued.
8693
*/
87-
bool tryPush(const std::uint8_t *data, std::size_t size,
88-
std::optional<std::uint64_t> user_timestamp = std::nullopt);
94+
Result<void, DataTrackError>
95+
tryPush(const std::uint8_t *data, std::size_t size,
96+
std::optional<std::uint64_t> user_timestamp = std::nullopt);
8997

9098
/// Whether the track is still published in the room.
9199
bool isPublished() const;

include/livekit/local_participant.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,11 @@ class LocalParticipant : public Participant {
181181
* LocalParticipant::unpublishDataTrack().
182182
*
183183
* @param name Unique track name visible to other participants.
184-
* @return Shared pointer to the published data track.
185-
* @throws std::runtime_error on FFI or publish failure.
184+
* @return The published track on success, or a typed error describing why
185+
* publication failed.
186186
*/
187-
std::shared_ptr<LocalDataTrack> publishDataTrack(const std::string &name);
187+
Result<std::shared_ptr<LocalDataTrack>, DataTrackError>
188+
publishDataTrack(const std::string &name);
188189

189190
/**
190191
* Unpublish a data track from the room.

include/livekit/remote_data_track.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818

1919
#include "livekit/data_track_info.h"
2020
#include "livekit/data_track_subscription.h"
21+
#include "livekit/data_track_error.h"
2122
#include "livekit/ffi_handle.h"
23+
#include "livekit/result.h"
2224

2325
#include <memory>
2426
#include <string>
@@ -39,10 +41,13 @@ class OwnedRemoteDataTrack;
3941
* Typical usage:
4042
*
4143
* // In RoomDelegate::onDataTrackPublished callback:
42-
* auto sub = remoteDataTrack->subscribe();
43-
* DataFrame frame;
44-
* while (sub->read(frame)) {
45-
* // process frame
44+
* auto sub_result = remoteDataTrack->subscribe();
45+
* if (sub_result) {
46+
* auto sub = sub_result.value();
47+
* DataFrame frame;
48+
* while (sub->read(frame)) {
49+
* // process frame
50+
* }
4651
* }
4752
*/
4853
class RemoteDataTrack {
@@ -68,10 +73,8 @@ class RemoteDataTrack {
6873
*
6974
* Returns a DataTrackSubscription that delivers frames via blocking
7075
* read(). Destroy the subscription to unsubscribe.
71-
*
72-
* @throws std::runtime_error if the FFI subscribe call fails.
7376
*/
74-
std::shared_ptr<DataTrackSubscription>
77+
Result<std::shared_ptr<DataTrackSubscription>, DataTrackError>
7578
subscribe(const DataTrackSubscription::Options &options = {});
7679

7780
private:

0 commit comments

Comments
 (0)