Skip to content
Merged
5 changes: 1 addition & 4 deletions include/livekit/data_track_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_DATA_TRACK_ERROR_H
#define LIVEKIT_DATA_TRACK_ERROR_H
#pragma once

#include <cstdint>
#include <string>
Expand Down Expand Up @@ -83,5 +82,3 @@ struct SubscribeDataTrackError {
};

} // namespace livekit

#endif // LIVEKIT_DATA_TRACK_ERROR_H
4 changes: 2 additions & 2 deletions include/livekit/local_audio_track.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class LIVEKIT_API LocalAudioTrack : public Track {
/// 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 left for a future revision.
/// a true move but is an API-breaking change hence left for a future revision.
void setPublication(const std::shared_ptr<LocalTrackPublication>& publication) noexcept override {
local_publication_ = publication;
}
Expand All @@ -99,4 +99,4 @@ class LIVEKIT_API LocalAudioTrack : public Track {
std::shared_ptr<LocalTrackPublication> local_publication_;
};

} // namespace livekit
} // namespace livekit
5 changes: 1 addition & 4 deletions include/livekit/result.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_RESULT_H
#define LIVEKIT_RESULT_H
#pragma once

#include <cassert>
#include <optional>
Expand Down Expand Up @@ -187,5 +186,3 @@ class [[nodiscard]] Result<void, E> {
};

} // namespace livekit

#endif // LIVEKIT_RESULT_H
8 changes: 4 additions & 4 deletions include/livekit/room.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_ROOM_H
#define LIVEKIT_ROOM_H
#pragma once

#include <cstdint>
#include <memory>
Expand Down Expand Up @@ -173,6 +172,9 @@ class LIVEKIT_API Room {
/// Returns a snapshot of all current remote participants.
std::vector<std::shared_ptr<RemoteParticipant>> remoteParticipants() const;

/// Returns the current connection state of the room.
ConnectionState connectionState() const;

/* Register a handler for incoming text streams on a specific topic.
*
* When a remote participant opens a text stream with the given topic,
Expand Down Expand Up @@ -324,5 +326,3 @@ class LIVEKIT_API Room {
void OnEvent(const proto::FfiEvent& event);
};
} // namespace livekit

#endif /* LIVEKIT_ROOM_H */
5 changes: 1 addition & 4 deletions include/livekit/subscription_thread_dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_SUBSCRIPTION_THREAD_DISPATCHER_H
#define LIVEKIT_SUBSCRIPTION_THREAD_DISPATCHER_H
#pragma once

#include <cstdint>
#include <functional>
Expand Down Expand Up @@ -459,5 +458,3 @@ class LIVEKIT_API SubscriptionThreadDispatcher {
};

} // namespace livekit

#endif /* LIVEKIT_SUBSCRIPTION_THREAD_DISPATCHER_H */
8 changes: 4 additions & 4 deletions include/livekit/video_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ namespace proto {
class FfiEvent;
}

// Represents a pull-based stream of decoded PCM audio frames coming from
// a remote (or local) LiveKit track. Similar to VideoStream, but for audio.
// Represents a pull-based stream of decoded video frames coming from
// a remote (or local) LiveKit track. Similar to AudioStream, but for video.
//
// Typical usage:
//
// VideoStream::Options opts;
// auto stream = VideoStream::fromTrack(remoteVideoTrack, opts);
//
// AudioFrameEvent ev;
// VideoFrameEvent ev;
// while (stream->read(ev)) {
// // ev.frame contains interleaved int16 PCM samples
// // ev.frame contains the decoded video buffer
// }
//
// stream->close(); // optional, called automatically in destructor
Expand Down
5 changes: 1 addition & 4 deletions src/ffi_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_FFI_CLIENT_H
#define LIVEKIT_FFI_CLIENT_H
#pragma once

#include <atomic>
#include <cstdint>
Expand Down Expand Up @@ -196,5 +195,3 @@ class LIVEKIT_INTERNAL_API FfiClient {
std::atomic<bool> initialized_{false};
};
} // namespace livekit

