mirror of
https://github.com/godotengine/webrtc-native.git
synced 2026-01-01 05:48:15 +03:00
Fix name collision, scons file, final touches
This commit is contained in:
@@ -111,12 +111,12 @@ elif target_platform == "windows":
|
||||
# Mostly VisualStudio
|
||||
if env["CC"] == "cl":
|
||||
env.Append(CCFLAGS=["/DWEBRTC_WIN", "/DWIN32_LEAN_AND_MEAN", "/DNOMINMAX", "/DRTC_UNUSED=", "/DNO_RETURN="])
|
||||
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", lib_name]])
|
||||
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]])
|
||||
env.Append(LIBPATH=[lib_path])
|
||||
# Mostly "gcc"
|
||||
else:
|
||||
env.Append(CCFLAGS=["-DWINVER=0x0603", "-D_WIN32_WINNT=0x0603", "-DWEBRTC_WIN", "-DWIN32_LEAN_AND_MEAN", "-DNOMINMAX", "-DRTC_UNUSED=", "-DNO_RETURN="])
|
||||
env.Append(LIBS=["secur32", lib_name])
|
||||
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in ["secur32", "advapi32", "winmm", lib_name]])
|
||||
env.Append(LIBPATH=[lib_path])
|
||||
|
||||
elif target_platform == "osx":
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCPeer::GodotCSDO::GodotCSDO(WebRTCPeer *parent) {
|
||||
WebRTCLibPeer::GodotCSDO::GodotCSDO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
|
||||
void WebRTCLibPeer::GodotCSDO::OnSuccess(webrtc::SessionDescriptionInterface *desc) {
|
||||
// serialize this offer and send it to the remote peer:
|
||||
std::string sdp; // sdp = session description protocol
|
||||
desc->ToString(&sdp);
|
||||
parent->queue_signal("offer_created", 2, desc->type().c_str(), sdp.c_str());
|
||||
};
|
||||
|
||||
void WebRTCPeer::GodotCSDO::OnFailure(const std::string &error){};
|
||||
void WebRTCLibPeer::GodotCSDO::OnFailure(const std::string &error){};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCPeer::GodotDCO::GodotDCO(WebRTCPeer *parent) {
|
||||
WebRTCLibPeer::GodotDCO::GodotDCO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) {
|
||||
void WebRTCLibPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) {
|
||||
const uint8_t *data = buffer.data.data<uint8_t>();
|
||||
uint8_t *memory_controlled_buffer = new uint8_t[buffer.data.size()];
|
||||
|
||||
@@ -14,6 +14,6 @@ void WebRTCPeer::GodotDCO::OnMessage(const webrtc::DataBuffer &buffer) {
|
||||
parent->queue_packet(memory_controlled_buffer, buffer.data.size());
|
||||
};
|
||||
|
||||
void WebRTCPeer::GodotDCO::OnStateChange(){};
|
||||
void WebRTCLibPeer::GodotDCO::OnStateChange(){};
|
||||
|
||||
void WebRTCPeer::GodotDCO::OnBufferedAmountChange(uint64_t previous_amount){};
|
||||
void WebRTCLibPeer::GodotDCO::OnBufferedAmountChange(uint64_t previous_amount){};
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCPeer::GodotPCO::GodotPCO(WebRTCPeer *parent) {
|
||||
WebRTCLibPeer::GodotPCO::GodotPCO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
|
||||
void WebRTCLibPeer::GodotPCO::OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
void WebRTCLibPeer::GodotPCO::OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
void WebRTCLibPeer::GodotPCO::OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
||||
void WebRTCLibPeer::GodotPCO::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnRenegotiationNeeded() {
|
||||
void WebRTCLibPeer::GodotPCO::OnRenegotiationNeeded() {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
|
||||
void WebRTCLibPeer::GodotPCO::OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
|
||||
void WebRTCLibPeer::GodotPCO::OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) {
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
|
||||
void WebRTCLibPeer::GodotPCO::OnIceCandidate(const webrtc::IceCandidateInterface *candidate) {
|
||||
// Serialize the candidate and send it to the remote peer:
|
||||
|
||||
godot::Dictionary candidateSDP;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
WebRTCPeer::GodotSSDO::GodotSSDO(WebRTCPeer *parent) {
|
||||
WebRTCLibPeer::GodotSSDO::GodotSSDO(WebRTCLibPeer *parent) {
|
||||
this->parent = parent;
|
||||
}
|
||||
|
||||
void WebRTCPeer::GodotSSDO::OnSuccess(){};
|
||||
void WebRTCLibPeer::GodotSSDO::OnSuccess(){};
|
||||
|
||||
void WebRTCPeer::GodotSSDO::OnFailure(const std::string &error){};
|
||||
void WebRTCLibPeer::GodotSSDO::OnFailure(const std::string &error){};
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
|
||||
using namespace godot_webrtc;
|
||||
|
||||
void WebRTCPeer::set_write_mode(godot_int mode) {
|
||||
void WebRTCLibPeer::set_write_mode(godot_int mode) {
|
||||
}
|
||||
|
||||
godot_int WebRTCPeer::get_write_mode() const {
|
||||
godot_int WebRTCLibPeer::get_write_mode() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool WebRTCPeer::was_string_packet() const {
|
||||
bool WebRTCLibPeer::was_string_packet() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
godot_int WebRTCPeer::get_connection_state() const {
|
||||
godot_int WebRTCLibPeer::get_connection_state() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::create_offer() {
|
||||
godot_error WebRTCLibPeer::create_offer() {
|
||||
peer_connection->CreateOffer(
|
||||
ptr_csdo, // CreateSessionDescriptionObserver* observer,
|
||||
nullptr // webrtc::PeerConnectionInterface::RTCOfferAnswerOptions() // const MediaConstraintsInterface* constraints
|
||||
@@ -25,17 +25,17 @@ godot_error WebRTCPeer::create_offer() {
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::set_remote_description(const char *type, const char *sdp) {
|
||||
godot_error WebRTCLibPeer::set_remote_description(const char *type, const char *sdp) {
|
||||
godot_error err = set_description(type, sdp, false); //false meaning !isLocal because it is remote
|
||||
peer_connection->CreateAnswer(ptr_csdo, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions());
|
||||
return err;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::set_local_description(const char *type, const char *sdp) {
|
||||
godot_error WebRTCLibPeer::set_local_description(const char *type, const char *sdp) {
|
||||
return set_description(type, sdp, true); // isLocal == true
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
|
||||
godot_error WebRTCLibPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIndexName, const char *sdpName) {
|
||||
webrtc::SdpParseError *error = nullptr;
|
||||
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
|
||||
sdpMidName,
|
||||
@@ -52,7 +52,7 @@ godot_error WebRTCPeer::add_ice_candidate(const char *sdpMidName, int sdpMlineIn
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::poll() {
|
||||
godot_error WebRTCLibPeer::poll() {
|
||||
std::function<void()> signal;
|
||||
while (!signal_queue.empty()) {
|
||||
mutex_signal_queue->lock();
|
||||
@@ -65,13 +65,13 @@ godot_error WebRTCPeer::poll() {
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::get_packet(const uint8_t **r_buffer, int &r_len) {
|
||||
godot_error WebRTCLibPeer::get_packet(const uint8_t **r_buffer, int *r_len) {
|
||||
if (packet_queue_size == 0)
|
||||
return GODOT_ERR_UNAVAILABLE;
|
||||
mutex_packet_queue->lock();
|
||||
uint8_t *current_packet = packet_queue.front();
|
||||
*r_buffer = current_packet;
|
||||
r_len = packet_sizes_queue.front();
|
||||
*r_len = packet_sizes_queue.front();
|
||||
|
||||
packet_queue.pop();
|
||||
packet_sizes_queue.pop();
|
||||
@@ -81,24 +81,24 @@ godot_error WebRTCPeer::get_packet(const uint8_t **r_buffer, int &r_len) {
|
||||
return GODOT_OK;
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::put_packet(const uint8_t *p_buffer, int p_len) {
|
||||
godot_error WebRTCLibPeer::put_packet(const uint8_t *p_buffer, int p_len) {
|
||||
webrtc::DataBuffer webrtc_buffer(rtc::CopyOnWriteBuffer(p_buffer, p_len), true);
|
||||
data_channel->Send(webrtc_buffer);
|
||||
return GODOT_OK; // @TODO properly return any Error we may get.
|
||||
}
|
||||
|
||||
godot_int WebRTCPeer::get_available_packet_count() const {
|
||||
godot_int WebRTCLibPeer::get_available_packet_count() const {
|
||||
return packet_queue_size;
|
||||
}
|
||||
|
||||
godot_int WebRTCPeer::get_max_packet_size() const {
|
||||
godot_int WebRTCLibPeer::get_max_packet_size() const {
|
||||
return 1200;
|
||||
}
|
||||
|
||||
void WebRTCPeer::_register_methods() {
|
||||
void WebRTCLibPeer::_register_methods() {
|
||||
}
|
||||
|
||||
void WebRTCPeer::_init() {
|
||||
void WebRTCLibPeer::_init() {
|
||||
register_interface(&interface);
|
||||
|
||||
// initialize variables:
|
||||
@@ -118,7 +118,7 @@ void WebRTCPeer::_init() {
|
||||
nullptr // std::unique_ptr<RtcEventLogFactoryInterface> event_log_factory
|
||||
);
|
||||
if (pc_factory.get() == nullptr) { // PeerConnectionFactory couldn't be created. Fail the method call.
|
||||
godot_print_error("PeerConnectionFactory could not be created", "_init", "WebRTCPeer.cpp", 80);
|
||||
ERR_PRINT("PeerConnectionFactory could not be created");
|
||||
// return GODOT_FAILED;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ void WebRTCPeer::_init() {
|
||||
// create a PeerConnection object:
|
||||
peer_connection = pc_factory->CreatePeerConnection(configuration, nullptr, nullptr, &pco);
|
||||
if (peer_connection.get() == nullptr) { // PeerConnection couldn't be created. Fail the method call.
|
||||
godot_print_error("PeerConnection could not be created", "_init", "WebRTCPeer.cpp", 101);
|
||||
ERR_PRINT("PeerConnection could not be created");
|
||||
// return GODOT_FAILED;
|
||||
}
|
||||
|
||||
@@ -146,14 +146,14 @@ void WebRTCPeer::_init() {
|
||||
data_channel->RegisterObserver(&dco);
|
||||
}
|
||||
|
||||
WebRTCPeer::WebRTCPeer() :
|
||||
WebRTCLibPeer::WebRTCLibPeer() :
|
||||
dco(this),
|
||||
pco(this),
|
||||
ptr_csdo(new rtc::RefCountedObject<GodotCSDO>(this)),
|
||||
ptr_ssdo(new rtc::RefCountedObject<GodotSSDO>(this)) {
|
||||
}
|
||||
|
||||
WebRTCPeer::~WebRTCPeer() {
|
||||
WebRTCLibPeer::~WebRTCLibPeer() {
|
||||
if (_owner) {
|
||||
register_interface(NULL);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ WebRTCPeer::~WebRTCPeer() {
|
||||
delete mutex_packet_queue;
|
||||
}
|
||||
|
||||
void WebRTCPeer::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
|
||||
void WebRTCLibPeer::queue_signal(godot::String p_name, int p_argc, const godot::Variant &p_arg1, const godot::Variant &p_arg2, const godot::Variant &p_arg3) {
|
||||
mutex_signal_queue->lock();
|
||||
signal_queue.push(
|
||||
[this, p_name, p_argc, p_arg1, p_arg2, p_arg3] {
|
||||
@@ -173,7 +173,7 @@ void WebRTCPeer::queue_signal(godot::String p_name, int p_argc, const godot::Var
|
||||
mutex_signal_queue->unlock();
|
||||
}
|
||||
|
||||
void WebRTCPeer::queue_packet(uint8_t *buffer, int buffer_size) {
|
||||
void WebRTCLibPeer::queue_packet(uint8_t *buffer, int buffer_size) {
|
||||
mutex_packet_queue->lock();
|
||||
packet_queue.push(buffer);
|
||||
packet_sizes_queue.push(buffer_size);
|
||||
@@ -181,7 +181,7 @@ void WebRTCPeer::queue_packet(uint8_t *buffer, int buffer_size) {
|
||||
mutex_packet_queue->unlock();
|
||||
}
|
||||
|
||||
godot_error WebRTCPeer::set_description(const char *type, const char *sdp, bool isLocal) {
|
||||
godot_error WebRTCLibPeer::set_description(const char *type, const char *sdp, bool isLocal) {
|
||||
// webrtc::SdpType type = (isOffer) ? webrtc::SdpType::kOffer : webrtc::SdpType::kAnswer;
|
||||
godot::String string_sdp = sdp;
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
|
||||
#include "api/peerconnectioninterface.h" // interface for all things needed from WebRTC
|
||||
#include "media/base/mediaengine.h" // needed for CreateModularPeerConnectionFactory
|
||||
#ifdef interface
|
||||
#pragma message("\n 'interface' is defined \n")
|
||||
#undef interface
|
||||
#endif // interface
|
||||
|
||||
#include <functional> // std::function
|
||||
#include <mutex> // mutex @TODO replace std::mutex with Godot mutex
|
||||
|
||||
@@ -16,8 +11,8 @@
|
||||
|
||||
namespace godot_webrtc {
|
||||
|
||||
class WebRTCPeer : public WebRTCPeerNative {
|
||||
GODOT_CLASS(WebRTCPeer, WebRTCPeerNative);
|
||||
class WebRTCLibPeer : public WebRTCPeerNative {
|
||||
GODOT_CLASS(WebRTCLibPeer, WebRTCPeerNative);
|
||||
|
||||
public:
|
||||
static void _register_methods();
|
||||
@@ -36,13 +31,13 @@ public:
|
||||
godot_error poll();
|
||||
|
||||
/* WebRTCPeer */
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int &r_len);
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len);
|
||||
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len);
|
||||
virtual godot_int get_available_packet_count() const;
|
||||
virtual godot_int get_max_packet_size() const;
|
||||
|
||||
WebRTCPeer();
|
||||
~WebRTCPeer();
|
||||
WebRTCLibPeer();
|
||||
~WebRTCLibPeer();
|
||||
|
||||
/* helper functions */
|
||||
|
||||
@@ -54,9 +49,9 @@ public:
|
||||
/** DataChannelObserver callback functions **/
|
||||
class GodotDCO : public webrtc::DataChannelObserver {
|
||||
public:
|
||||
WebRTCPeer *parent;
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotDCO(WebRTCPeer *parent);
|
||||
GodotDCO(WebRTCLibPeer *parent);
|
||||
void OnMessage(const webrtc::DataBuffer &buffer) override;
|
||||
void OnStateChange() override; // UNUSED
|
||||
void OnBufferedAmountChange(uint64_t previous_amount) override; // UNUSED
|
||||
@@ -65,9 +60,9 @@ public:
|
||||
/** PeerConnectionObserver callback functions **/
|
||||
class GodotPCO : public webrtc::PeerConnectionObserver {
|
||||
public:
|
||||
WebRTCPeer *parent;
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotPCO(WebRTCPeer *parent);
|
||||
GodotPCO(WebRTCLibPeer *parent);
|
||||
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override;
|
||||
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;
|
||||
@@ -81,9 +76,9 @@ public:
|
||||
/** CreateSessionDescriptionObserver callback functions **/
|
||||
class GodotCSDO : public webrtc::CreateSessionDescriptionObserver {
|
||||
public:
|
||||
WebRTCPeer *parent;
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotCSDO(WebRTCPeer *parent);
|
||||
GodotCSDO(WebRTCLibPeer *parent);
|
||||
void OnSuccess(webrtc::SessionDescriptionInterface *desc) override;
|
||||
void OnFailure(const std::string &error) override;
|
||||
};
|
||||
@@ -91,9 +86,9 @@ public:
|
||||
/** SetSessionDescriptionObserver callback functions **/
|
||||
class GodotSSDO : public webrtc::SetSessionDescriptionObserver {
|
||||
public:
|
||||
WebRTCPeer *parent;
|
||||
WebRTCLibPeer *parent;
|
||||
|
||||
GodotSSDO(WebRTCPeer *parent);
|
||||
GodotSSDO(WebRTCLibPeer *parent);
|
||||
void OnSuccess() override;
|
||||
void OnFailure(const std::string &error) override;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "WebRTCPeer.hpp"
|
||||
#include "WebRTCLibPeer.hpp"
|
||||
#include "net/WebRTCPeerNative.hpp"
|
||||
#include <gdnative_api_struct.gen.h>
|
||||
|
||||
@@ -21,5 +21,5 @@ extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_opt
|
||||
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
|
||||
godot::Godot::nativescript_init(handle);
|
||||
|
||||
godot::register_class<godot_webrtc::WebRTCPeer>();
|
||||
godot::register_class<godot_webrtc::WebRTCLibPeer>();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ WebRTCPeerNative::~WebRTCPeerNative() {
|
||||
* In this case it forwards calls to our C++ class, but could be plain C,
|
||||
* and you could use void *user for any kind of state struct pointer you have.
|
||||
*/
|
||||
godot_error get_packet_wp(void *user, const uint8_t **r_buffer, int &r_len) {
|
||||
godot_error get_packet_wp(void *user, const uint8_t **r_buffer, int *r_len) {
|
||||
return ((WebRTCPeerNative *)user)->get_packet(r_buffer, r_len);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <net/godot_net.h>
|
||||
|
||||
/* Forward declare interface functions */
|
||||
godot_error get_packet_wp(void *, const uint8_t **, int &);
|
||||
godot_error get_packet_wp(void *, const uint8_t **, int *);
|
||||
godot_error put_packet_wp(void *, const uint8_t *, int);
|
||||
godot_int get_available_packet_count_wp(const void *);
|
||||
godot_int get_max_packet_size_wp(const void *);
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
virtual godot_error poll() = 0;
|
||||
|
||||
/* PacketPeer */
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int &r_len) = 0;
|
||||
virtual godot_error get_packet(const uint8_t **r_buffer, int *r_len) = 0;
|
||||
virtual godot_error put_packet(const uint8_t *p_buffer, int p_len) = 0;
|
||||
virtual godot_int get_available_packet_count() const = 0;
|
||||
virtual godot_int get_max_packet_size() const = 0;
|
||||
|
||||
Reference in New Issue
Block a user