添加注释
This commit is contained in:
parent
2861cdee5f
commit
dcc9180221
@ -48,14 +48,15 @@ include_directories(/opt/homebrew/include/pango-1.0)
|
|||||||
include_directories(/opt/homebrew/include/glib-2.0)
|
include_directories(/opt/homebrew/include/glib-2.0)
|
||||||
include_directories(/opt/homebrew/include/glib-2.0/glib)
|
include_directories(/opt/homebrew/include/glib-2.0/glib)
|
||||||
include_directories(/opt/homebrew/include/atk-1.0)
|
include_directories(/opt/homebrew/include/atk-1.0)
|
||||||
include_directories(${JSONCPP_INCLUDE_DIRS})
|
#include_directories(/opt/homebrew/Cellar/ffmpeg/6.1.1_3/include)
|
||||||
|
#include_directories(${JSONCPP_INCLUDE_DIRS})
|
||||||
include_directories(${GTK3_INCLUDE_DIRS})
|
include_directories(${GTK3_INCLUDE_DIRS})
|
||||||
|
|
||||||
# 项目内
|
# 项目内
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include/absl)
|
include_directories(${CMAKE_SOURCE_DIR}/include/absl)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk)
|
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/ffmpeg)
|
#include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/ffmpeg)
|
||||||
#include_directories(/Users/dongl/tools/ffmpeg/ffmpeg_build/include)
|
#include_directories(/Users/dongl/tools/ffmpeg/ffmpeg_build/include)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/harfbuzz-ng/src/src)
|
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/harfbuzz-ng/src/src)
|
||||||
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/libyuv/include)
|
include_directories(${CMAKE_SOURCE_DIR}/include/webrtc_cxx_sdk/third_party/libyuv/include)
|
||||||
@ -73,7 +74,7 @@ message( ${AVFOUNDATION_LIBRARY})
|
|||||||
# 链接库
|
# 链接库
|
||||||
link_directories(${CMAKE_SOURCE_DIR}/lib/arm_macos)
|
link_directories(${CMAKE_SOURCE_DIR}/lib/arm_macos)
|
||||||
link_directories(/opt/homebrew/lib)
|
link_directories(/opt/homebrew/lib)
|
||||||
link_directories(/opt/homebrew/Cellar/ffmpeg/6.0_1/lib)
|
#link_directories(/opt/homebrew/Cellar/ffmpeg/6.1.1_3/lib)
|
||||||
#link_directories(/Users/dongl/tools/ffmpeg/ffmpeg_build/lib)
|
#link_directories(/Users/dongl/tools/ffmpeg/ffmpeg_build/lib)
|
||||||
|
|
||||||
add_subdirectory(src/client)
|
add_subdirectory(src/client)
|
||||||
|
@ -24,7 +24,7 @@ target_link_libraries(client
|
|||||||
|
|
||||||
PkgConfig::FFMPEG
|
PkgConfig::FFMPEG
|
||||||
|
|
||||||
gtk-3 gdk-3 pangocairo-1.0 pango-1.0 harfbuzz atk-1.0 cairo-gobject cairo gdk_pixbuf-2.0 gio-2.0 gobject-2.0 glib-2.0
|
gtk-3 gdk-3 cairo gobject-2.0 glib-2.0
|
||||||
|
|
||||||
${COCOA_LIBRARY}
|
${COCOA_LIBRARY}
|
||||||
${CORE_AUDIO_LIBRARY}
|
${CORE_AUDIO_LIBRARY}
|
||||||
|
@ -74,7 +74,9 @@ namespace {
|
|||||||
static rtc::scoped_refptr<DummySetSessionDescriptionObserver> Create() {
|
static rtc::scoped_refptr<DummySetSessionDescriptionObserver> Create() {
|
||||||
return rtc::make_ref_counted<DummySetSessionDescriptionObserver>();
|
return rtc::make_ref_counted<DummySetSessionDescriptionObserver>();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void OnSuccess() { RTC_LOG(LS_INFO) << __FUNCTION__; }
|
virtual void OnSuccess() { RTC_LOG(LS_INFO) << __FUNCTION__; }
|
||||||
|
|
||||||
virtual void OnFailure(webrtc::RTCError error) {
|
virtual void OnFailure(webrtc::RTCError error) {
|
||||||
RTC_LOG(LS_INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": "
|
RTC_LOG(LS_INFO) << __FUNCTION__ << " " << ToString(error.type()) << ": "
|
||||||
<< error.message();
|
<< error.message();
|
||||||
@ -114,6 +116,7 @@ namespace {
|
|||||||
rtc::VideoSourceInterface<webrtc::VideoFrame> *source() override {
|
rtc::VideoSourceInterface<webrtc::VideoFrame> *source() override {
|
||||||
return capturer_.get();
|
return capturer_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<webrtc::VcmCapturer> capturer_;
|
std::unique_ptr<webrtc::VcmCapturer> capturer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "rtc_base/win32.h"
|
#include "rtc_base/win32.h"
|
||||||
#endif // WEBRTC_WIN
|
#endif // WEBRTC_WIN
|
||||||
|
|
||||||
|
// 抽象回调
|
||||||
class MainWndCallback {
|
class MainWndCallback {
|
||||||
public:
|
public:
|
||||||
// 通知登陆信令服务器
|
// 通知登陆信令服务器
|
||||||
@ -37,7 +38,7 @@ public:
|
|||||||
virtual void DisconnectFromCurrentPeer() = 0;
|
virtual void DisconnectFromCurrentPeer() = 0;
|
||||||
// 自定义消息处理函数
|
// 自定义消息处理函数
|
||||||
virtual void UIThreadCallback(int msg_id, void *data) = 0;
|
virtual void UIThreadCallback(int msg_id, void *data) = 0;
|
||||||
// 关闭conductor
|
// 关闭
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -45,41 +46,32 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Pure virtual interface for the main window.
|
// Pure virtual interface for the main window.
|
||||||
|
// 主窗口基类
|
||||||
class MainWindow {
|
class MainWindow {
|
||||||
public:
|
public:
|
||||||
virtual ~MainWindow() {}
|
virtual ~MainWindow() {}
|
||||||
|
|
||||||
|
// 当前的UI界面
|
||||||
enum UI {
|
enum UI {
|
||||||
CONNECT_TO_SERVER,
|
CONNECT_TO_SERVER, // 链接至服务器页面
|
||||||
LIST_PEERS,
|
LIST_PEERS, // PEER双端通讯列表的页面
|
||||||
STREAMING,
|
STREAMING, // 流媒体对话的页面
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 注册抽象回调函数集结构体
|
||||||
virtual void RegisterObserver(MainWndCallback *callback) = 0;
|
virtual void RegisterObserver(MainWndCallback *callback) = 0;
|
||||||
|
// 窗口是否有效?
|
||||||
virtual bool IsWindow() = 0;
|
virtual bool IsWindow() = 0;
|
||||||
|
|
||||||
virtual void MessageBox(const char *caption,
|
virtual void MessageBox(const char *caption,const char *text,bool is_error) = 0;
|
||||||
const char *text,
|
|
||||||
bool is_error) = 0;
|
|
||||||
|
|
||||||
virtual UI current_ui() = 0;
|
virtual UI current_ui() = 0;
|
||||||
|
|
||||||
virtual void SwitchToConnectUI() = 0;
|
virtual void SwitchToConnectUI() = 0;
|
||||||
|
|
||||||
virtual void SwitchToPeerList(const Peers &peers) = 0;
|
virtual void SwitchToPeerList(const Peers &peers) = 0;
|
||||||
|
|
||||||
virtual void SwitchToStreamingUI() = 0;
|
virtual void SwitchToStreamingUI() = 0;
|
||||||
|
|
||||||
virtual void StartLocalRenderer(webrtc::VideoTrackInterface *local_video) = 0;
|
virtual void StartLocalRenderer(webrtc::VideoTrackInterface *local_video) = 0;
|
||||||
|
|
||||||
virtual void StopLocalRenderer() = 0;
|
virtual void StopLocalRenderer() = 0;
|
||||||
|
virtual void StartRemoteRenderer(webrtc::VideoTrackInterface *remote_video) = 0;
|
||||||
virtual void StartRemoteRenderer(
|
|
||||||
webrtc::VideoTrackInterface *remote_video) = 0;
|
|
||||||
|
|
||||||
virtual void StopRemoteRenderer() = 0;
|
virtual void StopRemoteRenderer() = 0;
|
||||||
|
|
||||||
virtual void QueueUIThreadCallback(int msg_id, void *data) = 0;
|
virtual void QueueUIThreadCallback(int msg_id, void *data) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,6 +69,7 @@ void PeerConnectionClient::RegisterObserver(
|
|||||||
callback_ = callback;
|
callback_ = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 链接服务器
|
||||||
void PeerConnectionClient::Connect(const std::string &server,
|
void PeerConnectionClient::Connect(const std::string &server,
|
||||||
int port,
|
int port,
|
||||||
const std::string &client_name) {
|
const std::string &client_name) {
|
||||||
@ -77,50 +78,59 @@ void PeerConnectionClient::Connect(const std::string& server,
|
|||||||
|
|
||||||
if (state_ != NOT_CONNECTED) {
|
if (state_ != NOT_CONNECTED) {
|
||||||
RTC_LOG(LS_WARNING)
|
RTC_LOG(LS_WARNING)
|
||||||
|
// 在调用 Connect() 之前,客户端不得连接
|
||||||
<< "The client must not be connected before you can call Connect()";
|
<< "The client must not be connected before you can call Connect()";
|
||||||
callback_->OnServerConnectionFailure();
|
callback_->OnServerConnectionFailure();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server.empty() || client_name.empty()) {
|
if (server.empty() || client_name.empty()) {
|
||||||
callback_->OnServerConnectionFailure();
|
callback_->OnServerConnectionFailure(); // 链接失败
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port <= 0)
|
if (port <= 0)
|
||||||
port = kDefaultServerPort;
|
port = kDefaultServerPort; // 默认值8888
|
||||||
|
|
||||||
|
// 设置地址端口客户端名称
|
||||||
server_address_.SetIP(server);
|
server_address_.SetIP(server);
|
||||||
server_address_.SetPort(port);
|
server_address_.SetPort(port);
|
||||||
client_name_ = client_name;
|
client_name_ = client_name;
|
||||||
|
|
||||||
|
// ip 是否正确 未解析ip
|
||||||
if (server_address_.IsUnresolvedIP()) {
|
if (server_address_.IsUnresolvedIP()) {
|
||||||
state_ = RESOLVING;
|
state_ = RESOLVING; // 状态解决?
|
||||||
resolver_ = new rtc::AsyncResolver();
|
resolver_ = new rtc::AsyncResolver();
|
||||||
|
// SignalDone 当地址解析过程完成时会触发此信号。
|
||||||
|
// 解析结果 类指针 成员函数指针
|
||||||
resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult);
|
resolver_->SignalDone.connect(this, &PeerConnectionClient::OnResolveResult);
|
||||||
|
// AsyncResolver 将执行异步 DNS 解析,并在上发送结果信号
|
||||||
resolver_->Start(server_address_);
|
resolver_->Start(server_address_);
|
||||||
} else {
|
} else {
|
||||||
DoConnect();
|
DoConnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerConnectionClient::OnResolveResult(
|
void PeerConnectionClient::OnResolveResult(rtc::AsyncResolverInterface *resolver) {
|
||||||
rtc::AsyncResolverInterface* resolver) {
|
|
||||||
if (resolver_->GetError() != 0) {
|
if (resolver_->GetError() != 0) {
|
||||||
callback_->OnServerConnectionFailure();
|
callback_->OnServerConnectionFailure(); // 链接失败
|
||||||
resolver_->Destroy(false);
|
resolver_->Destroy(false);
|
||||||
resolver_ = NULL;
|
resolver_ = nullptr;
|
||||||
state_ = NOT_CONNECTED;
|
state_ = NOT_CONNECTED; // 状态未链接
|
||||||
} else {
|
} else {
|
||||||
|
// 这里有重复检验了一下 因为进入此函数的先决条件是为解析ip
|
||||||
server_address_ = resolver_->address();
|
server_address_ = resolver_->address();
|
||||||
DoConnect();
|
DoConnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 执行链接 链接时 做链接 进行链接 真正执行链接的函数
|
||||||
void PeerConnectionClient::DoConnect() {
|
void PeerConnectionClient::DoConnect() {
|
||||||
control_socket_.reset(CreateClientSocket(server_address_.ipaddr().family()));
|
control_socket_.reset(CreateClientSocket(server_address_.ipaddr().family()));
|
||||||
hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family()));
|
hanging_get_.reset(CreateClientSocket(server_address_.ipaddr().family()));
|
||||||
|
// 初始化套接字信号
|
||||||
InitSocketSignals();
|
InitSocketSignals();
|
||||||
|
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
snprintf(buffer, sizeof(buffer), "GET /sign_in?%s HTTP/1.0\r\n\r\n",
|
snprintf(buffer, sizeof(buffer), "GET /sign_in?%s HTTP/1.0\r\n\r\n",
|
||||||
client_name_.c_str());
|
client_name_.c_str());
|
||||||
|
@ -38,12 +38,12 @@ struct PeerConnectionClientObserver {
|
|||||||
class PeerConnectionClient : public sigslot::has_slots<> {
|
class PeerConnectionClient : public sigslot::has_slots<> {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
NOT_CONNECTED,
|
NOT_CONNECTED, // 未连接
|
||||||
RESOLVING,
|
RESOLVING, // 解决
|
||||||
SIGNING_IN,
|
SIGNING_IN, // 登录中
|
||||||
CONNECTED,
|
CONNECTED, // 连接的
|
||||||
SIGNING_OUT_WAITING,
|
SIGNING_OUT_WAITING, // 退出等待
|
||||||
SIGNING_OUT,
|
SIGNING_OUT, // 退出
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerConnectionClient();
|
PeerConnectionClient();
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gobject/gclosure.h>
|
#include <gobject/gclosure.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <stddef.h>
|
#include <cstddef>
|
||||||
#include <stdio.h>
|
#include <cstdio>
|
||||||
#include <stdlib.h>
|
#include <cstdlib>
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -42,9 +42,7 @@ namespace {
|
|||||||
// GtkMainWnd instance.
|
// GtkMainWnd instance.
|
||||||
//
|
//
|
||||||
|
|
||||||
gboolean OnDestroyedCallback(GtkWidget *widget,
|
gboolean OnDestroyedCallback(GtkWidget *widget, GdkEvent *event, gpointer data) {
|
||||||
GdkEvent *event,
|
|
||||||
gpointer data) {
|
|
||||||
reinterpret_cast<GtkMainWnd *>(data)->OnDestroyed(widget, event);
|
reinterpret_cast<GtkMainWnd *>(data)->OnDestroyed(widget, event);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -54,6 +52,9 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gboolean SimulateButtonClick(gpointer button) {
|
gboolean SimulateButtonClick(gpointer button) {
|
||||||
|
// g_signal_emit_by_name 是 GLib 库中用于通过信号名称发出信号的函数。
|
||||||
|
// 在 GTK 编程中,通过 g_signal_emit_by_name 可以模拟发出特定信号,触发与之关联的信号处理函数。
|
||||||
|
// 模拟触发模拟按钮点击
|
||||||
g_signal_emit_by_name(button, "clicked");
|
g_signal_emit_by_name(button, "clicked");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -77,7 +78,7 @@ namespace {
|
|||||||
GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
|
GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
|
||||||
|
|
||||||
// "if iter is NULL, then the number of toplevel nodes is returned."
|
// "if iter is NULL, then the number of toplevel nodes is returned."
|
||||||
int rows = gtk_tree_model_iter_n_children(model, NULL);
|
int rows = gtk_tree_model_iter_n_children(model, nullptr);
|
||||||
GtkTreePath *lastpath = gtk_tree_path_new_from_indices(rows - 1, -1);
|
GtkTreePath *lastpath = gtk_tree_path_new_from_indices(rows - 1, -1);
|
||||||
|
|
||||||
// Select the last item in the list
|
// Select the last item in the list
|
||||||
@ -94,6 +95,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a tree view, that we use to display the list of peers.
|
// Creates a tree view, that we use to display the list of peers.
|
||||||
|
// 创建一个树视图,我们用它来显示对等点列表。
|
||||||
void InitializeList(GtkWidget *list) {
|
void InitializeList(GtkWidget *list) {
|
||||||
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
||||||
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
|
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
|
||||||
@ -125,17 +127,20 @@ namespace {
|
|||||||
|
|
||||||
gboolean HandleUIThreadCallback(gpointer data) {
|
gboolean HandleUIThreadCallback(gpointer data) {
|
||||||
UIThreadCallbackData *cb_data = reinterpret_cast<UIThreadCallbackData *>(data);
|
UIThreadCallbackData *cb_data = reinterpret_cast<UIThreadCallbackData *>(data);
|
||||||
|
// 自定义的消息处理纯虚函数
|
||||||
cb_data->callback->UIThreadCallback(cb_data->msg_id, cb_data->data);
|
cb_data->callback->UIThreadCallback(cb_data->msg_id, cb_data->data);
|
||||||
delete cb_data;
|
delete cb_data;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重新绘制
|
||||||
gboolean Redraw(gpointer data) {
|
gboolean Redraw(gpointer data) {
|
||||||
GtkMainWnd *wnd = reinterpret_cast<GtkMainWnd *>(data);
|
GtkMainWnd *wnd = reinterpret_cast<GtkMainWnd *>(data);
|
||||||
wnd->OnRedraw();
|
wnd->OnRedraw();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 绘制
|
||||||
gboolean Draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
|
gboolean Draw(GtkWidget *widget, cairo_t *cr, gpointer data) {
|
||||||
GtkMainWnd *wnd = reinterpret_cast<GtkMainWnd *>(data);
|
GtkMainWnd *wnd = reinterpret_cast<GtkMainWnd *>(data);
|
||||||
wnd->Draw(widget, cr);
|
wnd->Draw(widget, cr);
|
||||||
@ -152,16 +157,17 @@ GtkMainWnd::GtkMainWnd(const char *server,
|
|||||||
int port,
|
int port,
|
||||||
bool autoconnect,
|
bool autoconnect,
|
||||||
bool autocall)
|
bool autocall)
|
||||||
: window_(NULL),
|
: window_(nullptr),
|
||||||
draw_area_(NULL),
|
draw_area_(nullptr),
|
||||||
vbox_(NULL),
|
vbox_(nullptr),
|
||||||
server_edit_(NULL),
|
server_edit_(nullptr),
|
||||||
port_edit_(NULL),
|
port_edit_(nullptr),
|
||||||
peer_list_(NULL),
|
peer_list_(nullptr),
|
||||||
callback_(NULL),
|
callback_(nullptr),
|
||||||
server_(server),
|
server_(server),
|
||||||
autoconnect_(autoconnect),
|
autoconnect_(autoconnect),
|
||||||
autocall_(autocall) {
|
autocall_(autocall) {
|
||||||
|
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
snprintf(buffer, sizeof(buffer), "%i", port);
|
snprintf(buffer, sizeof(buffer), "%i", port);
|
||||||
port_ = buffer;
|
port_ = buffer;
|
||||||
@ -176,70 +182,92 @@ void GtkMainWnd::RegisterObserver(MainWndCallback *callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GtkMainWnd::IsWindow() {
|
bool GtkMainWnd::IsWindow() {
|
||||||
return window_ != NULL && GTK_IS_WINDOW(window_);
|
return window_ != nullptr && GTK_IS_WINDOW(window_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GtkMainWnd::MessageBox(const char *caption,
|
void GtkMainWnd::MessageBox(const char *caption, const char *text, bool is_error) {
|
||||||
const char *text,
|
|
||||||
bool is_error) {
|
|
||||||
GtkWidget *dialog = gtk_message_dialog_new(
|
GtkWidget *dialog = gtk_message_dialog_new(
|
||||||
GTK_WINDOW(window_), GTK_DIALOG_DESTROY_WITH_PARENT,
|
GTK_WINDOW(window_), GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
is_error ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
|
is_error ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "%s",
|
||||||
text);
|
text);
|
||||||
|
// "hhhhhhhh");
|
||||||
gtk_window_set_title(GTK_WINDOW(dialog), caption);
|
gtk_window_set_title(GTK_WINDOW(dialog), caption);
|
||||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
gtk_widget_destroy(dialog);
|
gtk_widget_destroy(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查看当前的界面
|
||||||
MainWindow::UI GtkMainWnd::current_ui() {
|
MainWindow::UI GtkMainWnd::current_ui() {
|
||||||
if (vbox_)
|
if (vbox_)
|
||||||
return CONNECT_TO_SERVER;
|
return UI::CONNECT_TO_SERVER;
|
||||||
|
|
||||||
if (peer_list_)
|
if (peer_list_)
|
||||||
return LIST_PEERS;
|
return UI::LIST_PEERS;
|
||||||
|
|
||||||
return STREAMING;
|
return UI::STREAMING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开始本地绘制
|
||||||
|
// VideoTrackInterface 是 WebRTC 中的一个接口,它表示一个视频轨道。在实时通信中,可以使用该接口来传输视频数据。
|
||||||
void GtkMainWnd::StartLocalRenderer(webrtc::VideoTrackInterface *local_video) {
|
void GtkMainWnd::StartLocalRenderer(webrtc::VideoTrackInterface *local_video) {
|
||||||
|
// 重新初始化 或者是赋值 一个渲染绘制类
|
||||||
local_renderer_.reset(new VideoRenderer(this, local_video));
|
local_renderer_.reset(new VideoRenderer(this, local_video));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 通知本地绘制
|
||||||
void GtkMainWnd::StopLocalRenderer() {
|
void GtkMainWnd::StopLocalRenderer() {
|
||||||
local_renderer_.reset();
|
local_renderer_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 开始远程绘制
|
||||||
void GtkMainWnd::StartRemoteRenderer(
|
void GtkMainWnd::StartRemoteRenderer(
|
||||||
webrtc::VideoTrackInterface *remote_video) {
|
webrtc::VideoTrackInterface *remote_video) {
|
||||||
remote_renderer_.reset(new VideoRenderer(this, remote_video));
|
remote_renderer_.reset(new VideoRenderer(this, remote_video));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 停止远程绘制
|
||||||
void GtkMainWnd::StopRemoteRenderer() {
|
void GtkMainWnd::StopRemoteRenderer() {
|
||||||
remote_renderer_.reset();
|
remote_renderer_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 队列形式的UI线程内的回调?
|
||||||
void GtkMainWnd::QueueUIThreadCallback(int msg_id, void *data) {
|
void GtkMainWnd::QueueUIThreadCallback(int msg_id, void *data) {
|
||||||
g_idle_add(HandleUIThreadCallback,
|
// g_idle_add 是 GLib 库中的一个函数,用于在主事件循环(main loop)中添加一个空闲回调函数。
|
||||||
new UIThreadCallbackData(callback_, msg_id, data));
|
// 当调用 g_idle_add 函数时,它会创建一个空闲源(idle source),并将空闲回调函数注册到主事件循环中。
|
||||||
|
// 当主事件循环处于空闲状态时,空闲源会触发并调用注册的回调函数。
|
||||||
|
// 使用 g_idle_add 函数可以方便地在主事件循环的空闲时执行任务或更新界面,以提高程序的响应性。
|
||||||
|
// 只声明 定义不在这里
|
||||||
|
g_idle_add( // 回调处理函数
|
||||||
|
HandleUIThreadCallback,
|
||||||
|
// 回调类 封装了一层 添加了消息id 与 数据
|
||||||
|
new UIThreadCallbackData(callback_, msg_id, data)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建GUI窗口/窗体/GTK部件?
|
||||||
bool GtkMainWnd::Create() {
|
bool GtkMainWnd::Create() {
|
||||||
RTC_DCHECK(window_ == NULL);
|
RTC_DCHECK(window_ == nullptr);
|
||||||
|
|
||||||
|
// GTK_WINDOW_TOPLEVEL 类型,表示创建一个顶层窗口。顶层窗口是一个独立的窗口框架,通常作为应用程序的主窗口。
|
||||||
window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
if (window_) {
|
if (window_) {
|
||||||
|
// 设置窗口位置
|
||||||
gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER);
|
gtk_window_set_position(GTK_WINDOW(window_), GTK_WIN_POS_CENTER);
|
||||||
|
// 默认大小
|
||||||
gtk_window_set_default_size(GTK_WINDOW(window_), 640, 480);
|
gtk_window_set_default_size(GTK_WINDOW(window_), 640, 480);
|
||||||
|
// 窗口标题
|
||||||
gtk_window_set_title(GTK_WINDOW(window_), "PeerConnection client");
|
gtk_window_set_title(GTK_WINDOW(window_), "PeerConnection client");
|
||||||
g_signal_connect(G_OBJECT(window_), "delete-event",
|
// 可以将特定信号与回调函数连接起来,从而实现事件驱动的编程模型
|
||||||
G_CALLBACK(&OnDestroyedCallback), this);
|
g_signal_connect(G_OBJECT(window_), "delete-event", // 要连接信号的对象实例、信号名称
|
||||||
|
G_CALLBACK(&OnDestroyedCallback), this); // 回调函数,即信号发出时要执行的函数、传递给回调函数的数据
|
||||||
g_signal_connect(window_, "key-press-event", G_CALLBACK(OnKeyPressCallback),
|
g_signal_connect(window_, "key-press-event", G_CALLBACK(OnKeyPressCallback),
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
// 切换到连接用户界面
|
||||||
SwitchToConnectUI();
|
SwitchToConnectUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
return window_ != NULL;
|
return window_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GtkMainWnd::Destroy() {
|
bool GtkMainWnd::Destroy() {
|
||||||
@ -248,83 +276,118 @@ bool GtkMainWnd::Destroy() {
|
|||||||
|
|
||||||
// 销毁释放 一个 GTK+ 窗口部件(widget)及其所有子部件。
|
// 销毁释放 一个 GTK+ 窗口部件(widget)及其所有子部件。
|
||||||
gtk_widget_destroy(window_);
|
gtk_widget_destroy(window_);
|
||||||
window_ = NULL;
|
window_ = nullptr;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换到连接用户界面
|
||||||
void GtkMainWnd::SwitchToConnectUI() {
|
void GtkMainWnd::SwitchToConnectUI() {
|
||||||
RTC_LOG(LS_INFO) << __FUNCTION__;
|
RTC_LOG(LS_INFO) << __FUNCTION__;
|
||||||
|
|
||||||
RTC_DCHECK(IsWindow());
|
RTC_DCHECK(IsWindow());
|
||||||
RTC_DCHECK(vbox_ == NULL);
|
RTC_DCHECK(vbox_ == nullptr);
|
||||||
|
|
||||||
|
// 设置 GTK 容器(如窗口、框架等)的边框宽度
|
||||||
gtk_container_set_border_width(GTK_CONTAINER(window_), 10);
|
gtk_container_set_border_width(GTK_CONTAINER(window_), 10);
|
||||||
|
// peer_list 待通话页面
|
||||||
if (peer_list_) {
|
if (peer_list_) {
|
||||||
|
// 销毁一个小部件。当一个小部件被销毁时,它在其他对象上持有的所有引用都将被释放:
|
||||||
gtk_widget_destroy(peer_list_);
|
gtk_widget_destroy(peer_list_);
|
||||||
peer_list_ = NULL;
|
peer_list_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 这行代码创建了一个垂直方向的 GTK 容器(box),并设置了 5 像素的间距。
|
||||||
vbox_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
vbox_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||||
|
// 这个和上一行好像都是控件容器 最终依次添加到window_窗口中
|
||||||
|
// 应该是布局管理容器 在布局中的位置的管理
|
||||||
GtkWidget *valign = gtk_alignment_new(0, 1, 0, 0);
|
GtkWidget *valign = gtk_alignment_new(0, 1, 0, 0);
|
||||||
gtk_container_add(GTK_CONTAINER(vbox_), valign);
|
gtk_container_add(GTK_CONTAINER(vbox_), valign);
|
||||||
gtk_container_add(GTK_CONTAINER(window_), vbox_);
|
gtk_container_add(GTK_CONTAINER(window_), vbox_);
|
||||||
|
|
||||||
|
// 创建了一个水平容器
|
||||||
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
|
||||||
|
|
||||||
|
// 这回才是独立的子控件 一个label文字标签
|
||||||
GtkWidget *label = gtk_label_new("Server");
|
GtkWidget *label = gtk_label_new("Server");
|
||||||
gtk_container_add(GTK_CONTAINER(hbox), label);
|
gtk_container_add(GTK_CONTAINER(hbox), label);
|
||||||
|
|
||||||
|
// 文本输入控件 服务器地址
|
||||||
server_edit_ = gtk_entry_new();
|
server_edit_ = gtk_entry_new();
|
||||||
|
// 设置输入框的初始值 这个初始值在构造本类GtkMainWnd时就初始化了
|
||||||
gtk_entry_set_text(GTK_ENTRY(server_edit_), server_.c_str());
|
gtk_entry_set_text(GTK_ENTRY(server_edit_), server_.c_str());
|
||||||
|
// 设置控件最小尺寸的函数
|
||||||
gtk_widget_set_size_request(server_edit_, 400, 30);
|
gtk_widget_set_size_request(server_edit_, 400, 30);
|
||||||
gtk_container_add(GTK_CONTAINER(hbox), server_edit_);
|
gtk_container_add(GTK_CONTAINER(hbox), server_edit_);
|
||||||
|
|
||||||
|
// 文本输入控件 端口号
|
||||||
port_edit_ = gtk_entry_new();
|
port_edit_ = gtk_entry_new();
|
||||||
gtk_entry_set_text(GTK_ENTRY(port_edit_), port_.c_str());
|
gtk_entry_set_text(GTK_ENTRY(port_edit_), port_.c_str());
|
||||||
gtk_widget_set_size_request(port_edit_, 70, 30);
|
gtk_widget_set_size_request(port_edit_, 70, 30);
|
||||||
gtk_container_add(GTK_CONTAINER(hbox), port_edit_);
|
gtk_container_add(GTK_CONTAINER(hbox), port_edit_);
|
||||||
|
|
||||||
|
// 创建一个带有包含给定文本的子部件的小GtkButton部件 按钮部件
|
||||||
GtkWidget *button = gtk_button_new_with_label("Connect");
|
GtkWidget *button = gtk_button_new_with_label("Connect");
|
||||||
gtk_widget_set_size_request(button, 70, 30);
|
gtk_widget_set_size_request(button, 70, 30);
|
||||||
|
// 设置绑定事件
|
||||||
|
// GLib 库中用于连接信号和信号处理函数的函数。在 GTK 编程中,
|
||||||
|
// 通过 g_signal_connect 可以将特定的信号与相应的信号处理函数关联起来,以实现用户交互和事件处理。
|
||||||
g_signal_connect(button, "clicked", G_CALLBACK(OnClickedCallback), this);
|
g_signal_connect(button, "clicked", G_CALLBACK(OnClickedCallback), this);
|
||||||
gtk_container_add(GTK_CONTAINER(hbox), button);
|
gtk_container_add(GTK_CONTAINER(hbox), button);
|
||||||
|
// end 至此水平容器子控件全部添加完毕了
|
||||||
|
|
||||||
|
//
|
||||||
GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0);
|
GtkWidget *halign = gtk_alignment_new(1, 0, 0, 0);
|
||||||
gtk_container_add(GTK_CONTAINER(halign), hbox);
|
gtk_container_add(GTK_CONTAINER(halign), hbox);
|
||||||
|
// 最终添加到这个垂直容器
|
||||||
gtk_box_pack_start(GTK_BOX(vbox_), halign, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(vbox_), halign, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
// 显示窗口及其所有子控件
|
||||||
gtk_widget_show_all(window_);
|
gtk_widget_show_all(window_);
|
||||||
|
|
||||||
|
|
||||||
|
// autoconnect_ 构造时初始化的字段
|
||||||
if (autoconnect_)
|
if (autoconnect_)
|
||||||
|
// g_idle_add 是 GLib 库中用于注册空闲处理函数的函数。在 GTK 编程中,通过 g_idle_add 可以注册一个空闲处理函数,
|
||||||
|
// 当主循环处于空闲状态时,该函数将被调用。g_idle_add 是 GLib 库中用于注册空闲处理函数的函数。
|
||||||
|
// 在 GTK 编程中,通过 g_idle_add 可以注册一个空闲处理函数,当主循环处于空闲状态时,该函数将被调用。
|
||||||
|
// 待触发的函数 模拟按钮点击
|
||||||
g_idle_add(SimulateButtonClick, button);
|
g_idle_add(SimulateButtonClick, button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换到对等列表界面 待通话界面
|
||||||
void GtkMainWnd::SwitchToPeerList(const Peers &peers) {
|
void GtkMainWnd::SwitchToPeerList(const Peers &peers) {
|
||||||
RTC_LOG(LS_INFO) << __FUNCTION__;
|
RTC_LOG(LS_INFO) << __FUNCTION__;
|
||||||
|
|
||||||
|
// peer_list gtk 界面是否有效
|
||||||
if (!peer_list_) {
|
if (!peer_list_) {
|
||||||
|
// 设置边框宽度0?
|
||||||
gtk_container_set_border_width(GTK_CONTAINER(window_), 0);
|
gtk_container_set_border_width(GTK_CONTAINER(window_), 0);
|
||||||
if (vbox_) {
|
if (vbox_) {
|
||||||
|
// 消逝了垂直容器还有其内的所有子控件
|
||||||
gtk_widget_destroy(vbox_);
|
gtk_widget_destroy(vbox_);
|
||||||
vbox_ = NULL;
|
vbox_ = nullptr;
|
||||||
server_edit_ = NULL;
|
server_edit_ = nullptr;
|
||||||
port_edit_ = NULL;
|
port_edit_ = nullptr;
|
||||||
} else if (draw_area_) {
|
} else if (draw_area_) {
|
||||||
|
// 用于渲染视频流的绘图表面界面
|
||||||
gtk_widget_destroy(draw_area_);
|
gtk_widget_destroy(draw_area_);
|
||||||
draw_area_ = NULL;
|
draw_area_ = nullptr;
|
||||||
draw_buffer_.reset();
|
draw_buffer_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化待通话界面控件 树形视图控件
|
||||||
peer_list_ = gtk_tree_view_new();
|
peer_list_ = gtk_tree_view_new();
|
||||||
g_signal_connect(peer_list_, "row-activated",
|
// 绑定信号事件 行激活?事件
|
||||||
G_CALLBACK(OnRowActivatedCallback), this);
|
g_signal_connect(peer_list_, "row-activated", G_CALLBACK(OnRowActivatedCallback), this);
|
||||||
|
// 用于设置树形视图控件 GtkTreeView 是否显示列标题
|
||||||
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(peer_list_), FALSE);
|
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(peer_list_), FALSE);
|
||||||
|
// 创建一个树视图,我们用它来显示对等点列表。
|
||||||
InitializeList(peer_list_);
|
InitializeList(peer_list_);
|
||||||
gtk_container_add(GTK_CONTAINER(window_), peer_list_);
|
gtk_container_add(GTK_CONTAINER(window_), peer_list_);
|
||||||
gtk_widget_show_all(window_);
|
gtk_widget_show_all(window_);
|
||||||
} else {
|
} else {
|
||||||
|
//
|
||||||
GtkListStore *store =
|
GtkListStore *store =
|
||||||
GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(peer_list_)));
|
GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(peer_list_)));
|
||||||
gtk_list_store_clear(store);
|
gtk_list_store_clear(store);
|
||||||
@ -338,42 +401,54 @@ void GtkMainWnd::SwitchToPeerList(const Peers &peers) {
|
|||||||
g_idle_add(SimulateLastRowActivated, peer_list_);
|
g_idle_add(SimulateLastRowActivated, peer_list_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 切换到流媒体用户通话界面
|
||||||
void GtkMainWnd::SwitchToStreamingUI() {
|
void GtkMainWnd::SwitchToStreamingUI() {
|
||||||
RTC_LOG(LS_INFO) << __FUNCTION__;
|
RTC_LOG(LS_INFO) << __FUNCTION__;
|
||||||
|
|
||||||
RTC_DCHECK(draw_area_ == NULL);
|
RTC_DCHECK(draw_area_ == nullptr);
|
||||||
|
|
||||||
|
// 设置边框
|
||||||
gtk_container_set_border_width(GTK_CONTAINER(window_), 0);
|
gtk_container_set_border_width(GTK_CONTAINER(window_), 0);
|
||||||
|
// 消逝待通话界面
|
||||||
if (peer_list_) {
|
if (peer_list_) {
|
||||||
gtk_widget_destroy(peer_list_);
|
gtk_widget_destroy(peer_list_);
|
||||||
peer_list_ = NULL;
|
peer_list_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用于创建一个空白的绘图区域控件 GtkDrawingArea。
|
||||||
|
// GtkDrawingArea 控件通常用于显示自定义绘图,比如绘制图形、图表、图像等。
|
||||||
draw_area_ = gtk_drawing_area_new();
|
draw_area_ = gtk_drawing_area_new();
|
||||||
gtk_container_add(GTK_CONTAINER(window_), draw_area_);
|
gtk_container_add(GTK_CONTAINER(window_), draw_area_);
|
||||||
|
// 绑定事件开始绘制
|
||||||
g_signal_connect(G_OBJECT(draw_area_), "draw", G_CALLBACK(&::Draw), this);
|
g_signal_connect(G_OBJECT(draw_area_), "draw", G_CALLBACK(&::Draw), this);
|
||||||
|
|
||||||
gtk_widget_show_all(window_);
|
gtk_widget_show_all(window_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 窗口整体消逝
|
||||||
void GtkMainWnd::OnDestroyed(GtkWidget *widget, GdkEvent *event) {
|
void GtkMainWnd::OnDestroyed(GtkWidget *widget, GdkEvent *event) {
|
||||||
callback_->Close();
|
callback_->Close();
|
||||||
window_ = NULL;
|
window_ = nullptr;
|
||||||
draw_area_ = NULL;
|
draw_area_ = nullptr;
|
||||||
vbox_ = NULL;
|
vbox_ = nullptr;
|
||||||
server_edit_ = NULL;
|
server_edit_ = nullptr;
|
||||||
port_edit_ = NULL;
|
port_edit_ = nullptr;
|
||||||
peer_list_ = NULL;
|
peer_list_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
void GtkMainWnd::OnClicked(GtkWidget *widget) {
|
void GtkMainWnd::OnClicked(GtkWidget *widget) {
|
||||||
// Make the connect button insensitive, so that it cannot be clicked more than
|
// Make the connect button insensitive, so that it cannot be clicked more than
|
||||||
// once. Now that the connection includes auto-retry, it should not be
|
// once. Now that the connection includes auto-retry, it should not be
|
||||||
// necessary to click it more than once.
|
// necessary to click it more than once.
|
||||||
|
// 使连接按钮不敏感,使其不能被点击超过一次。 现在连接包括自动重试,不应该需要多次点击它。
|
||||||
|
// 用于设置一个控件是否处于可用状态(即是否响应用户输入)。当控件处于可用状态时,用户可以与其交互;当控件不可用时,用户无法与其交互。
|
||||||
gtk_widget_set_sensitive(widget, false);
|
gtk_widget_set_sensitive(widget, false);
|
||||||
server_ = gtk_entry_get_text(GTK_ENTRY(server_edit_));
|
server_ = gtk_entry_get_text(GTK_ENTRY(server_edit_));
|
||||||
port_ = gtk_entry_get_text(GTK_ENTRY(port_edit_));
|
port_ = gtk_entry_get_text(GTK_ENTRY(port_edit_));
|
||||||
int port = port_.length() ? atoi(port_.c_str()) : 0;
|
int port = port_.length() ? atoi(port_.c_str()) : 0;
|
||||||
|
|
||||||
|
// 回调 登录
|
||||||
callback_->StartLogin(server_, port);
|
callback_->StartLogin(server_, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
#ifndef EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
#ifndef EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
||||||
#define EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
#define EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -23,6 +23,8 @@
|
|||||||
#include "../main_wnd.h"
|
#include "../main_wnd.h"
|
||||||
#include "../peer_connection_client.h"
|
#include "../peer_connection_client.h"
|
||||||
|
|
||||||
|
// 主窗口的GTK实现
|
||||||
|
|
||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
typedef struct _GtkWidget GtkWidget;
|
typedef struct _GtkWidget GtkWidget;
|
||||||
typedef union _GdkEvent GdkEvent;
|
typedef union _GdkEvent GdkEvent;
|
||||||
@ -38,55 +40,82 @@ typedef struct _cairo cairo_t;
|
|||||||
class GtkMainWnd : public MainWindow {
|
class GtkMainWnd : public MainWindow {
|
||||||
public:
|
public:
|
||||||
GtkMainWnd(const char *server, int port, bool autoconnect, bool autocall);
|
GtkMainWnd(const char *server, int port, bool autoconnect, bool autocall);
|
||||||
~GtkMainWnd();
|
|
||||||
|
|
||||||
virtual void RegisterObserver(MainWndCallback* callback);
|
~GtkMainWnd() override;
|
||||||
virtual bool IsWindow();
|
|
||||||
virtual void SwitchToConnectUI();
|
|
||||||
virtual void SwitchToPeerList(const Peers& peers);
|
|
||||||
virtual void SwitchToStreamingUI();
|
|
||||||
virtual void MessageBox(const char* caption, const char* text, bool is_error);
|
|
||||||
virtual MainWindow::UI current_ui();
|
|
||||||
virtual void StartLocalRenderer(webrtc::VideoTrackInterface* local_video);
|
|
||||||
virtual void StopLocalRenderer();
|
|
||||||
virtual void StartRemoteRenderer(webrtc::VideoTrackInterface* remote_video);
|
|
||||||
virtual void StopRemoteRenderer();
|
|
||||||
|
|
||||||
virtual void QueueUIThreadCallback(int msg_id, void* data);
|
// 继承的纯虚接口
|
||||||
|
/*virtual */void RegisterObserver(MainWndCallback *callback) override;
|
||||||
|
|
||||||
|
/*virtual */bool IsWindow() override;
|
||||||
|
|
||||||
|
/*virtual */void SwitchToConnectUI() override;
|
||||||
|
|
||||||
|
/*virtual */void SwitchToPeerList(const Peers &peers) override;
|
||||||
|
|
||||||
|
/*virtual */void SwitchToStreamingUI() override;
|
||||||
|
|
||||||
|
/*virtual */void MessageBox(const char *caption, const char *text, bool is_error) override;
|
||||||
|
|
||||||
|
/*virtual */MainWindow::UI current_ui() override;
|
||||||
|
|
||||||
|
/*virtual */void StartLocalRenderer(webrtc::VideoTrackInterface *local_video) override;
|
||||||
|
|
||||||
|
/*virtual */void StopLocalRenderer() override;
|
||||||
|
|
||||||
|
/*virtual */void StartRemoteRenderer(webrtc::VideoTrackInterface *remote_video) override;
|
||||||
|
|
||||||
|
/*virtual */void StopRemoteRenderer() override;
|
||||||
|
|
||||||
|
/*virtual*/ void QueueUIThreadCallback(int msg_id, void *data) override;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************************************/
|
||||||
|
/** 接下来的UI操作的函数 **/
|
||||||
|
/********************************************************************************************/
|
||||||
|
|
||||||
// Creates and shows the main window with the |Connect UI| enabled.
|
// Creates and shows the main window with the |Connect UI| enabled.
|
||||||
|
// 创建主窗口 (链接窗口)
|
||||||
bool Create();
|
bool Create();
|
||||||
|
|
||||||
// Destroys the window. When the window is destroyed, it ends the
|
// Destroys the window. When the window is destroyed, it ends the main message loop.
|
||||||
// main message loop.
|
// 销毁窗口
|
||||||
bool Destroy();
|
bool Destroy();
|
||||||
|
|
||||||
// Callback for when the main window is destroyed.
|
// Callback for when the main window is destroyed.
|
||||||
|
// 主窗口被销毁时的回调。
|
||||||
void OnDestroyed(GtkWidget *widget, GdkEvent *event);
|
void OnDestroyed(GtkWidget *widget, GdkEvent *event);
|
||||||
|
|
||||||
// Callback for when the user clicks the "Connect" button.
|
// Callback for when the user clicks the "Connect" button.
|
||||||
|
// 当用户点击“连接”按钮时的回调。 链接信令服务器的回调
|
||||||
void OnClicked(GtkWidget *widget);
|
void OnClicked(GtkWidget *widget);
|
||||||
|
|
||||||
// Callback for keystrokes. Used to capture Esc and Return.
|
// Callback for keystrokes. Used to capture Esc and Return.
|
||||||
|
// 按键事件回调。 用于捕获 Esc 和 Return。
|
||||||
void OnKeyPress(GtkWidget *widget, GdkEventKey *key);
|
void OnKeyPress(GtkWidget *widget, GdkEventKey *key);
|
||||||
|
|
||||||
// Callback when the user double clicks a peer in order to initiate a
|
// Callback when the user double clicks a peer in order to initiate a connection.
|
||||||
// connection.
|
// 当用户双击对等点以发起连接时的回调。 点击待通信列表后webrtc对话的回调
|
||||||
void OnRowActivated(GtkTreeView* tree_view,
|
void OnRowActivated(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column);
|
||||||
GtkTreePath* path,
|
|
||||||
GtkTreeViewColumn* column);
|
|
||||||
|
|
||||||
|
// 重画时?
|
||||||
void OnRedraw();
|
void OnRedraw();
|
||||||
|
|
||||||
|
// 绘制
|
||||||
void Draw(GtkWidget *widget, cairo_t *cr);
|
void Draw(GtkWidget *widget, cairo_t *cr);
|
||||||
|
|
||||||
|
/// 内部类
|
||||||
protected:
|
protected:
|
||||||
|
// 视频渲染绘制 继承webrtc的sink接收组件
|
||||||
|
// 一般来说,VideoSinkInterface 接口定义了一组方法或函数,用于接收、处理和显示视频数据。
|
||||||
class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
class VideoRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||||
public:
|
public:
|
||||||
VideoRenderer(GtkMainWnd *main_wnd, webrtc::VideoTrackInterface *track_to_render);
|
VideoRenderer(GtkMainWnd *main_wnd, webrtc::VideoTrackInterface *track_to_render);
|
||||||
|
|
||||||
virtual ~VideoRenderer();
|
virtual ~VideoRenderer();
|
||||||
|
|
||||||
// VideoSinkInterface implementation
|
// VideoSinkInterface implementation
|
||||||
|
// 基类 VideoSinkInterface 视频接收器接口实现
|
||||||
void OnFrame(const webrtc::VideoFrame &frame) override;
|
void OnFrame(const webrtc::VideoFrame &frame) override;
|
||||||
|
|
||||||
const uint8_t *image() const { return image_.get(); }
|
const uint8_t *image() const { return image_.get(); }
|
||||||
@ -96,32 +125,35 @@ class GtkMainWnd : public MainWindow {
|
|||||||
int height() const { return height_; }
|
int height() const { return height_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// 设置渲染大小
|
||||||
void SetSize(int width, int height);
|
void SetSize(int width, int height);
|
||||||
std::unique_ptr<uint8_t[]> image_;
|
|
||||||
int width_;
|
std::unique_ptr<uint8_t[]> image_; // 某一帧?
|
||||||
int height_;
|
int width_; // 渲染的宽
|
||||||
GtkMainWnd* main_wnd_;
|
int height_; // 渲染的高
|
||||||
rtc::scoped_refptr<webrtc::VideoTrackInterface> rendered_track_;
|
GtkMainWnd *main_wnd_; // 自定义的主窗口抽象类
|
||||||
|
rtc::scoped_refptr<webrtc::VideoTrackInterface> rendered_track_; // 渲染轨道
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GtkWidget* window_; // Our main window.
|
/// GtkWidget 可能是部件/窗口/控件
|
||||||
GtkWidget* draw_area_; // The drawing surface for rendering video streams.
|
GtkWidget *window_; // Our main window. // GTK的 主窗口部件
|
||||||
GtkWidget* vbox_; // Container for the Connect UI.
|
GtkWidget *draw_area_; // The drawing surface for rendering video streams. // 用于渲染视频流的绘图表面。
|
||||||
GtkWidget* server_edit_;
|
GtkWidget *vbox_; // Container for the Connect UI. // Connect UI 的容器。
|
||||||
GtkWidget* port_edit_;
|
GtkWidget *server_edit_; // 链接信令服务器地址的输入框控件
|
||||||
GtkWidget* peer_list_; // The list of peers.
|
GtkWidget *port_edit_; // 链接信令服务器端口的输入框控件
|
||||||
MainWndCallback* callback_;
|
GtkWidget *peer_list_; // The list of peers. // Peer 链接的列表 待通话的列表 此时双方已经互相交换了SDP了 协商完了已经
|
||||||
std::string server_;
|
MainWndCallback *callback_; // 回调函数集抽象类 自定义的各种操作的回调
|
||||||
std::string port_;
|
std::string server_; // 链接的地址
|
||||||
bool autoconnect_;
|
std::string port_; // 链接的端口
|
||||||
bool autocall_;
|
bool autoconnect_; // 是否链接?
|
||||||
std::unique_ptr<VideoRenderer> local_renderer_;
|
bool autocall_; // 是否通话?
|
||||||
std::unique_ptr<VideoRenderer> remote_renderer_;
|
std::unique_ptr<GtkMainWnd::VideoRenderer> local_renderer_; // 本地渲染
|
||||||
int width_;
|
std::unique_ptr<GtkMainWnd::VideoRenderer> remote_renderer_; // 远程渲染
|
||||||
int height_;
|
int width_; //
|
||||||
std::unique_ptr<uint8_t[]> draw_buffer_;
|
int height_; //
|
||||||
int draw_buffer_size_;
|
std::unique_ptr<uint8_t[]> draw_buffer_; // 绘制缓存
|
||||||
|
int draw_buffer_size_; // 绘制缓存大小
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
#endif // EXAMPLES_PEERCONNECTION_CLIENT_LINUX_MAIN_WND_H_
|
||||||
|
@ -13,17 +13,22 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
#if defined(WEBRTC_POSIX)
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
|
||||||
|
// 表头终止符
|
||||||
static const char kHeaderTerminator[] = "\r\n\r\n";
|
static const char kHeaderTerminator[] = "\r\n\r\n";
|
||||||
|
// 表头终止符 数组的长度
|
||||||
static const int kHeaderTerminatorLength = sizeof(kHeaderTerminator) - 1;
|
static const int kHeaderTerminatorLength = sizeof(kHeaderTerminator) - 1;
|
||||||
|
|
||||||
// static
|
// static 什么头 不知道???? 像是http头的格式
|
||||||
const char DataSocket::kCrossOriginAllowHeaders[] =
|
const char DataSocket::kCrossOriginAllowHeaders[] =
|
||||||
"Access-Control-Allow-Origin: *\r\n"
|
"Access-Control-Allow-Origin: *\r\n"
|
||||||
"Access-Control-Allow-Credentials: true\r\n"
|
"Access-Control-Allow-Credentials: true\r\n"
|
||||||
@ -52,8 +57,8 @@ WinsockInitializer WinsockInitializer::singleton;
|
|||||||
//
|
//
|
||||||
|
|
||||||
bool SocketBase::Create() {
|
bool SocketBase::Create() {
|
||||||
RTC_DCHECK(!valid());
|
RTC_DCHECK(!valid()); // 检验本地监听?socket是否未有效
|
||||||
socket_ = ::socket(AF_INET, SOCK_STREAM, 0);
|
socket_ = ::socket(AF_INET, SOCK_STREAM, 0); // 初始化后有效了
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,9 +273,8 @@ bool DataSocket::ParseContentLengthAndType(const char* headers, size_t length) {
|
|||||||
bool ListeningSocket::Listen(unsigned short port) {
|
bool ListeningSocket::Listen(unsigned short port) {
|
||||||
RTC_DCHECK(valid());
|
RTC_DCHECK(valid());
|
||||||
int enabled = 1;
|
int enabled = 1;
|
||||||
if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
|
// SO_REUSEADDR 端口复用
|
||||||
reinterpret_cast<const char*>(&enabled),
|
if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&enabled), sizeof(enabled)) != 0) {
|
||||||
sizeof(enabled)) != 0) {
|
|
||||||
printf("setsockopt failed\n");
|
printf("setsockopt failed\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,11 @@
|
|||||||
typedef int socklen_t;
|
typedef int socklen_t;
|
||||||
typedef SOCKET NativeSocket;
|
typedef SOCKET NativeSocket;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#define closesocket close
|
#define closesocket close
|
||||||
typedef int NativeSocket;
|
typedef int NativeSocket;
|
||||||
|
|
||||||
@ -36,15 +38,21 @@ typedef int NativeSocket;
|
|||||||
class SocketBase {
|
class SocketBase {
|
||||||
public:
|
public:
|
||||||
SocketBase() : socket_(INVALID_SOCKET) {}
|
SocketBase() : socket_(INVALID_SOCKET) {}
|
||||||
|
|
||||||
explicit SocketBase(NativeSocket socket) : socket_(socket) {}
|
explicit SocketBase(NativeSocket socket) : socket_(socket) {}
|
||||||
|
|
||||||
SocketBase(SocketBase &other) = delete;
|
SocketBase(SocketBase &other) = delete;
|
||||||
|
|
||||||
SocketBase &operator=(const SocketBase &other) = delete;
|
SocketBase &operator=(const SocketBase &other) = delete;
|
||||||
|
|
||||||
~SocketBase() { Close(); }
|
~SocketBase() { Close(); }
|
||||||
|
|
||||||
NativeSocket socket() const { return socket_; }
|
NativeSocket socket() const { return socket_; }
|
||||||
|
|
||||||
bool valid() const { return socket_ != INVALID_SOCKET; }
|
bool valid() const { return socket_ != INVALID_SOCKET; }
|
||||||
|
|
||||||
bool Create();
|
bool Create();
|
||||||
|
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -52,6 +60,7 @@ class SocketBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Represents an HTTP server socket.
|
// Represents an HTTP server socket.
|
||||||
|
// 表示 HTTP 服务器套接字。
|
||||||
class DataSocket : public SocketBase {
|
class DataSocket : public SocketBase {
|
||||||
public:
|
public:
|
||||||
enum RequestMethod {
|
enum RequestMethod {
|
||||||
@ -68,11 +77,15 @@ class DataSocket : public SocketBase {
|
|||||||
|
|
||||||
static const char kCrossOriginAllowHeaders[];
|
static const char kCrossOriginAllowHeaders[];
|
||||||
|
|
||||||
|
// 标头是否有效 收到的标头
|
||||||
bool headers_received() const { return method_ != INVALID; }
|
bool headers_received() const { return method_ != INVALID; }
|
||||||
|
|
||||||
RequestMethod method() const { return method_; }
|
RequestMethod method() const { return method_; }
|
||||||
|
|
||||||
|
// 获取请求uri /命令?参数=值
|
||||||
const std::string &request_path() const { return request_path_; }
|
const std::string &request_path() const { return request_path_; }
|
||||||
|
|
||||||
|
// 请求参数 ?后面拼接的参数
|
||||||
std::string request_arguments() const;
|
std::string request_arguments() const;
|
||||||
|
|
||||||
const std::string &data() const { return data_; }
|
const std::string &data() const { return data_; }
|
||||||
@ -81,19 +94,23 @@ class DataSocket : public SocketBase {
|
|||||||
|
|
||||||
size_t content_length() const { return content_length_; }
|
size_t content_length() const { return content_length_; }
|
||||||
|
|
||||||
|
// 已收到请求?
|
||||||
bool request_received() const {
|
bool request_received() const {
|
||||||
return headers_received() && (method_ != POST || data_received());
|
return headers_received() && (method_ != POST || data_received());
|
||||||
}
|
}
|
||||||
|
// 收到的数据
|
||||||
bool data_received() const {
|
bool data_received() const {
|
||||||
return method_ != POST || data_.length() >= content_length_;
|
return method_ != POST || data_.length() >= content_length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查请求路径 的 命令 /xxx? ?前的uri
|
||||||
// Checks if the request path (minus arguments) matches a given path.
|
// Checks if the request path (minus arguments) matches a given path.
|
||||||
bool PathEquals(const char *path) const;
|
bool PathEquals(const char *path) const;
|
||||||
|
|
||||||
// Called when we have received some data from clients.
|
// Called when we have received some data from clients.
|
||||||
// Returns false if an error occurred.
|
// Returns false if an error occurred.
|
||||||
|
// 当我们从客户端收到一些数据时调用。
|
||||||
|
// 如果发生错误则返回 false。
|
||||||
bool OnDataAvailable(bool *close_socket);
|
bool OnDataAvailable(bool *close_socket);
|
||||||
|
|
||||||
// Send a raw buffer of bytes.
|
// Send a raw buffer of bytes.
|
||||||
@ -121,13 +138,18 @@ class DataSocket : public SocketBase {
|
|||||||
// A fairly relaxed HTTP header parser. Parses the method, path and
|
// A fairly relaxed HTTP header parser. Parses the method, path and
|
||||||
// content length (POST only) of a request.
|
// content length (POST only) of a request.
|
||||||
// Returns true if a valid request was received and no errors occurred.
|
// Returns true if a valid request was received and no errors occurred.
|
||||||
|
// 一个相当宽松的 HTTP 标头解析器。解析方法、路径和请求的内容长度(仅限 POST)。如果收到有效请求并且没有发生错误,则返回 true。
|
||||||
bool ParseHeaders();
|
bool ParseHeaders();
|
||||||
|
|
||||||
// Figures out whether the request is a GET or POST and what path is
|
// Figures out whether the request is a GET or POST and what path is
|
||||||
// being requested.
|
// being requested.
|
||||||
|
// 判断请求是 GET 还是 POST 以及路径是什么,正在被请求。
|
||||||
bool ParseMethodAndPath(const char *begin, size_t len);
|
bool ParseMethodAndPath(const char *begin, size_t len);
|
||||||
|
|
||||||
// Determines the length of the body and it's mime type.
|
// Determines the length of the body and it's mime type.
|
||||||
|
// 确定正文的长度及其 mime 类型。
|
||||||
|
// MIME (Multipurpose Internet Mail Extensions) 是一种在互联网上标识文件类型的标准。
|
||||||
|
// 在 WebRTC 相关的开发中,MIME 类型用于标识传输的数据的类型。
|
||||||
bool ParseContentLengthAndType(const char *headers, size_t length);
|
bool ParseContentLengthAndType(const char *headers, size_t length);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -141,11 +163,15 @@ class DataSocket : public SocketBase {
|
|||||||
|
|
||||||
// The server socket. Accepts connections and generates DataSocket instances
|
// The server socket. Accepts connections and generates DataSocket instances
|
||||||
// for each new connection.
|
// for each new connection.
|
||||||
|
//
|
||||||
|
// 服务器套接字。接受连接并生成 DataSocket 实例
|
||||||
|
// 对于每个新连接。
|
||||||
class ListeningSocket : public SocketBase {
|
class ListeningSocket : public SocketBase {
|
||||||
public:
|
public:
|
||||||
ListeningSocket() {}
|
ListeningSocket() {}
|
||||||
|
|
||||||
bool Listen(unsigned short port);
|
bool Listen(unsigned short port);
|
||||||
|
|
||||||
DataSocket *Accept() const;
|
DataSocket *Accept() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,9 +10,13 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#if defined(WEBRTC_POSIX)
|
#if defined(WEBRTC_POSIX)
|
||||||
|
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -102,24 +106,28 @@ int main(int argc, char* argv[]) {
|
|||||||
while (!quit) {
|
while (!quit) {
|
||||||
fd_set socket_set;
|
fd_set socket_set;
|
||||||
FD_ZERO(&socket_set);
|
FD_ZERO(&socket_set);
|
||||||
|
// 监听socket放入socket集合
|
||||||
if (listener.valid())
|
if (listener.valid())
|
||||||
FD_SET(listener.socket(), &socket_set);
|
FD_SET(listener.socket(), &socket_set);
|
||||||
|
// 后面建立的socket链接 select 设置 fd 到 fd_array select 维护
|
||||||
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
|
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i)
|
||||||
FD_SET((*i)->socket(), &socket_set);
|
FD_SET((*i)->socket(), &socket_set);
|
||||||
|
// 超时时间
|
||||||
struct timeval timeout = {10, 0};
|
struct timeval timeout = {10, 0};
|
||||||
if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
|
if (select(FD_SETSIZE, &socket_set, NULL, NULL, &timeout) == SOCKET_ERROR) {
|
||||||
printf("select failed\n");
|
printf("select failed\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 有sokcet链接就执行 客户端socket发送的信令
|
||||||
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
|
for (SocketArray::iterator i = sockets.begin(); i != sockets.end(); ++i) {
|
||||||
DataSocket *s = *i;
|
DataSocket *s = *i;
|
||||||
bool socket_done = true;
|
bool socket_done = true; // 套接字完成状态
|
||||||
|
// 查看是否维护了某个fd描述符
|
||||||
if (FD_ISSET(s->socket(), &socket_set)) {
|
if (FD_ISSET(s->socket(), &socket_set)) {
|
||||||
|
// 数据可用 与 已接收到请求
|
||||||
if (s->OnDataAvailable(&socket_done) && s->request_received()) {
|
if (s->OnDataAvailable(&socket_done) && s->request_received()) {
|
||||||
ChannelMember* member = clients.Lookup(s);
|
ChannelMember *member = clients.Lookup(s); // 查找是否已经包含当前DataSocket 则该用户是第一次发送信令
|
||||||
if (member || PeerChannel::IsPeerConnection(s)) {
|
if (member || PeerChannel::IsPeerConnection(s)) {
|
||||||
if (!member) {
|
if (!member) {
|
||||||
if (s->PathEquals("/sign_in")) {
|
if (s->PathEquals("/sign_in")) {
|
||||||
@ -129,12 +137,14 @@ int main(int argc, char* argv[]) {
|
|||||||
s->Send("500 Error", true, "text/plain", "",
|
s->Send("500 Error", true, "text/plain", "",
|
||||||
"Peer most likely gone.");
|
"Peer most likely gone.");
|
||||||
}
|
}
|
||||||
} else if (member->is_wait_request(s)) {
|
} else if (member->is_wait_request(s)) { // 等待
|
||||||
// no need to do anything.
|
// no need to do anything.
|
||||||
socket_done = false;
|
socket_done = false;
|
||||||
} else {
|
} else {
|
||||||
ChannelMember* target = clients.IsTargetedRequest(s);
|
// 对端的 ChannelMember 连接到服务器的单个对等点。
|
||||||
|
ChannelMember *target = clients.IsTargetedRequest(s); // to= 后的目标客户端target并转发数据到对端。
|
||||||
if (target) {
|
if (target) {
|
||||||
|
// 将请求转发到对等点
|
||||||
member->ForwardRequestToPeer(s, target);
|
member->ForwardRequestToPeer(s, target);
|
||||||
} else if (s->PathEquals("/sign_out")) {
|
} else if (s->PathEquals("/sign_out")) {
|
||||||
s->Send("200 OK", true, "text/plain", "", "");
|
s->Send("200 OK", true, "text/plain", "", "");
|
||||||
@ -159,6 +169,7 @@ int main(int argc, char* argv[]) {
|
|||||||
socket_done = false;
|
socket_done = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 响应完消息 断开 socket 从监听的队列中删除 ????
|
||||||
if (socket_done) {
|
if (socket_done) {
|
||||||
printf("Disconnecting socket\n");
|
printf("Disconnecting socket\n");
|
||||||
clients.OnClosing(s);
|
clients.OnClosing(s);
|
||||||
@ -173,10 +184,11 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
clients.CheckForTimeout();
|
clients.CheckForTimeout();
|
||||||
|
|
||||||
|
// 将新连接的DataSocket加入到sockets数组中
|
||||||
if (FD_ISSET(listener.socket(), &socket_set)) {
|
if (FD_ISSET(listener.socket(), &socket_set)) {
|
||||||
DataSocket *s = listener.Accept();
|
DataSocket *s = listener.Accept();
|
||||||
if (sockets.size() >= kMaxConnections) {
|
if (sockets.size() >= kMaxConnections) {
|
||||||
delete s; // sorry, that's all we can take.
|
delete s; // sorry, that's all we can take. 超过链接最大限制了 拒绝掉了
|
||||||
printf("Connection limit reached\n");
|
printf("Connection limit reached\n");
|
||||||
} else {
|
} else {
|
||||||
sockets.push_back(s);
|
sockets.push_back(s);
|
||||||
|
@ -20,15 +20,21 @@
|
|||||||
class DataSocket;
|
class DataSocket;
|
||||||
|
|
||||||
// Represents a single peer connected to the server.
|
// Represents a single peer connected to the server.
|
||||||
|
// 表示连接到服务器的单个对等点。
|
||||||
class ChannelMember {
|
class ChannelMember {
|
||||||
public:
|
public:
|
||||||
explicit ChannelMember(DataSocket *socket);
|
explicit ChannelMember(DataSocket *socket);
|
||||||
|
|
||||||
~ChannelMember();
|
~ChannelMember();
|
||||||
|
|
||||||
bool connected() const { return connected_; }
|
bool connected() const { return connected_; }
|
||||||
|
|
||||||
int id() const { return id_; }
|
int id() const { return id_; }
|
||||||
|
|
||||||
void set_disconnected() { connected_ = false; }
|
void set_disconnected() { connected_ = false; }
|
||||||
|
|
||||||
bool is_wait_request(DataSocket *ds) const;
|
bool is_wait_request(DataSocket *ds) const;
|
||||||
|
|
||||||
const std::string &name() const { return name_; }
|
const std::string &name() const { return name_; }
|
||||||
|
|
||||||
bool TimedOut();
|
bool TimedOut();
|
||||||
@ -66,6 +72,7 @@ class ChannelMember {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Manages all currently connected peers.
|
// Manages all currently connected peers.
|
||||||
|
// 管理所有当前连接的对等点。
|
||||||
class PeerChannel {
|
class PeerChannel {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<ChannelMember *> Members;
|
typedef std::vector<ChannelMember *> Members;
|
||||||
@ -103,8 +110,10 @@ class PeerChannel {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DeleteAll();
|
void DeleteAll();
|
||||||
|
|
||||||
void BroadcastChangedState(const ChannelMember &member,
|
void BroadcastChangedState(const ChannelMember &member,
|
||||||
Members *delivery_failures);
|
Members *delivery_failures);
|
||||||
|
|
||||||
void HandleDeliveryFailures(Members *failures);
|
void HandleDeliveryFailures(Members *failures);
|
||||||
|
|
||||||
// Builds a simple list of "name,id\n" entries for each member.
|
// Builds a simple list of "name,id\n" entries for each member.
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
project(test)
|
project(test)
|
||||||
|
|
||||||
include_directories(/opt/homebrew/Cellar/sdl2_image/2.8.1/include)
|
#include_directories(/opt/homebrew/Cellar/sdl2_image/2.8.1/include)
|
||||||
find_library(SDL2Image SDL2_image REQUIRED)
|
#find_library(SDL2Image SDL2_image REQUIRED)
|
||||||
find_library(SDL2 SDL2 REQUIRED)
|
#find_library(SDL2 SDL2 REQUIRED)
|
||||||
|
#
|
||||||
message(${SDL2Image})
|
#message(${SDL2Image})
|
||||||
message(${SDL2})
|
#message(${SDL2})
|
||||||
|
|
||||||
add_executable(test test_main.cc)
|
add_executable(test test_main.cc)
|
||||||
|
|
||||||
target_link_libraries(test PUBLIC
|
#target_link_libraries(test PUBLIC
|
||||||
${SDL2Image}
|
# ${SDL2Image}
|
||||||
${SDL2}
|
# ${SDL2}
|
||||||
PkgConfig::FFMPEG
|
# PkgConfig::FFMPEG
|
||||||
)
|
#)
|
Loading…
x
Reference in New Issue
Block a user