Added support for controlling the streams max bps

This commit is contained in:
WolverinDEV 2021-01-04 20:32:29 +01:00
parent a233915064
commit 8be83fc51d
11 changed files with 357 additions and 60 deletions

@ -1 +1 @@
Subproject commit b07d170e7b5260d341db2617187e0df7edc71b3c Subproject commit 366ba5ba42e7503afcb2e81b367209c9e4f5c5d7

2
rtclib

@ -1 +1 @@
Subproject commit ea13ab489529ef0ebc72c15505c6be52ed484269 Subproject commit 2c08b8759268095b96f3904757300905db1ea61d

View File

@ -478,7 +478,7 @@ void VirtualServer::client_move(
} }
if(auto client{dynamic_pointer_cast<VoiceClient>(target)}; client) { if(auto client{dynamic_pointer_cast<VoiceClient>(target)}; client) {
/* Start normal broadcasting, what the client expects */ /* Start normal broadcasting, what the client expects */
this->rtc_server().start_broadcast(client->rtc_client_id, 1, 1); this->rtc_server().start_broadcast_audio(client->rtc_client_id, 1);
} }
} else { } else {
/* client left the server */ /* client left the server */

View File

@ -619,7 +619,7 @@ namespace ts {
//handleCommandDummy_ConnectFailed //handleCommandDummy_ConnectFailed
//handleCommandDummy_ConnectionLost //handleCommandDummy_ConnectionLost
//Not needed - completly useless //Not needed - completely useless
//CMD_TODO handleCommandCustomInfo //CMD_TODO handleCommandCustomInfo
//CMD_TODO handleCommandCustomSearch //CMD_TODO handleCommandCustomSearch
//CMD_TODO serverquerycmd //CMD_TODO serverquerycmd

View File

@ -15,6 +15,7 @@
#include "misc/timer.h" #include "misc/timer.h"
#include "../manager/ActionLogger.h" #include "../manager/ActionLogger.h"
#include "./voice/VoiceClient.h" #include "./voice/VoiceClient.h"
#include "../rtc/imports.h"
using namespace std::chrono; using namespace std::chrono;
using namespace ts; using namespace ts;
@ -620,13 +621,22 @@ command_result SpeakingClient::handleCommand(Command &command) {
} else if(command.command() == "rtcicecandidate") { } else if(command.command() == "rtcicecandidate") {
return this->handleCommandRtcIceCandidate(command); return this->handleCommandRtcIceCandidate(command);
} else if(command.command() == "rtcbroadcast") { } else if(command.command() == "rtcbroadcast") {
/* TODO: Remove this command once the first 1.5.0 stable is out */
return this->handleCommandRtcBroadcast(command); return this->handleCommandRtcBroadcast(command);
} else if(command.command() == "rtcsessionreset") { } else if(command.command() == "rtcsessionreset") {
return this->handleCommandRtcSessionReset(command); return this->handleCommandRtcSessionReset(command);
} else if(command.command() == "broadcastaudio") {
return this->handleCommandBroadcastAudio(command);
} else if(command.command() == "broadcastvideo") {
return this->handleCommandBroadcastVideo(command);
} else if(command.command() == "broadcastvideojoin") { } else if(command.command() == "broadcastvideojoin") {
return this->handleCommandBroadcastVideoJoin(command); return this->handleCommandBroadcastVideoJoin(command);
} else if(command.command() == "broadcastvideoleave") { } else if(command.command() == "broadcastvideoleave") {
return this->handleCommandBroadcastVideoLeave(command); return this->handleCommandBroadcastVideoLeave(command);
} else if(command.command() == "broadcastvideoconfig") {
return this->handleCommandBroadcastVideoConfig(command);
} else if(command.command() == "broadcastvideoconfigure") {
return this->handleCommandBroadcastVideoConfigure(command);
} }
} }
return ConnectedClient::handleCommand(command); return ConnectedClient::handleCommand(command);
@ -676,7 +686,7 @@ command_result SpeakingClient::handleCommandRtcSessionReset(Command &command) {
this->server->rtc_server().reset_rtp_session(this->rtc_client_id); this->server->rtc_server().reset_rtp_session(this->rtc_client_id);
if(this->getType() == ClientType::CLIENT_TEASPEAK) { if(this->getType() == ClientType::CLIENT_TEASPEAK) {
/* registering the broadcast again since rtp session reset resets the broadcasts as well */ /* registering the broadcast again since rtp session reset resets the broadcasts as well */
this->server->rtc_server().start_broadcast(this->rtc_client_id, 1, 1); this->server->rtc_server().start_broadcast_audio(this->rtc_client_id, 1);
} }
return command_result{error::ok}; return command_result{error::ok};
} }
@ -696,6 +706,128 @@ command_result SpeakingClient::handleCommandRtcIceCandidate(Command &command) {
return command_result{error::ok}; return command_result{error::ok};
} }
ts::command_result parse_broadcast_options(ParameterBulk &cmd, VideoBroadcastOptions& options, bool requires_all) {
if(cmd.has("broadcast_bitrate_max")) {
options.update_mask |= VideoBroadcastOptions::kOptionBitrate;
options.bitrate = cmd["broadcast_bitrate_max"];
} else if(requires_all) {
return ts::command_result{error::parameter_missing, "broadcast_bitrate_max"};
}
if(cmd.has("broadcast_keyframe_interval")) {
options.update_mask |= VideoBroadcastOptions::kOptionKeyframeInterval;
options.keyframe_interval = cmd["broadcast_keyframe_interval"];
} else if(requires_all) {
return ts::command_result{error::parameter_missing, "broadcast_keyframe_interval"};
}
return ts::command_result{error::ok};
}
void simplify_broadcast_options(const VideoBroadcastOptions& current_options, VideoBroadcastOptions& target_options) {
if(target_options.bitrate == current_options.bitrate) {
target_options.update_mask &= ~VideoBroadcastOptions::kOptionBitrate;
}
if(target_options.keyframe_interval == current_options.keyframe_interval) {
target_options.update_mask &= ~VideoBroadcastOptions::kOptionKeyframeInterval;
}
}
/**
* Test if the client has permissions to use the target broadcast options
* @param client
* @param channel_id
* @param options
* @return
*/
ts::command_result test_broadcast_options(SpeakingClient& client, ChannelId channel_id, const VideoBroadcastOptions& options) {
if(options.update_mask & VideoBroadcastOptions::kOptionBitrate) {
auto required_value = options.bitrate == 0 ? -1 : (permission::PermissionValue) (options.bitrate / 1000);
if(!permission::v2::permission_granted(required_value, client.calculate_permission(permission::i_video_max_kbps, channel_id))) {
return ts::command_result{permission::i_video_max_kbps};
}
}
return ts::command_result{error::ok};
}
inline command_result broadcast_start_result_to_command_result(rtc::BroadcastStartResult broadcast_result) {
switch(broadcast_result) {
case rtc::BroadcastStartResult::Success:
return ts::command_result{error::ok};
case rtc::BroadcastStartResult::InvalidBroadcastType:
return ts::command_result{error::parameter_invalid, "type"};
case rtc::BroadcastStartResult::InvalidStreamId:
return ts::command_result{error::rtc_missing_target_channel};
case rtc::BroadcastStartResult::ClientHasNoChannel:
return ts::command_result{error::vs_critical, "no channel"};
case rtc::BroadcastStartResult::InvalidClient:
return ts::command_result{error::vs_critical, "invalid client"};
case rtc::BroadcastStartResult::UnknownError:
default:
return ts::command_result{error::vs_critical, "unknown error"};
}
}
command_result SpeakingClient::handleCommandBroadcastAudio(Command &command) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(5);
auto ssrc = command[0].has("ssrc") ? command["ssrc"].as<uint32_t>() : (uint32_t) 0;
auto broadcast_result = this->server->rtc_server().start_broadcast_audio(this->rtc_client_id, ssrc);
return broadcast_start_result_to_command_result(broadcast_result);
}
command_result SpeakingClient::handleCommandBroadcastVideo(Command &command) {
CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(15);
auto ssrc = command[0].has("ssrc") ? command["ssrc"].as<uint32_t>() : (uint32_t) 0;
auto type = (rtc::VideoBroadcastType) command["type"].as<uint8_t>();
switch(type) {
case rtc::VideoBroadcastType::Screen:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()), false)) {
return ts::command_result{permission::b_video_screen};
}
break;
case rtc::VideoBroadcastType::Camera:
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_camera, this->getChannelId()), false)) {
return ts::command_result{permission::b_video_camera};
}
break;
default:
return ts::command_result{error::parameter_invalid, "type"};
}
VideoBroadcastOptions options;
memset(&options, 0, sizeof(options));
if(ssrc != 0) {
ts::command_result result;
result.reset(parse_broadcast_options(command[0], options, true));
if(result.has_error()) {
return result;
}
result.reset(test_broadcast_options(*this, this->getChannelId(), options));
if(result.has_error()) {
return result;
}
result.release_data();
}
auto broadcast_result = this->server->rtc_server().start_broadcast_video(this->rtc_client_id, type, ssrc, &options);
return broadcast_start_result_to_command_result(broadcast_result);
}
command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) { command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) {
CMD_REQ_SERVER; CMD_REQ_SERVER;
CMD_CHK_AND_INC_FLOOD_POINTS(15); CMD_CHK_AND_INC_FLOOD_POINTS(15);
@ -703,6 +835,7 @@ command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) {
std::vector<std::tuple<uint8_t, uint32_t>> broadcasts{}; std::vector<std::tuple<uint8_t, uint32_t>> broadcasts{};
broadcasts.reserve(command.bulkCount()); broadcasts.reserve(command.bulkCount());
ts::command_result_bulk result{};
for(size_t index{0}; index < command.bulkCount(); index++) { for(size_t index{0}; index < command.bulkCount(); index++) {
auto& bulk = command[index]; auto& bulk = command[index];
@ -716,54 +849,37 @@ command_result SpeakingClient::handleCommandRtcBroadcast(Command &command) {
} }
broadcasts.push_back(std::make_tuple(type, ssrc)); broadcasts.push_back(std::make_tuple(type, ssrc));
} switch(type) {
case 1: {
/* TODO: Apply constraints like bandwidth? */ ts::Command cmd{""};
cmd["ssrc"] = ssrc;
ts::command_result_bulk result{}; result.insert_result(this->handleCommandBroadcastAudio(cmd));
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; break;
}
case 3: case 2: {
if(!permission::v2::permission_granted(1, this->calculate_permission(permission::b_video_screen, this->getChannelId()), false)) { ts::Command cmd{""};
result.emplace_result(permission::b_video_screen); cmd["broadcast_bitrate_max"] = 1500000;
continue; cmd["broadcast_keyframe_interval"] = 7;
} cmd["ssrc"] = ssrc;
cmd["type"] = (uint8_t) rtc::VideoBroadcastType::Camera;
result.insert_result(this->handleCommandBroadcastVideo(cmd));
break; break;
}
case 3: {
ts::Command cmd{""};
cmd["broadcast_bitrate_max"] = 1500000;
cmd["broadcast_keyframe_interval"] = 7;
cmd["ssrc"] = ssrc;
cmd["type"] = (uint8_t) rtc::VideoBroadcastType::Screen;
result.insert_result(this->handleCommandBroadcastVideo(cmd));
break;
}
default: 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:
result.emplace_result(error::ok);
break;
case rtc::BroadcastStartResult::InvalidBroadcastType:
result.emplace_result(error::parameter_invalid, "type"); result.emplace_result(error::parameter_invalid, "type");
break; break;
case rtc::BroadcastStartResult::InvalidStreamId:
result.emplace_result(error::rtc_missing_target_channel);
break;
case rtc::BroadcastStartResult::ClientHasNoChannel:
result.emplace_result(error::vs_critical, "no channel");
break;
case rtc::BroadcastStartResult::InvalidClient:
result.emplace_result(error::vs_critical, "invalid client");
break;
case rtc::BroadcastStartResult::UnknownError:
default:
result.emplace_result(error::vs_critical, "unknown error");
} }
} }
return ts::command_result{std::move(result)}; return ts::command_result{std::move(result)};
} }
@ -818,8 +934,6 @@ command_result SpeakingClient::handleCommandBroadcastVideoJoin(Command &cmd) {
/* The client is free to join his own broadcast */ /* The client is free to join his own broadcast */
} }
/* TODO: Configure the broadcast? */
using VideoBroadcastJoinResult = rtc::VideoBroadcastJoinResult; using VideoBroadcastJoinResult = rtc::VideoBroadcastJoinResult;
switch(this->server->rtc_server().join_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type)) { switch(this->server->rtc_server().join_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type)) {
case VideoBroadcastJoinResult::Success: case VideoBroadcastJoinResult::Success:
@ -848,4 +962,101 @@ command_result SpeakingClient::handleCommandBroadcastVideoLeave(Command &cmd) {
this->server->rtc_server().leave_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type); this->server->rtc_server().leave_video_broadcast(this->rtc_client_id, broadcast_id, broadcast_type);
return ts::command_result{error::ok}; return ts::command_result{error::ok};
}
command_result SpeakingClient::handleCommandBroadcastVideoConfig(Command &cmd) {
CMD_REQ_SERVER;
auto broadcast_type = (rtc::VideoBroadcastType) cmd["bt"].as<uint8_t>();
VideoBroadcastOptions options;
auto result = this->server->rtc_server().client_broadcast_video_config(this->rtc_client_id, broadcast_type, &options);
switch(result) {
case rtc::VideoBroadcastConfigureResult::Success:
break;
case rtc::VideoBroadcastConfigureResult::InvalidBroadcast:
return ts::command_result{error::broadcast_invalid_id};
case rtc::VideoBroadcastConfigureResult::InvalidBroadcastType:
return ts::command_result{error::broadcast_invalid_type};
case rtc::VideoBroadcastConfigureResult::InvalidClient:
return ts::command_result{error::client_invalid_id};
case rtc::VideoBroadcastConfigureResult::UnknownError:
default:
return ts::command_result{error::vs_critical};
}
ts::command_builder notify{this->notify_response_command("notifybroadcastvideoconfig")};
notify.put_unchecked(0, "bt", (uint8_t) broadcast_type);
notify.put_unchecked(0, "broadcast_keyframe_interval", options.keyframe_interval);
notify.put_unchecked(0, "broadcast_bitrate_max", options.bitrate);
this->sendCommand(notify);
return ts::command_result{error::ok};
}
inline command_result broadcast_config_result_to_command_result(rtc::VideoBroadcastConfigureResult result) {
switch(result) {
case rtc::VideoBroadcastConfigureResult::Success:
return ts::command_result{error::ok};
case rtc::VideoBroadcastConfigureResult::InvalidBroadcast:
return ts::command_result{error::broadcast_invalid_id};
case rtc::VideoBroadcastConfigureResult::InvalidBroadcastType:
return ts::command_result{error::broadcast_invalid_type};
case rtc::VideoBroadcastConfigureResult::InvalidClient:
return ts::command_result{error::client_invalid_id};
case rtc::VideoBroadcastConfigureResult::UnknownError:
default:
return ts::command_result{error::vs_critical};
}
}
command_result SpeakingClient::handleCommandBroadcastVideoConfigure(Command &cmd) {
CMD_REQ_SERVER;
auto broadcast_type = (rtc::VideoBroadcastType) cmd["bt"].as<uint8_t>();
VideoBroadcastOptions current_options;
auto query_result = this->server->rtc_server().client_broadcast_video_config(this->rtc_client_id, broadcast_type, &current_options);
if(query_result != rtc::VideoBroadcastConfigureResult::Success) {
return broadcast_config_result_to_command_result(query_result);
}
VideoBroadcastOptions options;
memset(&options, 0, sizeof(options));
{
ts::command_result result;
result.reset(parse_broadcast_options(cmd[0], options, false));
if(result.has_error()) {
return result;
}
simplify_broadcast_options(current_options, options);
result.reset(test_broadcast_options(*this, this->getChannelId(), options));
if(result.has_error()) {
return result;
}
result.release_data();
}
{
auto result = test_broadcast_options(*this, this->getChannelId(), options);
if(result.has_error()) {
return result;
}
result.release_data();
}
auto result = this->server->rtc_server().client_broadcast_video_configure(this->rtc_client_id, broadcast_type, &options);
return broadcast_config_result_to_command_result(result);
} }

