diff --git a/server/src/client/SpeakingClient.cpp b/server/src/client/SpeakingClient.cpp index 904be00..fcd6473 100644 --- a/server/src/client/SpeakingClient.cpp +++ b/server/src/client/SpeakingClient.cpp @@ -716,18 +716,48 @@ command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) { CMD_REQ_SERVER; CMD_CHK_AND_INC_FLOOD_POINTS(15); - /* TODO: Filter out duplicates */ - std::vector> broadcasts{}; broadcasts.reserve(command.bulkCount()); for(size_t index{0}; index < command.bulkCount(); index++) { auto& bulk = command[index]; - broadcasts.push_back(std::make_tuple(bulk["type"], bulk.has("ssrc") ? bulk["ssrc"].as() : (uint32_t) 0)); + + auto ssrc = bulk.has("ssrc") ? bulk["ssrc"].as() : (uint32_t) 0; + auto type = bulk["type"].as(); + + for(const auto& entry : broadcasts) { + if(std::get<0>(entry) == type) { + return ts::command_result{error::parameter_constraint_violation}; + } + } + + broadcasts.push_back(std::make_tuple(type, ssrc)); } + /* TODO: Apply constraints like bandwidth? */ + ts::command_result_bulk result{}; for(size_t index{0}; index < command.bulkCount(); index++) { + auto broadcast_type = std::get<0>(broadcasts[index]); + switch(broadcast_type) { + case 2: + if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()), false)) { + result.emplace_result(permission::b_video_camera); + continue; + } + break; + + case 3: + if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()), false)) { + result.emplace_result(permission::b_video_screen); + continue; + } + break; + + default: + break; + } + auto broadcast_result = this->server->rtc_server().start_broadcast(this->rtc_client_id, std::get<0>(broadcasts[index]), std::get<1>(broadcasts[index])); switch(broadcast_result) { case rtc::BroadcastStartResult::Success: @@ -755,11 +785,46 @@ command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) { 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(); + if(broadcast_id != this->rtc_client_id) { + CMD_CHK_AND_INC_FLOOD_POINTS(25); + + /* the broadcast is is actually the rtc client id of the broadcaster */ + uint32_t camera_streams, screen_streams; + if(!this->server->rtc_server().client_video_stream_count(this->rtc_client_id, &camera_streams, &screen_streams)) { + return ts::command_result{error::vs_critical, "failed to count client streams"}; + } + + if(!permission::v2::permission_granted(camera_streams + screen_streams, this->calculate_permission(permission::i_video_max_streams, this->getChannelId()), false)) { + return ts::command_result{permission::i_video_max_streams}; + } + + switch(broadcast_type) { + case rtc::VideoBroadcastType::Camera: + if(!permission::v2::permission_granted(camera_streams, this->calculate_permission(permission::i_video_max_camera_streams, this->getChannelId()), false)) { + return ts::command_result{permission::i_video_max_camera_streams}; + } + break; + + case rtc::VideoBroadcastType::Screen: + if(!permission::v2::permission_granted(screen_streams, this->calculate_permission(permission::i_video_max_screen_streams, this->getChannelId()), false)) { + return ts::command_result{permission::i_video_max_screen_streams}; + } + break; + + default: + return ts::command_result{error::broadcast_invalid_type}; + } + } else { + CMD_CHK_AND_INC_FLOOD_POINTS(5); + /* The client is free to join his own broadcast */ + } + + /* TODO: Configure the broadcast? */ + using VideoBroadcastJoinResult = rtc::VideoBroadcastJoinResult; switch(this->server->rtc_server().join_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type)) { case VideoBroadcastJoinResult::Success: diff --git a/server/src/manager/SqlDataManager.cpp b/server/src/manager/SqlDataManager.cpp index b78b88f..e1a6e93 100644 --- a/server/src/manager/SqlDataManager.cpp +++ b/server/src/manager/SqlDataManager.cpp @@ -45,7 +45,7 @@ if(!result && result.msg().find(ignore) == string::npos){ #define RESIZE_COLUMN(tblName, rowName, size) up vote EXECUTE("Could not change column size", "ALTER TABLE " tblName " ALTER COLUMN " rowName " varchar(" size ")"); #define CURRENT_DATABASE_VERSION 17 -#define CURRENT_PERMISSION_VERSION 6 +#define CURRENT_PERMISSION_VERSION 7 #define CLIENT_UID_LENGTH "64" #define CLIENT_NAME_LENGTH "128" @@ -834,6 +834,43 @@ bool SqlDataManager::update_permissions(std::string &error) { return false; perm_version(6); + + case 6: + +#define do_auto_update(type, name, value, granted) \ +if(!auto_update(permission::update::type, name, {value, value != permNotGranted}, false, false, {granted, granted != permNotGranted})) \ + return false; + + do_auto_update(QUERY_ADMIN, "b_video_screen", 1, 100); + do_auto_update(QUERY_ADMIN, "b_video_camera", 1, 100); + do_auto_update(QUERY_ADMIN, "i_video_max_kbps", 20 * 1000 * 1000, 100); + do_auto_update(QUERY_ADMIN, "i_video_max_streams", permNotGranted, 100); + do_auto_update(QUERY_ADMIN, "i_video_max_screen_streams", permNotGranted, 100); + do_auto_update(QUERY_ADMIN, "i_video_max_camera_streams", permNotGranted, 100); + + do_auto_update(SERVER_ADMIN, "b_video_screen", 1, 100); + do_auto_update(SERVER_ADMIN, "b_video_camera", 1, 100); + do_auto_update(SERVER_ADMIN, "i_video_max_kbps", 20 * 1000 * 1000, 100); + do_auto_update(SERVER_ADMIN, "i_video_max_streams", permNotGranted, 100); + do_auto_update(SERVER_ADMIN, "i_video_max_screen_streams", permNotGranted, 100); + do_auto_update(SERVER_ADMIN, "i_video_max_camera_streams", permNotGranted, 100); + + do_auto_update(SERVER_NORMAL, "b_video_screen", 1, 100); + do_auto_update(SERVER_NORMAL, "b_video_camera", 1, 100); + do_auto_update(SERVER_NORMAL, "i_video_max_kbps", 5 * 1000 * 1000, 100); + do_auto_update(SERVER_NORMAL, "i_video_max_streams", 20, 100); + do_auto_update(SERVER_NORMAL, "i_video_max_screen_streams", 2, 100); + do_auto_update(SERVER_NORMAL, "i_video_max_camera_streams", 20, 100); + + do_auto_update(SERVER_GUEST, "b_video_screen", 1, 100); + do_auto_update(SERVER_GUEST, "b_video_camera", 1, 100); + do_auto_update(SERVER_GUEST, "i_video_max_kbps", 2500 * 1000, 100); + do_auto_update(SERVER_GUEST, "i_video_max_streams", 8, 100); + do_auto_update(SERVER_GUEST, "i_video_max_screen_streams", 1, 100); + do_auto_update(SERVER_GUEST, "i_video_max_camera_streams", 8, 100); + + perm_version(7); + default: break; } diff --git a/server/src/rtc/imports.h b/server/src/rtc/imports.h index a11cb09..b1c92d2 100644 --- a/server/src/rtc/imports.h +++ b/server/src/rtc/imports.h @@ -65,6 +65,8 @@ extern const char* librtc_apply_remote_description(void* /* server */, uint32_t extern const char* librtc_generate_local_description(void* /* server */, uint32_t /* client id */, char** /* description */); extern const char* librtc_add_ice_candidate(void* /* server */, uint32_t /* client id */, uint32_t /* media line */, const char* /* candidate */); +extern uint32_t librtc_client_video_stream_count(void* /* server */, uint32_t /* client id */, uint32_t* /* camera count */, uint32_t* /* screen count */); + extern void* librtc_create_audio_source_supplier(void* /* server */, uint32_t /* client id */, uint32_t /* stream id */); extern void librtc_audio_source_supply(void* /* sender */, uint16_t /* seq no */, diff --git a/server/src/rtc/lib.cpp b/server/src/rtc/lib.cpp index 82c3da1..e54d646 100644 --- a/server/src/rtc/lib.cpp +++ b/server/src/rtc/lib.cpp @@ -74,7 +74,7 @@ uint32_t librtc_callback_rtc_configure(const void* callback_data_ptr, void* conf options.ice_tcp = config::web::tcp_enabled; options.ice_udp = config::web::udp_enabled; options.ice_upnp = config::web::enable_upnp; - options.max_port = config::web::webrtc_port_min; + options.min_port = config::web::webrtc_port_min; options.max_port = config::web::webrtc_port_max; std::string stun_host{config::web::stun_host}; @@ -320,6 +320,10 @@ void Server::destroy_client(RTCClientId client_id) { librtc_destroy_client(this->server_ptr, client_id); } +bool Server::client_video_stream_count(uint32_t client_id, uint32_t *camera, uint32_t *desktop) { + return librtc_client_video_stream_count(this->server_ptr, client_id, camera, desktop) == 0; +} + void Server::reset_rtp_session(RTCClientId client_id) { librtc_reset_rtp_session(this->server_ptr, client_id); } diff --git a/server/src/rtc/lib.h b/server/src/rtc/lib.h index 4fdb6a5..1603e56 100644 --- a/server/src/rtc/lib.h +++ b/server/src/rtc/lib.h @@ -56,6 +56,8 @@ namespace ts::rtc { bool initialize_native_connection(std::string& /* error */, RTCClientId /* client id */); void destroy_client(RTCClientId /* client id */); + bool client_video_stream_count(uint32_t /* client id */, uint32_t* /* camera count */, uint32_t* /* screen count */); + /* RTC client actions */ void reset_rtp_session(RTCClientId /* client */); bool apply_remote_description(std::string& /* error */, RTCClientId /* client id */, uint32_t /* mode */, const std::string& /* description */);