1313// TODO(shijing), remove this livekit_ffi.h as it should be internal only.
1414#include " livekit_ffi.h"
1515
16+ // Consider expose this video_utils.h to public ?
17+ #include " video_utils.h"
18+
1619using namespace livekit ;
1720
1821namespace {
@@ -160,6 +163,58 @@ void runNoiseCaptureLoop(const std::shared_ptr<AudioSource> &source) {
160163 std::cout << " Error in clearQueue" << std::endl;
161164 }
162165}
166+
167+ void runFakeVideoCaptureLoop (const std::shared_ptr<VideoSource> &source) {
168+ auto frame = LKVideoFrame::create (1280 , 720 , VideoBufferType::ARGB);
169+ double framerate = 1.0 / 30 ;
170+ while (g_running.load (std::memory_order_relaxed)) {
171+ static auto start = std::chrono::high_resolution_clock::now ();
172+ float t = std::chrono::duration<float >(
173+ std::chrono::high_resolution_clock::now () - start)
174+ .count ();
175+ // Cycle every 4 seconds: 0=red, 1=green, 2=blue, 3 black
176+ int stage = static_cast <int >(t) % 4 ;
177+ std::vector<int > rgb (4 );
178+ switch (stage) {
179+ case 0 : // red
180+ rgb[0 ] = 255 ;
181+ rgb[1 ] = 0 ;
182+ rgb[2 ] = 0 ;
183+ break ;
184+ case 1 : // green
185+ rgb[0 ] = 0 ;
186+ rgb[1 ] = 255 ;
187+ rgb[2 ] = 0 ;
188+ break ;
189+ case 2 : // blue
190+ rgb[0 ] = 0 ;
191+ rgb[1 ] = 0 ;
192+ rgb[2 ] = 255 ;
193+ break ;
194+ case 4 : // black
195+ rgb[0 ] = 0 ;
196+ rgb[1 ] = 0 ;
197+ rgb[2 ] = 0 ;
198+ }
199+ for (size_t i = 0 ; i < frame.dataSize (); i += 4 ) {
200+ frame.data ()[i] = 255 ;
201+ frame.data ()[i + 1 ] = rgb[0 ];
202+ frame.data ()[i + 2 ] = rgb[1 ];
203+ frame.data ()[i + 3 ] = rgb[2 ];
204+ }
205+ LKVideoFrame i420 = convertViaFfi (frame, VideoBufferType::I420, false );
206+ try {
207+ source->captureFrame (frame, 0 , VideoRotation::VIDEO_ROTATION_0);
208+ } catch (const std::exception &e) {
209+ // If something goes wrong, log and break out
210+ std::cerr << " Error in captureFrame: " << e.what () << std::endl;
211+ break ;
212+ }
213+
214+ std::this_thread::sleep_for (std::chrono::duration<double >(framerate));
215+ }
216+ }
217+
163218} // namespace
164219
165220int main (int argc, char *argv[]) {
@@ -210,35 +265,64 @@ int main(int argc, char *argv[]) {
210265 << info.reliable_dc_buffered_amount_low_threshold << " \n "
211266 << " Creation time (ms): " << info.creation_time << " \n " ;
212267
268+ // Setup Audio Source / Track
213269 auto audioSource = std::make_shared<AudioSource>(44100 , 1 , 10 );
214270 auto audioTrack =
215271 LocalAudioTrack::createLocalAudioTrack (" micTrack" , audioSource);
216272
217- TrackPublishOptions opts ;
218- opts .source = TrackSource::SOURCE_MICROPHONE;
219- opts .dtx = false ;
220- opts .simulcast = false ;
221-
273+ TrackPublishOptions audioOpts ;
274+ audioOpts .source = TrackSource::SOURCE_MICROPHONE;
275+ audioOpts .dtx = false ;
276+ audioOpts .simulcast = false ;
277+ std::shared_ptr<LocalTrackPublication> audioPub;
222278 try {
223279 // publishTrack takes std::shared_ptr<Track>, LocalAudioTrack derives from
224280 // Track
225- auto pub = room.local_participant ()->publishTrack (audioTrack, opts );
281+ audioPub = room.local_participant ()->publishTrack (audioTrack, audioOpts );
226282
227283 std::cout << " Published track:\n "
228- << " SID: " << pub ->sid () << " \n "
229- << " Name: " << pub ->name () << " \n "
230- << " Kind: " << static_cast <int >(pub ->kind ()) << " \n "
231- << " Source: " << static_cast <int >(pub ->source ()) << " \n "
232- << " Simulcasted: " << std::boolalpha << pub ->simulcasted ()
284+ << " SID: " << audioPub ->sid () << " \n "
285+ << " Name: " << audioPub ->name () << " \n "
286+ << " Kind: " << static_cast <int >(audioPub ->kind ()) << " \n "
287+ << " Source: " << static_cast <int >(audioPub ->source ()) << " \n "
288+ << " Simulcasted: " << std::boolalpha << audioPub ->simulcasted ()
233289 << " \n "
234- << " Muted: " << std::boolalpha << pub ->muted () << " \n " ;
290+ << " Muted: " << std::boolalpha << audioPub ->muted () << " \n " ;
235291 } catch (const std::exception &e) {
236292 std::cerr << " Failed to publish track: " << e.what () << std::endl;
237293 }
238294
239295 // TODO, if we have pre-buffering feature, we might consider starting the
240296 // thread right after creating the source.
241297 std::thread audioThread (runNoiseCaptureLoop, audioSource);
298+
299+ // Setup Video Source / Track
300+ auto videoSource = std::make_shared<VideoSource>(1280 , 720 );
301+ std::shared_ptr<LocalVideoTrack> videoTrack =
302+ LocalVideoTrack::createLocalVideoTrack (" cam" , videoSource);
303+ TrackPublishOptions videoOpts;
304+ videoOpts.source = TrackSource::SOURCE_CAMERA;
305+ videoOpts.dtx = false ;
306+ videoOpts.simulcast = true ;
307+ std::shared_ptr<LocalTrackPublication> videoPub;
308+ try {
309+ // publishTrack takes std::shared_ptr<Track>, LocalAudioTrack derives from
310+ // Track
311+ videoPub = room.local_participant ()->publishTrack (videoTrack, videoOpts);
312+
313+ std::cout << " Published track:\n "
314+ << " SID: " << videoPub->sid () << " \n "
315+ << " Name: " << videoPub->name () << " \n "
316+ << " Kind: " << static_cast <int >(videoPub->kind ()) << " \n "
317+ << " Source: " << static_cast <int >(videoPub->source ()) << " \n "
318+ << " Simulcasted: " << std::boolalpha << videoPub->simulcasted ()
319+ << " \n "
320+ << " Muted: " << std::boolalpha << videoPub->muted () << " \n " ;
321+ } catch (const std::exception &e) {
322+ std::cerr << " Failed to publish track: " << e.what () << std::endl;
323+ }
324+ std::thread videoThread (runFakeVideoCaptureLoop, videoSource);
325+
242326 // Keep the app alive until Ctrl-C so we continue receiving events,
243327 // similar to asyncio.run(main()) keeping the loop running.
244328 while (g_running.load ()) {
@@ -249,6 +333,14 @@ int main(int argc, char *argv[]) {
249333 if (audioThread.joinable ()) {
250334 audioThread.join ();
251335 }
336+ // Clean up the audio track publishment
337+ room.local_participant ()->unpublishTrack (audioPub->sid ());
338+
339+ if (videoThread.joinable ()) {
340+ videoThread.join ();
341+ }
342+ // Clean up the video track publishment
343+ room.local_participant ()->unpublishTrack (videoPub->sid ());
252344
253345 FfiClient::instance ().shutdown ();
254346 std::cout << " Exiting.\n " ;
0 commit comments