Skip to content
Merged
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
12 changes: 11 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,21 @@ CI step will fail loudly if its symbols escape the public ABI of

Tests are under `src/tests/` using Google Test:

```
```bash
source .token_helpers/set_data_track_test_tokens.bash
./build.sh debug-tests
cd build-debug && ctest
```

Always source the test tokens before running tests, even for a targeted local
test run. The integration and stress suites require `LIVEKIT_URL`,
`LIVEKIT_TOKEN_A`, and `LIVEKIT_TOKEN_B`; use
`source .token_helpers/set_data_track_test_tokens.bash` from the repository
root so the current shell inherits them. Do not report an integration test as
verified just because it was skipped for missing tokens. If tokens cannot be
sourced or the LiveKit server is not available, say that the integration test
was not actually exercised.

Integration tests (`src/tests/integration/`) cover: room connections, callbacks, data tracks, RPC, logging, audio processing, and the subscription thread dispatcher. The token source HTTP/JSON wire contract (request serialization, response parsing, header passthrough, GET support, sandbox URL/header resolution) is covered by mocked unit tests in `src/tests/unit/test_token_source.cpp`, which inject a stub HTTP transport so no live server is needed. For a full end-to-end check, `TokenSourceEndpointConnectTest` connects a `Room` with a real JWT minted by the `livekit/token-server-action` token server pointed at the local dev `livekit-server`. The action exposes its `/createToken` endpoint as a `token-url` output; `tests.yml` passes that to the integration test step as `LIVEKIT_CREATE_TOKEN_URL`, which the test reads to locate the endpoint. The server is started in the `e2e-testing` jobs via the token server's reusable GitHub Action, pinned by SHA in `tests.yml`.

When adding new client facing functionality, add a new test case to the existing test suite.
Expand Down
17 changes: 17 additions & 0 deletions include/livekit/room_event_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,19 @@ struct AudioEncodingOptions {
std::uint64_t max_bitrate = 0;
};

/// @brief Controls how the encoder degrades quality when bandwidth is constrained.
enum class DegradationPreference {
/// Balance between framerate and resolution degradation.
Balanced = 0,
/// Degrade resolution to maintain framerate (prioritize smooth motion).
MaintainFramerate = 1,
/// Degrade framerate to maintain resolution (prioritize image clarity).
MaintainResolution = 2,
/// Maintain both framerate and resolution. Frames may be dropped before
/// encoding if necessary to avoid overusing network and encoder resources.
MaintainFramerateAndResolution = 4,
};

/// Optional frame metadata features for published video tracks.
struct FrameMetadataFeatures {
/// Embed a user-supplied wall-clock timestamp.
Expand Down Expand Up @@ -324,6 +337,10 @@ struct TrackPublishOptions {
/// @deprecated Use frame_metadata_features instead.
[[deprecated("TrackPublishOptions::packet_trailer_features is deprecated; use frame_metadata_features instead")]]
FrameMetadataFeatures packet_trailer_features{};

/// Controls how the encoder trades off between resolution and framerate
/// when bandwidth is constrained. If not set, the server defaults apply.
std::optional<DegradationPreference> degradation_preference;
Comment thread
alan-george-lk marked this conversation as resolved.
};

// ---------------------------------------------------------
Expand Down
6 changes: 6 additions & 0 deletions src/room_proto_converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,9 @@ proto::TrackPublishOptions toProto(const TrackPublishOptions& in) {
for (const proto::FrameMetadataFeature feature : toProto(mergedFrameMetadataFeatures(in))) {
msg.add_frame_metadata_features(feature);
}
if (in.degradation_preference) {
msg.set_degradation_preference(static_cast<proto::DegradationPreference>(*in.degradation_preference));
}
return msg;
}

Expand Down Expand Up @@ -563,6 +566,9 @@ TrackPublishOptions fromProto(const proto::TrackPublishOptions& in) {
out.frame_metadata_features = frame_metadata_features;
}
out.packet_trailer_features = frame_metadata_features;
if (in.has_degradation_preference()) {
out.degradation_preference = static_cast<DegradationPreference>(in.degradation_preference());
}
return out;
}

Expand Down
2 changes: 1 addition & 1 deletion src/tests/common/test_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ class LiveKitTestBase : public ::testing::Test {
/// Fail the test if the required environment variables are not set
void failIfNotConfigured() {
if (!config_.available) {
FAIL() << "LIVEKIT_URL, LIVEKIT_TOKEN_A, and LIVEKIT_TOKEN_B not set";
throw std::runtime_error("LIVEKIT_URL, LIVEKIT_TOKEN_A, and LIVEKIT_TOKEN_B not set");
}
}

Expand Down
1 change: 1 addition & 0 deletions src/tests/unit/test_room_event_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ TEST(RoomEventTypesTest, TrackPublishOptionsDefaults) {
EXPECT_FALSE(options.packet_trailer_features.user_timestamp);
EXPECT_FALSE(options.packet_trailer_features.frame_id);
EXPECT_FALSE(options.packet_trailer_features.user_data);
EXPECT_FALSE(options.degradation_preference.has_value());
}

TEST(RoomEventTypesTest, UserPacketDataDefaults) {
Expand Down
14 changes: 14 additions & 0 deletions src/tests/unit/test_video_frame_metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,20 @@ TEST(TrackPublishOptionsTest, FrameMetadataFeaturesRoundTrip) {
EXPECT_TRUE(round_trip.frame_metadata_features->user_data);
}

TEST(TrackPublishOptionsTest, DegradationPreferenceRoundTrip) {
TrackPublishOptions options;
options.degradation_preference = DegradationPreference::MaintainFramerateAndResolution;

proto::TrackPublishOptions proto_options = toProto(options);
ASSERT_TRUE(proto_options.has_degradation_preference());
EXPECT_EQ(proto_options.degradation_preference(),
proto::DegradationPreference::DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE_AND_RESOLUTION);

TrackPublishOptions round_trip = fromProto(proto_options);
ASSERT_TRUE(round_trip.degradation_preference.has_value());
EXPECT_EQ(*round_trip.degradation_preference, DegradationPreference::MaintainFramerateAndResolution);
}

TEST(TrackPublishOptionsTest, DeprecatedPacketTrailerFeaturesAreMerged) {
TrackPublishOptions options;

Expand Down
Loading