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