View File

@ -70,9 +70,13 @@ namespace ts::server {
virtual command_result handleCommandRtcSessionDescribe(Command &command); virtual command_result handleCommandRtcSessionDescribe(Command &command);
virtual command_result handleCommandRtcSessionReset(Command &command); virtual command_result handleCommandRtcSessionReset(Command &command);
virtual command_result handleCommandRtcIceCandidate(Command &); virtual command_result handleCommandRtcIceCandidate(Command &);
virtual command_result handleCommandRtcBroadcast(Command &); virtual command_result handleCommandRtcBroadcast(Command &); /* Old method used 'till 1.5.0b4 */
virtual command_result handleCommandBroadcastAudio(Command &);
virtual command_result handleCommandBroadcastVideo(Command &);
virtual command_result handleCommandBroadcastVideoJoin(Command &); virtual command_result handleCommandBroadcastVideoJoin(Command &);
virtual command_result handleCommandBroadcastVideoLeave(Command &); virtual command_result handleCommandBroadcastVideoLeave(Command &);
virtual command_result handleCommandBroadcastVideoConfig(Command &);
virtual command_result handleCommandBroadcastVideoConfigure(Command &);
void triggerVoiceEnd(); void triggerVoiceEnd();
inline void updateSpeak(bool onlyUpdate, const std::chrono::system_clock::time_point &time); inline void updateSpeak(bool onlyUpdate, const std::chrono::system_clock::time_point &time);

View File

@ -156,6 +156,8 @@ inline bool permission_require_granted_value(ts::permission::PermissionType type
case permission::i_client_ban_max_bantime: case permission::i_client_ban_max_bantime:
case permission::i_client_max_idletime: case permission::i_client_max_idletime:
case permission::i_group_sort_id: case permission::i_group_sort_id:
case permission::i_video_max_kbps:
return false; return false;
default: default:
return true; return true;

View File

@ -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 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_DATABASE_VERSION 17
#define CURRENT_PERMISSION_VERSION 7 #define CURRENT_PERMISSION_VERSION 8
#define CLIENT_UID_LENGTH "64" #define CLIENT_UID_LENGTH "64"
#define CLIENT_NAME_LENGTH "128" #define CLIENT_NAME_LENGTH "128"
@ -841,6 +841,7 @@ bool SqlDataManager::update_permissions(std::string &error) {
if(!auto_update(permission::update::type, name, {value, value != permNotGranted}, false, false, {granted, granted != permNotGranted})) \ if(!auto_update(permission::update::type, name, {value, value != permNotGranted}, false, false, {granted, granted != permNotGranted})) \
return false; return false;
/* Attention: Due to a mistake the "i_video_max_kbps" permission has bit and not kbit values. In version 7 we divide by 1000. */
do_auto_update(QUERY_ADMIN, "b_video_screen", 1, 100); 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, "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_kbps", 20 * 1000 * 1000, 100);
@ -871,6 +872,14 @@ if(!auto_update(permission::update::type, name, {value, value != permNotGranted}
perm_version(7); perm_version(7);
case 7:
result = sql::command(this->sql(), "UPDATE `permissions` SET `value` = `value` / 1000 WHERE permId = 'i_video_max_kbps'").execute();
if(!result) {
LOG_SQL_CMD(result);
return false;
}
perm_version(8);
default: default:
break; break;
} }

View File

@ -45,6 +45,15 @@ struct RtpClientConfigureOptions {
uint16_t stun_port; uint16_t stun_port;
}; };
struct VideoBroadcastOptions {
constexpr static auto kOptionBitrate{0x01};
constexpr static auto kOptionKeyframeInterval{0x02};
uint32_t update_mask;
uint32_t bitrate;
uint32_t keyframe_interval;
};
extern const char* librtc_version(); extern const char* librtc_version();
extern void librtc_free_str(const char* /* ptr */); extern void librtc_free_str(const char* /* ptr */);
@ -79,14 +88,21 @@ extern void librtc_destroy_audio_source_supplier(void* /* sender */);
extern uint32_t librtc_create_channel(void* /* server */); 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_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 void librtc_destroy_channel(void* /* server */, uint32_t /* channel */);
/* Audio functions */
extern uint32_t librtc_client_broadcast_audio(void* /* server */, uint32_t /* client id */, uint32_t /* stream id */);
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 */); 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 */);
extern void librtc_whisper_reset(void* /* server */, uint32_t /* client id */); extern void librtc_whisper_reset(void* /* server */, uint32_t /* client id */);
/* Video functions */
extern uint32_t librtc_client_broadcast_video(void* /* server */, uint32_t /* client id */, uint8_t /* broadcast type */, uint32_t /* stream id */, const VideoBroadcastOptions* /* options */);
extern uint32_t librtc_client_broadcast_video_configure(void* /* callback data */, uint32_t /* client id */, uint8_t /* broadcast type */, const VideoBroadcastOptions* /* options */);
extern uint32_t librtc_client_broadcast_video_config(void* /* callback data */, uint32_t /* client id */, uint8_t /* broadcast type */, VideoBroadcastOptions* /* options */);
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 */);
#ifdef __cplusplus #ifdef __cplusplus
}; };
#endif #endif

