diff --git a/rtclib b/rtclib index ca4ed0a..d9150b3 160000 --- a/rtclib +++ b/rtclib @@ -1 +1 @@ -Subproject commit ca4ed0aba377f235e5bf643be3d74c7deb5f4d94 +Subproject commit d9150b3af8e5f57f0cd4cd2996b05495dc361bd1 diff --git a/server/src/client/SpeakingClient.cpp b/server/src/client/SpeakingClient.cpp index c6b6c4c..904be00 100644 --- a/server/src/client/SpeakingClient.cpp +++ b/server/src/client/SpeakingClient.cpp @@ -639,6 +639,10 @@ command_result SpeakingClient::handleCommand(Command &command) { return this->handleCommandRtcBroadcast(command); } else if(command.command() == "rtcsessionreset") { return this->handleCommandRtcSessionReset(command); + } else if(command.command() == "broadcastvideojoin") { + return this->handleCommandBroadcastVideoJoin(command); + } else if(command.command() == "broadcastvideoleave") { + return this->handleCommandBroadcastVideoLeave(command); } } return ConnectedClient::handleCommand(command); @@ -747,4 +751,41 @@ command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) { } } return ts::command_result{std::move(result)}; +} + +command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) { + CMD_REQ_SERVER; + CMD_CHK_AND_INC_FLOOD_POINTS(25); + + auto broadcast_type = (rtc::VideoBroadcastType) cmd["bt"].as(); + auto broadcast_id = cmd["bid"].as(); + + using VideoBroadcastJoinResult = rtc::VideoBroadcastJoinResult; + switch(this->server->rtc_server().join_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type)) { + case VideoBroadcastJoinResult::Success: + return ts::command_result{error::ok}; + + case VideoBroadcastJoinResult::InvalidBroadcast: + return ts::command_result{error::broadcast_invalid_id}; + + case VideoBroadcastJoinResult::InvalidBroadcastType: + return ts::command_result{error::broadcast_invalid_type}; + + case VideoBroadcastJoinResult::InvalidClient: + return ts::command_result{error::client_invalid_id}; + + case VideoBroadcastJoinResult::UnknownError: + default: + return ts::command_result{error::vs_critical}; + } +} + +command_result SpeakingClient::handleCommandBroadcastVideoLeave(Command &cmd) { + CMD_REQ_SERVER; + + auto broadcast_type = (rtc::VideoBroadcastType) cmd["bt"].as(); + auto broadcast_id = cmd["bid"].as(); + + this->server->rtc_server().leave_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type); + return ts::command_result{error::ok}; } \ No newline at end of file diff --git a/server/src/client/SpeakingClient.h b/server/src/client/SpeakingClient.h index 97cf7b4..7f43529 100644 --- a/server/src/client/SpeakingClient.h +++ b/server/src/client/SpeakingClient.h @@ -71,6 +71,8 @@ namespace ts::server { virtual command_result handleCommandRtcSessionReset(Command &command); virtual command_result handleCommandRtcIceCandidate(Command &); virtual command_result handleCommandRtcBroadcast(Command &); + virtual command_result handleCommandBroadcastVideoJoin(Command &); + virtual command_result handleCommandBroadcastVideoLeave(Command &); void triggerVoiceEnd(); inline void updateSpeak(bool onlyUpdate, const std::chrono::system_clock::time_point &time); diff --git a/server/src/rtc/imports.h b/server/src/rtc/imports.h index fc1f26e..a11cb09 100644 --- a/server/src/rtc/imports.h +++ b/server/src/rtc/imports.h @@ -5,6 +5,12 @@ extern "C" { #endif +struct BroadcastInfo { + uint32_t broadcasting_client_id; + const void* broadcasting_client_data; + uint8_t broadcast_type; +}; + /* Attention: Do not call any librtc functions within being in the callback, only librtc_destroy_client is allowed */ struct NativeCallbacks { uint32_t version; @@ -21,6 +27,7 @@ struct NativeCallbacks { void(*client_stream_start)(const void* /* callback data */, uint32_t /* stream id */, const void* /* source callback data */); void(*client_stream_stop)(const void* /* callback data */, uint32_t /* stream id */, const void* /* source callback data */); + void(*client_video_broadcast_info)(const void* const* /* callback data array */, uint32_t /* callback data length */, const BroadcastInfo* /* broadcasts */, uint32_t /* broadcast count */); void(*client_audio_sender_data)(const void* /* callback data */, const void* /* source callback data */, uint8_t /* mode */, uint16_t /* seq. no. */, uint8_t /* codec */, const void* /* data */, uint32_t /* length */); void(*client_whisper_session_reset)(const void* /* callback data */); @@ -71,6 +78,8 @@ extern void librtc_destroy_audio_source_supplier(void* /* sender */); extern uint32_t librtc_create_channel(void* /* server */); extern uint32_t librtc_assign_channel(void* /* server */, uint32_t /* client id */, uint32_t /* channel id */); extern uint32_t librtc_client_broadcast(void* /* server */, uint32_t /* client id */, uint8_t /* broadcast type */, uint32_t /* stream id */); +extern uint32_t librtc_video_broadcast_join(void* /* server */, uint32_t /* client id */, uint32_t /* target client id */, uint8_t /* broadcast type */); +extern void librtc_video_broadcast_leave(void* /* server */, uint32_t /* client id */, uint32_t /* target client id */, uint8_t /* broadcast type */); extern void librtc_destroy_channel(void* /* server */, uint32_t /* channel */); extern const char* librtc_whisper_configure(void* /* server */, uint32_t /* client id */, uint32_t /* source stream id */, uint32_t* /* client ids */, uint32_t /* client id count */); diff --git a/server/src/rtc/lib.cpp b/server/src/rtc/lib.cpp index 469f64a..82c3da1 100644 --- a/server/src/rtc/lib.cpp +++ b/server/src/rtc/lib.cpp @@ -165,6 +165,31 @@ void librtc_callback_client_audio_start(const void* callback_data_ptr, uint32_t target_client->sendCommand(notify); } +void librtc_callback_client_video_broadcast_info(const void* const* callback_data_array, uint32_t callback_data_length, const BroadcastInfo* broadcasts, uint32_t broadcast_count) { + ts::command_builder notify{"notifybroadcastvideo", 32, broadcast_count}; + + size_t bulk_index{0}; + for(size_t index{0}; index < broadcast_count; index++) { + auto& broadcast = broadcasts[index]; + auto source_data = (LibCallbackData*) broadcast.broadcasting_client_data; + auto source_client = source_data->weak_ref.lock(); + if(!source_client) { continue; } + + auto bulk = notify.bulk(bulk_index++); + bulk.put_unchecked("bt", broadcast.broadcast_type); + bulk.put_unchecked("bid", broadcast.broadcasting_client_id); + bulk.put_unchecked("sclid", source_client->getClientId()); + } + + for(size_t index{0}; index < callback_data_length; index++) { + auto client_data = (LibCallbackData*) callback_data_array[index]; + auto client = client_data->weak_ref.lock(); + if(!client) { continue; } + + client->sendCommand(notify); + } +} + void librtc_callback_client_audio_stop(const void* callback_data_ptr, uint32_t stream_id, const void* source_data_ptr) { auto callback_data = (LibCallbackData*) callback_data_ptr; auto source_data = (LibCallbackData*) source_data_ptr; @@ -223,7 +248,7 @@ void librtc_client_whisper_session_reset(const void* callback_data_ptr) { } static NativeCallbacks native_callbacks{ - .version = 5, + .version = 6, .log = librtc_callback_log, .free_client_data = librtc_callback_free_client_data, @@ -237,6 +262,8 @@ static NativeCallbacks native_callbacks{ .client_stream_start = librtc_callback_client_audio_start, .client_stream_stop = librtc_callback_client_audio_stop, + .client_video_broadcast_info = librtc_callback_client_video_broadcast_info, + .client_audio_sender_data = librtc_callback_client_audio_sender_data, .client_whisper_session_reset = librtc_client_whisper_session_reset }; @@ -359,6 +386,21 @@ BroadcastStartResult Server::start_broadcast(uint32_t client_id, uint8_t btype, } } +VideoBroadcastJoinResult Server::join_video_broadcast(RTCClientId client_id, RTCClientId target_client_id, VideoBroadcastType video_broadcast_type) { + auto result = librtc_video_broadcast_join(this->server_ptr, client_id, target_client_id, (uint8_t) video_broadcast_type); + switch(result) { + case 0x00: return VideoBroadcastJoinResult::Success; + case 0x01: return VideoBroadcastJoinResult::InvalidBroadcastType; + case 0x02: return VideoBroadcastJoinResult::InvalidClient; + case 0x03: return VideoBroadcastJoinResult::InvalidBroadcast; + default: return VideoBroadcastJoinResult::UnknownError; + } +} + +void Server::leave_video_broadcast(RTCClientId client_id, RTCClientId target_client_id, VideoBroadcastType video_broadcast_type) { + librtc_video_broadcast_leave(this->server_ptr, client_id, target_client_id, (uint8_t) video_broadcast_type); +} + std::optional Server::create_audio_source_supplier_sender(uint32_t client_id, uint32_t stream_id) { auto result = librtc_create_audio_source_supplier(this->server_ptr, client_id, stream_id); if(!result) { return std::nullopt; } diff --git a/server/src/rtc/lib.h b/server/src/rtc/lib.h index 92b5cee..4fdb6a5 100644 --- a/server/src/rtc/lib.h +++ b/server/src/rtc/lib.h @@ -32,6 +32,19 @@ namespace ts::rtc { UnknownError }; + enum struct VideoBroadcastType { + Camera = 0, + Screen = 1 + }; + + enum struct VideoBroadcastJoinResult { + Success, + InvalidClient, + InvalidBroadcast, + InvalidBroadcastType, + UnknownError + }; + class NativeAudioSourceSupplier; class Server { public: @@ -57,6 +70,8 @@ namespace ts::rtc { uint32_t create_channel(); ChannelAssignResult assign_channel(RTCClientId /* client id */, RTCChannelId /* channel id */); BroadcastStartResult start_broadcast(RTCClientId /* client id */, uint8_t /* broadcast type */, RTCStreamId /* stream id */); + VideoBroadcastJoinResult join_video_broadcast(RTCClientId /* client id */, RTCClientId /* target id */, VideoBroadcastType /* broadcast type */); + void leave_video_broadcast(RTCClientId /* client id */, RTCClientId /* target id */, VideoBroadcastType /* broadcast type */); void destroy_channel(RTCChannelId /* channel id */); /* whisper actions */ diff --git a/shared b/shared index 83023f2..1ae3b59 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit 83023f2fa668c99d968dba5525a4284dfd656611 +Subproject commit 1ae3b59e1459fddf49f7f468f51e977c70286596