第三个消息则是MSG_CREATE_AUDIOSOURCE,第四个消息则是MSG_CREATE_VIDEOSOURCE,这两个消息的发送是在双击呼叫对端后,调用Conductor::InitializePeerConnection()函数进而调用Conductor::AddStreams()函数,在该函数中依次调用PeerConnectionFactory::CreateAudioSource()和PeerConnectionFactory::CreateVideoSource()函数发送。
在Win32SocketServer::Wait和Win32SocketServer::WakeUp函数中添加OutputDebugPrintf来输出相关信息,当在主线程中调用signaling_thread_->Send时,进入到Thread::Send发现,先调用current_thread->socketserver()->Wait(kForever, false);将当前线程即主线程Wait阻塞,然后signaling_thread_线程的消息响应循环回去响应signaling_thread_->Send所发送的消息,即在Thread::ProcessMessages中调用MessageQueue::Get,然后在这个函数中去调用Thread::ReceiveSends,在这个函数中响应了signaling_thread_->Send所发送的消息后,调用smsg.thread->socketserver()->WakeUp();即主线程的Win32SocketServer::WakeUp,这样由于在Thread::Send函数中主线程调用了current_thread->socketserver()->Wait(kForever, false);被阻塞,现在就可以继续执行了,然后主线程中执行Thread::Send的最后一条语句current_thread->socketserver()->WakeUp();即Win32SocketServer::WakeUp。
这样当下次在主线程中调用signaling_thread_->Send时,在Thread::Send中调用current_thread->socketserver()->Wait(kForever, false);时并不会阻塞主线程,但是signaling_thread_->Send发送的消息还未被响应即ready变量还为false,直到signaling_thread_线程的消息响应循环在调用Thread::ReceiveSends()响应了这个消息后才将ready赋值为true。所以在Thread::Send函数中的while循环中会第二次调用current_thread->socketserver()->Wait(kForever, false);这次就会阻塞主线程。
基于以上两段的分析,所以在主线程中调用signaling_thread_->Send时,Win32SocketServer::Wait和Win32SocketServer::WakeUp函数中消息的打印次序是,第一次调用先打印Wait,然后是打印两次WakeUp,当以后调用signaling_thread_->Send时,则是先打印两次Wait,然后再打印两次WakeUp。其中后面响应signaling_thread_->Send时,先打印的Wait事实上是相当于消耗掉在前一次执行signaling_thread_->Send发送消息时,Thread::Send函数中最后一条语句current_thread->socketserver()->WakeUp();。而第二个Wait才是阻塞当前的线程即主线程。当执行signaling_thread_->Send发送消息会打印两次WakeUp,其中第二次即Thread::Send函数中最后一条语句current_thread->socketserver()->WakeUp();而第一次则是signaling_thread_线程的消息响应循环种执行的Thread::ReceiveSends函数中的smsg.thread->socketserver()->WakeUp();。
在响应第四个消息MSG_CREATE_VIDEOSOURCE时,在响应该消息时会调用VideoCapturer::SetCaptureState函数,在该函数中通过主线程即main函数中的talk_base::Win32Thread w32_thread;来调用thread_->Post。由于虚函数实际执行的是MessageQueue::Post函数,该函数中会调用ss_->WakeUp();即Win32SocketServer::WakeUp,然后由于Thread::Send中while循环,此消息的响应并未完成,所以会继续Wait。
在响应第四个消息MSG_CREATE_VIDEOSOURCE时,PeerConnectionFactory::CreateVideoSource_s会调用VideoSource::Create函数进而调用VideoSource::Initialize,该函数又调用ChannelManager::StartVideoCapture,在这个函数中通过worker_thread_->Invoke来执行CaptureManager::StartVideoCapture,当worker_thread_线程消息响应循环中执行CaptureManager::StartVideoCapture中最终会调用VideoCapturer::SetCaptureState,而这个函数中通过主线程即main函数中的talk_base::Win32Thread w32_thread;来调用thread_->Post发送MSG_STATE_CHANGE消息。
回到Thread::Send函数中,以主线程调用signaling_thread_->Send发送消息为例,检测到发送线程即this不是当前线程(主线程)后,就将消息调用sendlist_.push_back(smsg);保存起来,然后就开始等待消息的响应(Wait for a reply),当调用 ss_->WakeUp();(即PhysicalSocketServer::WakeUp)时,signaling_thread_线程的消息响应循环就会去响应该消息。所以有可能已经signaling_thread_线程的消息响应循环已经对该消息响应完而且调用了smsg.thread->socketserver()->WakeUp();,然后cpu才接着执行Thread::Send函数中ss_->WakeUp();之后的while循环,即current_thread->socketserver()->Wait(kForever, false);。当然这个时候会马上返回,而并不阻塞在Win32SocketServer::Wait函数中的GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id);,并且会执行Thread::Send函数的最后一条语句current_thread->socketserver()->WakeUp();。这些都是通过打印Win32SocketServer::Wait和Win32SocketServer::WakeUp函数中的相关信息验证得到的。
当双击呼叫对端候,主线程中调用signaling_thread_->Send发送消息依次为MSG_INIT_FACTORY、MSG_CREATE_PEERCONNECTION、MSG_CREATE_AUDIOSOURCE和MSG_CREATE_VIDEOSOURCE。然后在Conductor::AddStreams函数中继续执行,会继续调用signaling_thread_->Send发送消息。如下图所示:
在Conductor::ConnectToPeer函数中调用Conductor::InitializePeerConnection函数,进而调用Conductor::AddStreams(),在Conductor::ConnectToPeer函数中执行完InitializePeerConnection后会调用PeerConnectionProxy::CreateOffer,由于PeerConnectionProxy关联了signaling_thread_所以也会调用signaling_thread_->Send发送消息。在这个步骤执行完之后就开始调用执行Win32SocketServer::MessageWindow::OnMessage函数中的ss_->Pump();(即Win32SocketServer::Pump()),最终会在该函数中调用MessageQueue::Dispatch执行VideoCapturer::OnMessage响应之前调用主线程(即talk_base::Win32Thread w32_thread;)发送的MSG_STATE_CHANGE消息。
为什么是在PeerConnectionProxy::CreateOffer执行后,才能执行到Win32SocketServer::MessageWindow::OnMessage函数的里面来执行ss_->Pump();,这是因为从调用signaling_thread_->Send发送第一个消息MSG_INIT_FACTORY开始,主线程中一直通过以下形式执行代码,即主线程通过调用Win32SocketServer::Wait函数中的GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id);来阻塞,然后Win32SocketServer::WakeUp()(signaling_thread_线程和主线程)执行PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);唤醒。主线程一直在响应双击呼叫对端事件,即一直在执行Conductor::ConnectToPeer,当执行完毕该函数后才有机会去在主线程中响应MSG_STATE_CHANGE消息,该消息是在Conductor::ConnectToPeer函数执行过程中通过主线程Post到主线程的消息队列中。
接上一段当执行完PeerConnectionProxy::CreateOffer后,由于在Thread::Send的最后通过调用current_thread->socketserver()->WakeUp();,该函数即Win32SocketServer::WakeUp(),这个函数PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);,所以主线程中创建的Win32SocketServer对象的成员变量MessageWindow wnd_;会收到消息s_wm_wakeup_id,其实应该是主线程收到消息,因为主线程(即talk_base::Win32Thread w32_thread;)中创建了Win32SocketServer对象及其成员变量MessageWindow wnd_;,根据MSDN对PostMessage函数的解释"Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message."。所以主线程的消息队列中收到s_wm_wakeup_id消息。这样说明了主线程通过Win32SocketServer::Wait函数的GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id);,而signaling_thread_线程通过Win32SocketServer::WakeUp函数中的PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);来唤醒,由于"函数GetMessage 是 从调用线程的消息队列里取得一个消息并将其放于指定的结构。GetMessage不接收属于其他线程或应用程序的消息。",但是通过PostMessage的MSDN注释可以明白子线程唤醒主线程。
而且在Conductor::ConnectToPeer函数中会调用主线程发送MSG_STATE_CHANGE消息,会唤醒一个主线程的等待,但是在主线程通过Thread::Send函数中的while循环判断当前的消息并没有被响应会继续阻塞,即主线程消耗掉了一次唤醒,这样当Thread::Send执行到最后,即当前消息发送的流程执行完之后需要再一次唤醒主线程(或者叫当前线程,因为这里是以主线程为例)。看一下Thread::Send函数最后的注释很详细。
双击呼叫对端后会执行Conductor::OnMessageFromPeer函数,然后也会调用signaling_thread_->Send发送消息,如下图所示,其中PeerConnectionProxy::AddIceCandidate可能会执行多次。
双击呼叫对端后会执行Conductor::OnMessageFromPeer函数,然后也会调用signaling_thread_->Send发送消息,同时打印Win32SocketServer::MessageWindow::OnMessage函数中的ss_->Pump();,发现每调用PeerConnectionProxy::AddIceCandidate执行一次后,都会打印输出ss_->Pump();,而在VideoTrackProxy::AddRenderer之后,有可能打印输出也可能不打印输出。其他就没有再打印输出ss_->Pump();的地方了。
当执行Conductor::OnMessageFromPeer函数,第一次调用signaling_thread_->Send发送消息是在PeerConnectionProxy::SetRemoteDescription,此时通过PostThreadMessage将消息NEW_STREAM_ADDED发送给主线程,然后主线程通过Conductor::UIThreadCallback来响应该消息两次调用signaling_thread_->Send发送消息。
至此,对trunk\talk\base\win32socketserver.cc文件的Win32SocketServer::Wait函数中的GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id);以及Win32SocketServer::MessageWindow::OnMessage函数中的对s_wm_wakeup_id消息响应的理解告一段落了。