#endif /* LIVEKIT_FFI_CLIENT_H */
5 changes: 1 addition & 4 deletions src/lk_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
* limitations under the License.
*/

#ifndef LIVEKIT_LK_LOG_H
#define LIVEKIT_LK_LOG_H
#pragma once

#include <spdlog/spdlog.h>

Expand Down Expand Up @@ -51,5 +50,3 @@ LIVEKIT_INTERNAL_API void shutdownLogger();
#define LK_LOG_WARN(...) SPDLOG_LOGGER_WARN(livekit::detail::getLogger(), __VA_ARGS__)
#define LK_LOG_ERROR(...) SPDLOG_LOGGER_ERROR(livekit::detail::getLogger(), __VA_ARGS__)
#define LK_LOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(livekit::detail::getLogger(), __VA_ARGS__)

#endif /* LIVEKIT_LK_LOG_H */
5 changes: 5 additions & 0 deletions src/room.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ std::vector<std::shared_ptr<RemoteParticipant>> Room::remoteParticipants() const
return out;
}

ConnectionState Room::connectionState() const {
const std::scoped_lock<std::mutex> g(lock_);
return connection_state_;
}

E2EEManager* Room::e2eeManager() const {
const std::scoped_lock<std::mutex> g(lock_);
return e2ee_manager_.get();
Expand Down
211 changes: 211 additions & 0 deletions src/tests/unit/test_result.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*
* Copyright 2026 LiveKit
*
* 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.
*/

/// @file test_result.cpp
/// @brief Unit tests for the Result<T, E> and Result<void, E> types.
///
/// Covers the invariants documented in result.h:
/// - ok() / has_error() / bool conversion correctness
/// - value() and error() accessor semantics for lvalue, rvalue, and const
/// overloads
/// - Move construction and forwarding behaviour
/// - void specialization

#include <gtest/gtest.h>
#include <livekit/result.h>

#include <memory>
#include <string>
#include <utility>

namespace livekit {

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

struct SimpleError {
int code{0};
std::string message;
};

// ---------------------------------------------------------------------------
// Result<T, E> — success path
// ---------------------------------------------------------------------------

TEST(ResultTest, SuccessOkIsTrue) {
auto r = Result<int, SimpleError>::success(42);
EXPECT_TRUE(r.ok());
}

TEST(ResultTest, SuccessHasErrorIsFalse) {
auto r = Result<int, SimpleError>::success(42);
EXPECT_FALSE(r.has_error());
}

TEST(ResultTest, SuccessBoolConversionIsTrue) {
auto r = Result<int, SimpleError>::success(42);
EXPECT_TRUE(static_cast<bool>(r));
}

TEST(ResultTest, SuccessValueMatchesInput) {
auto r = Result<int, SimpleError>::success(99);
EXPECT_EQ(r.value(), 99);
}

TEST(ResultTest, SuccessConstValueMatchesInput) {
const auto r = Result<int, SimpleError>::success(7);
EXPECT_EQ(r.value(), 7);
}

TEST(ResultTest, SuccessValueCanBeMutated) {
auto r = Result<int, SimpleError>::success(1);
r.value() = 100;
EXPECT_EQ(r.value(), 100);
}

TEST(ResultTest, SuccessStringValue) {
auto r = Result<std::string, SimpleError>::success("hello");
EXPECT_EQ(r.value(), "hello");
}

TEST(ResultTest, SuccessMoveValueTransfersOwnership) {
auto r = Result<std::unique_ptr<int>, SimpleError>::success(std::make_unique<int>(55));
auto ptr = std::move(r).value();
ASSERT_NE(ptr, nullptr);
EXPECT_EQ(*ptr, 55);
}

// ---------------------------------------------------------------------------
// Result<T, E> — failure path
// ---------------------------------------------------------------------------

TEST(ResultTest, FailureOkIsFalse) {
auto r = Result<int, SimpleError>::failure(SimpleError{1, "oops"});
EXPECT_FALSE(r.ok());
}

TEST(ResultTest, FailureHasErrorIsTrue) {
auto r = Result<int, SimpleError>::failure(SimpleError{1, "oops"});
EXPECT_TRUE(r.has_error());
}

TEST(ResultTest, FailureBoolConversionIsFalse) {
auto r = Result<int, SimpleError>::failure(SimpleError{1, "oops"});
EXPECT_FALSE(static_cast<bool>(r));
}

TEST(ResultTest, FailureErrorCodeMatchesInput) {
auto r = Result<int, SimpleError>::failure(SimpleError{42, "bad"});
EXPECT_EQ(r.error().code, 42);
EXPECT_EQ(r.error().message, "bad");
}

TEST(ResultTest, FailureConstErrorMatchesInput) {
const auto r = Result<int, SimpleError>::failure(SimpleError{3, "err"});
EXPECT_EQ(r.error().code, 3);
}

TEST(ResultTest, FailureMoveErrorTransfersOwnership) {
auto r = Result<int, std::unique_ptr<SimpleError>>::failure(std::make_unique<SimpleError>(SimpleError{9, "moved"}));
auto err = std::move(r).error();
ASSERT_NE(err, nullptr);
EXPECT_EQ(err->code, 9);
}

TEST(ResultTest, FailureStringError) {
auto r = Result<int, std::string>::failure("something went wrong");
EXPECT_EQ(r.error(), "something went wrong");
}

// ---------------------------------------------------------------------------
// Result<void, E> — success path
// ---------------------------------------------------------------------------

TEST(ResultVoidTest, SuccessOkIsTrue) {
auto r = Result<void, SimpleError>::success();
EXPECT_TRUE(r.ok());
}

TEST(ResultVoidTest, SuccessHasErrorIsFalse) {
auto r = Result<void, SimpleError>::success();
EXPECT_FALSE(r.has_error());
}

TEST(ResultVoidTest, SuccessBoolConversionIsTrue) {
auto r = Result<void, SimpleError>::success();
EXPECT_TRUE(static_cast<bool>(r));
}

TEST(ResultVoidTest, SuccessValueIsCallable) {
auto r = Result<void, SimpleError>::success();
EXPECT_NO_THROW(r.value());
}

// ---------------------------------------------------------------------------
// Result<void, E> — failure path
// ---------------------------------------------------------------------------

TEST(ResultVoidTest, FailureOkIsFalse) {
auto r = Result<void, SimpleError>::failure(SimpleError{5, "void fail"});
EXPECT_FALSE(r.ok());
}

TEST(ResultVoidTest, FailureHasErrorIsTrue) {
auto r = Result<void, SimpleError>::failure(SimpleError{5, "void fail"});
EXPECT_TRUE(r.has_error());
}

TEST(ResultVoidTest, FailureBoolConversionIsFalse) {
auto r = Result<void, SimpleError>::failure(SimpleError{5, "void fail"});
EXPECT_FALSE(static_cast<bool>(r));
}

TEST(ResultVoidTest, FailureErrorMatchesInput) {
auto r = Result<void, SimpleError>::failure(SimpleError{7, "nope"});
EXPECT_EQ(r.error().code, 7);
EXPECT_EQ(r.error().message, "nope");
}

TEST(ResultVoidTest, FailureMoveError) {
auto r = Result<void, std::string>::failure("void error");
auto msg = std::move(r).error();
EXPECT_EQ(msg, "void error");
}

// ---------------------------------------------------------------------------
// if-result idiom
// ---------------------------------------------------------------------------

TEST(ResultTest, IfResultIdiomSuccessEntersBranch) {
auto r = Result<int, SimpleError>::success(1);
bool entered = false;
if (r) {
entered = true;
}
EXPECT_TRUE(entered);
}

TEST(ResultTest, IfResultIdiomFailureSkipsBranch) {
auto r = Result<int, SimpleError>::failure(SimpleError{});
bool entered = false;
if (r) {
entered = true;
}
EXPECT_FALSE(entered);
}

} // namespace livekit
Loading
Loading