View File

@ -324,6 +324,30 @@ bool Server::client_video_stream_count(uint32_t client_id, uint32_t *camera, uin
return librtc_client_video_stream_count(this->server_ptr, client_id, camera, desktop) == 0; return librtc_client_video_stream_count(this->server_ptr, client_id, camera, desktop) == 0;
} }
VideoBroadcastConfigureResult Server::client_broadcast_video_configure(RTCClientId client_id, VideoBroadcastType broadcast_type,
const VideoBroadcastOptions *options) {
auto result = librtc_client_broadcast_video_configure(this->server_ptr, client_id, (uint8_t) broadcast_type, options);
switch(result) {
case 0x00: return VideoBroadcastConfigureResult::Success;
case 0x01: return VideoBroadcastConfigureResult::InvalidBroadcastType;
case 0x02: return VideoBroadcastConfigureResult::InvalidClient;
case 0x03: return VideoBroadcastConfigureResult::InvalidBroadcast;
default: return VideoBroadcastConfigureResult::UnknownError;
}
}
VideoBroadcastConfigureResult Server::client_broadcast_video_config(RTCClientId client_id, VideoBroadcastType broadcast_type,
VideoBroadcastOptions *options) {
auto result = librtc_client_broadcast_video_config(this->server_ptr, client_id, (uint8_t) broadcast_type, options);
switch(result) {
case 0x00: return VideoBroadcastConfigureResult::Success;
case 0x01: return VideoBroadcastConfigureResult::InvalidBroadcastType;
case 0x02: return VideoBroadcastConfigureResult::InvalidClient;
case 0x03: return VideoBroadcastConfigureResult::InvalidBroadcast;
default: return VideoBroadcastConfigureResult::UnknownError;
}
}
void Server::reset_rtp_session(RTCClientId client_id) { void Server::reset_rtp_session(RTCClientId client_id) {
librtc_reset_rtp_session(this->server_ptr, client_id); librtc_reset_rtp_session(this->server_ptr, client_id);
} }
@ -368,7 +392,7 @@ uint32_t Server::create_channel() {
return librtc_create_channel(this->server_ptr); return librtc_create_channel(this->server_ptr);
} }
ChannelAssignResult Server::assign_channel(uint32_t client_id, uint32_t channel_id) { ChannelAssignResult Server::assign_channel(RTCClientId client_id, RTCChannelId channel_id) {
auto result = librtc_assign_channel(this->server_ptr, client_id, channel_id); auto result = librtc_assign_channel(this->server_ptr, client_id, channel_id);
switch(result) { switch(result) {
case 0x00: return ChannelAssignResult::Success; case 0x00: return ChannelAssignResult::Success;
@ -378,8 +402,22 @@ ChannelAssignResult Server::assign_channel(uint32_t client_id, uint32_t channel_
} }
} }
BroadcastStartResult Server::start_broadcast(uint32_t client_id, uint8_t btype, uint32_t track_id) { BroadcastStartResult Server::start_broadcast_audio(RTCClientId client_id, RTCStreamId track_id) {
auto result = librtc_client_broadcast(this->server_ptr, client_id, btype, track_id); auto result = librtc_client_broadcast_audio(this->server_ptr, client_id, track_id);
switch(result) {
case 0x00: return BroadcastStartResult::Success;
case 0x01: return BroadcastStartResult::InvalidClient;
case 0x02: return BroadcastStartResult::ClientHasNoChannel;
case 0x03: return BroadcastStartResult::InvalidBroadcastType;
case 0x04: return BroadcastStartResult::InvalidStreamId;
default:
logCritical(LOG_GENERAL, "Audio broadcast start returned unknown error code: {}", result);
return BroadcastStartResult::UnknownError;
}
}
BroadcastStartResult Server::start_broadcast_video(RTCClientId client_id, VideoBroadcastType broadcast_type, RTCStreamId track_id, const VideoBroadcastOptions* options) {
auto result = librtc_client_broadcast_video(this->server_ptr, client_id, (uint8_t) broadcast_type, track_id, options);
switch(result) { switch(result) {
case 0x00: return BroadcastStartResult::Success; case 0x00: return BroadcastStartResult::Success;
case 0x01: return BroadcastStartResult::InvalidClient; case 0x01: return BroadcastStartResult::InvalidClient;

View File

@ -8,6 +8,8 @@ namespace ts::server {
class SpeakingClient; class SpeakingClient;
} }
struct VideoBroadcastOptions;
namespace ts::rtc { namespace ts::rtc {
typedef uint32_t RTCClientId; typedef uint32_t RTCClientId;
typedef uint32_t RTCChannelId; typedef uint32_t RTCChannelId;
@ -45,6 +47,14 @@ namespace ts::rtc {
UnknownError UnknownError
}; };
enum struct VideoBroadcastConfigureResult {
Success,
InvalidClient,
InvalidBroadcast, /* Client might not be broadcasting */
InvalidBroadcastType,
UnknownError
};
class NativeAudioSourceSupplier; class NativeAudioSourceSupplier;
class Server { class Server {
public: public:
@ -71,14 +81,21 @@ namespace ts::rtc {
/* channel actions */ /* channel actions */
uint32_t create_channel(); uint32_t create_channel();
ChannelAssignResult assign_channel(RTCClientId /* client id */, RTCChannelId /* channel id */); 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 */); void destroy_channel(RTCChannelId /* channel id */);
/* whisper actions */ /* Audio */
BroadcastStartResult start_broadcast_audio(RTCClientId /* client id */, RTCStreamId /* stream id */);
bool configure_whisper_session(std::string& /* error */, RTCClientId /* client id */, uint32_t /* source stream id */, RTCClientId* /* session members */, size_t /* session member count */); bool configure_whisper_session(std::string& /* error */, RTCClientId /* client id */, uint32_t /* source stream id */, RTCClientId* /* session members */, size_t /* session member count */);
void reset_whisper_session(RTCClientId /* client id */); void reset_whisper_session(RTCClientId /* client id */);
/* Video */
BroadcastStartResult start_broadcast_video(RTCClientId /* client id */, VideoBroadcastType /* broadcast type */, RTCStreamId /* stream id */, const VideoBroadcastOptions* /* options */);
VideoBroadcastConfigureResult client_broadcast_video_configure(RTCClientId /* client id */, VideoBroadcastType /* broadcast type */, const VideoBroadcastOptions* /* options */);
VideoBroadcastConfigureResult client_broadcast_video_config(RTCClientId /* client id */, VideoBroadcastType /* broadcast type */, VideoBroadcastOptions* /* options */);
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 */);
private: private:
void* server_ptr{nullptr}; void* server_ptr{nullptr};
}; };