99
1010#include " livekit/livekit.h"
1111
12+ // TODO, remove this livekit_ffi.h as it should be internal only.
13+ #include " livekit_ffi.h"
14+
15+ // If you have concrete RemoteParticipant / Track / Publication types exposed from Room,
16+ // you can also include their headers and use them directly in main.
17+ // For now we demonstrate logging via RoomDelegate events.
18+
1219using namespace livekit ;
1320
1421namespace {
22+
1523std::atomic<bool > g_running{true };
1624
1725void print_usage (const char * prog) {
@@ -88,6 +96,47 @@ bool parse_args(int argc, char* argv[], std::string& url, std::string& token) {
8896
8997 return !(url.empty () || token.empty ());
9098}
99+
100+ // ---------------------------------------------------------------------
101+ // SimpleRoomDelegate: analogous to the Python @room.on(...) handlers
102+ // ---------------------------------------------------------------------
103+
104+ class SimpleRoomDelegate : public livekit ::RoomDelegate {
105+ public:
106+ void onParticipantConnected (
107+ livekit::Room& /* room*/ ,
108+ const livekit::ParticipantConnectedEvent& ev) override
109+ {
110+ // Python:
111+ // logger.info("participant connected: %s %s", participant.sid, participant.identity)
112+ std::cout << " [Room] participant connected: identity="
113+ << ev.identity << " name=" << ev.name << " \n " ;
114+ }
115+
116+ void onTrackSubscribed (
117+ livekit::Room& /* room*/ ,
118+ const livekit::TrackSubscribedEvent& ev) override
119+ {
120+ // Python:
121+ // logger.info("track subscribed: %s", publication.sid)
122+ std::cout << " [Room] track subscribed: participant_identity="
123+ << ev.participant_identity
124+ << " track_sid=" << ev.track_sid
125+ << " name=" << ev.track_name << " \n " ;
126+
127+ // Python version also does:
128+ // if track.kind == KIND_VIDEO:
129+ // video_stream = VideoStream(track)
130+ // asyncio.ensure_future(receive_frames(video_stream))
131+ //
132+ // In C++, you'd typically spawn a thread or use your own executor here
133+ // once you have a concrete Track / VideoStream API.
134+ //
135+ // TODO: when you expose Track kind/source here, you can check whether
136+ // this is a video track and start a VideoStream-like consumer.
137+ }
138+ };
139+
91140} // namespace
92141
93142int main (int argc, char * argv[]) {
@@ -97,20 +146,75 @@ int main(int argc, char* argv[]) {
97146 return 1 ;
98147 }
99148
149+ // exit if token and url are not set (similar to Python example)
150+ if (url.empty () || token.empty ()) {
151+ std::cerr << " LIVEKIT_URL and LIVEKIT_TOKEN (or CLI args) are required\n " ;
152+ return 1 ;
153+ }
154+
100155 std::cout << " Connecting to: " << url << std::endl;
101156
102157 // Handle Ctrl-C to exit the idle loop
103158 std::signal (SIGINT, handle_sigint);
104159
105- Room room{};
106- room.Connect (url.c_str (), token.c_str ());
160+ livekit::Room room{};
161+ SimpleRoomDelegate delegate;
162+ room.setDelegate (&delegate);
163+
164+ bool res = room.Connect (url, token);
165+ std::cout << " Connect result is " << std::boolalpha << res << std::endl;
166+ if (!res) {
167+ std::cerr << " Failed to connect to room\n " ;
168+ FfiClient::instance ().shutdown ();
169+ return 1 ;
170+ }
171+
172+ auto info = room.room_info ();
173+ std::cout << " Connected to room:\n "
174+ << " SID: " << (info.sid ? *info.sid : " (none)" ) << " \n "
175+ << " Name: " << info.name << " \n "
176+ << " Metadata: " << info.metadata << " \n "
177+ << " Max participants: " << info.max_participants << " \n "
178+ << " Num participants: " << info.num_participants << " \n "
179+ << " Num publishers: " << info.num_publishers << " \n "
180+ << " Active recording: " << (info.active_recording ? " yes" : " no" ) << " \n "
181+ << " Empty timeout (s): " << info.empty_timeout << " \n "
182+ << " Departure timeout (s): " << info.departure_timeout << " \n "
183+ << " Lossy DC low threshold: " << info.lossy_dc_buffered_amount_low_threshold << " \n "
184+ << " Reliable DC low threshold: " << info.reliable_dc_buffered_amount_low_threshold << " \n "
185+ << " Creation time (ms): " << info.creation_time << " \n " ;
186+
187+
188+ // TODO, implement local and remoteParticipants in the room
189+ /*
190+ const auto& participants = room.remoteParticipants(); // e.g. map<string, shared_ptr<RemoteParticipant>>
191+ for (const auto& [identity, participant] : participants) {
192+ std::cout << "identity: " << identity << "\n";
193+ std::cout << "participant sid: " << participant->sid() << "\n";
194+ std::cout << "participant identity: " << participant->identity() << "\n";
195+ std::cout << "participant name: " << participant->name() << "\n";
196+ std::cout << "participant kind: " << static_cast<int>(participant->kind()) << "\n";
197+
198+ const auto& pubs = participant->trackPublications(); // e.g. map<string, shared_ptr<RemoteTrackPublication>>
199+ std::cout << "participant track publications: " << pubs.size() << "\n";
200+ for (const auto& [tid, publication] : pubs) {
201+ std::cout << "\ttrack id: " << tid << "\n";
202+ std::cout << "\t\ttrack publication sid: " << publication->sid() << "\n";
203+ std::cout << "\t\ttrack kind: " << static_cast<int>(publication->kind()) << "\n";
204+ std::cout << "\t\ttrack name: " << publication->name() << "\n";
205+ std::cout << "\t\ttrack source: " << static_cast<int>(publication->source()) << "\n";
206+ }
207+
208+ std::cout << "participant metadata: " << participant->metadata() << "\n";
209+ }*/
107210
108- // TODO: replace with proper event loop / callbacks.
109- // For now, keep the app alive until Ctrl-C .
211+ // Keep the app alive until Ctrl-C so we continue receiving events,
212+ // similar to asyncio.run(main()) keeping the loop running .
110213 while (g_running.load ()) {
111214 std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
112215 }
113216
217+ FfiClient::instance ().shutdown ();
114218 std::cout << " Exiting.\n " ;
115219 return 0 ;
116220}
0 commit comments