Skip to content

Commit 1319391

Browse files
Sxian/clt 2315/implement sdl media manager hookup audio video streams (#12)
* initial commit for video stream and other hooks * Get things functional * Implement the SDL media handling and hook up audio / video streams * fix the comments and the build * another try to fix the linux build
1 parent 847a8e1 commit 1319391

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2121
-365
lines changed

examples/CMakeLists.txt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
11
cmake_minimum_required(VERSION 3.31.0)
22
project (livekit-examples)
33

4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
7+
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
8+
include(sdl3)
9+
410
add_executable(SimpleRoom
511
simple_room/main.cpp
12+
simple_room/fallback_capture.cpp
13+
simple_room/fallback_capture.h
14+
simple_room/sdl_media.cpp
15+
simple_room/sdl_media.h
16+
simple_room/sdl_media_manager.cpp
17+
simple_room/sdl_media_manager.h
18+
simple_room/sdl_video_renderer.cpp
19+
simple_room/sdl_video_renderer.h
620
simple_room/wav_audio_source.cpp
721
simple_room/wav_audio_source.h
822
)
923

10-
target_link_libraries(SimpleRoom livekit)
24+
target_link_libraries(SimpleRoom
25+
PRIVATE
26+
livekit
27+
SDL3::SDL3
28+
)
1129

1230
add_custom_command(TARGET SimpleRoom POST_BUILD
1331
COMMAND ${CMAKE_COMMAND} -E copy_directory
1432
${CMAKE_SOURCE_DIR}/data
1533
${CMAKE_CURRENT_BINARY_DIR}/data
16-
)
34+
)

examples/cmake/sdl3.cmake

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# cmake/sdl3.cmake
2+
include(FetchContent)
3+
4+
# Only fetch/build SDL3 once, even if this file is included multiple times
5+
if (NOT TARGET SDL3::SDL3)
6+
FetchContent_Declare(
7+
SDL3
8+
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
9+
GIT_TAG release-3.2.26
10+
)
11+
12+
FetchContent_MakeAvailable(SDL3)
13+
endif()
14+
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2025 LiveKit, Inc.
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+
#include "fallback_capture.h"
18+
19+
#include <chrono>
20+
#include <thread>
21+
22+
#include "livekit/livekit.h"
23+
#include "wav_audio_source.h"
24+
25+
using namespace livekit;
26+
27+
// Test utils to run a capture loop to publish noisy audio frames to the room
28+
void runNoiseCaptureLoop(const std::shared_ptr<AudioSource> &source,
29+
std::atomic<bool> &running_flag) {
30+
const int sample_rate = source->sample_rate();
31+
const int num_channels = source->num_channels();
32+
const int frame_ms = 10;
33+
const int samples_per_channel = sample_rate * frame_ms / 1000;
34+
35+
// FIX: variable name should not shadow the type
36+
WavAudioSource wavSource("data/welcome.wav", 48000, 1, false);
37+
38+
using Clock = std::chrono::steady_clock;
39+
auto next_deadline = Clock::now();
40+
while (running_flag.load(std::memory_order_relaxed)) {
41+
AudioFrame frame =
42+
AudioFrame::create(sample_rate, num_channels, samples_per_channel);
43+
wavSource.fillFrame(frame);
44+
try {
45+
source->captureFrame(frame);
46+
} catch (const std::exception &e) {
47+
std::cerr << "Error in captureFrame (noise): " << e.what() << std::endl;
48+
break;
49+
}
50+
51+
// Pace the loop to roughly real-time
52+
next_deadline += std::chrono::milliseconds(frame_ms);
53+
std::this_thread::sleep_until(next_deadline);
54+
}
55+
56+
try {
57+
source->clearQueue();
58+
} catch (...) {
59+
std::cout << "Error in clearQueue (noise)" << std::endl;
60+
}
61+
}
62+
63+
// Fake video source: solid color cycling
64+
void runFakeVideoCaptureLoop(const std::shared_ptr<VideoSource> &source,
65+
std::atomic<bool> &running_flag) {
66+
auto frame = LKVideoFrame::create(1280, 720, VideoBufferType::BGRA);
67+
const double framerate = 1.0 / 30.0;
68+
69+
while (running_flag.load(std::memory_order_relaxed)) {
70+
static auto start = std::chrono::high_resolution_clock::now();
71+
float t = std::chrono::duration<float>(
72+
std::chrono::high_resolution_clock::now() - start)
73+
.count();
74+
// Cycle every 4 seconds: 0=red, 1=green, 2=blue, 3=black
75+
int stage = static_cast<int>(t) % 4;
76+
77+
std::array<uint8_t, 4> rgb{};
78+
switch (stage) {
79+
case 0: // red
80+
rgb = {255, 0, 0, 0};
81+
break;
82+
case 1: // green
83+
rgb = {0, 255, 0, 0};
84+
break;
85+
case 2: // blue
86+
rgb = {0, 0, 255, 0};
87+
break;
88+
case 3: // black
89+
default:
90+
rgb = {0, 0, 0, 0};
91+
break;
92+
}
93+
94+
// ARGB
95+
uint8_t *data = frame.data();
96+
const size_t size = frame.dataSize();
97+
for (size_t i = 0; i < size; i += 4) {
98+
data[i + 0] = 255; // A
99+
data[i + 1] = rgb[0]; // R
100+
data[i + 2] = rgb[1]; // G
101+
data[i + 3] = rgb[2]; // B
102+
}
103+
104+
try {
105+
// If VideoSource is ARGB-capable, pass frame.
106+
// If it expects I420, pass i420 instead.
107+
source->captureFrame(frame, 0, VideoRotation::VIDEO_ROTATION_0);
108+
} catch (const std::exception &e) {
109+
std::cerr << "Error in captureFrame (fake video): " << e.what()
110+
<< std::endl;
111+
break;
112+
}
113+
114+
std::this_thread::sleep_for(std::chrono::duration<double>(framerate));
115+
}
116+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2025 LiveKit, Inc.
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+
#pragma once
18+
19+
#include <chrono>
20+
#include <memory>
21+
22+
// Assuming you already have this somewhere:
23+
extern std::atomic<bool> g_running;
24+
25+
namespace livekit {
26+
class AudioSource;
27+
class VideoSource;
28+
} // namespace livekit
29+
30+
void runNoiseCaptureLoop(const std::shared_ptr<livekit::AudioSource> &source,
31+
std::atomic<bool> &running_flag);
32+
33+
void runFakeVideoCaptureLoop(
34+
const std::shared_ptr<livekit::VideoSource> &source,
35+
std::atomic<bool> &running_flag);

0 commit comments

Comments
 (0)