webrtc/peerconnection/samples/client/conductor.cc
tommi@google.com 53af7595d1 Switch the sample client back to render the videos in the main window
instead of two popup windows.  This also demonstrates one way of
implementing the VideoRenderer interface.
Review URL: http://webrtc-codereview.appspot.com/51004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@143 4adac7df-926f-26a2-2b94-8c16560cd09d
2011-07-04 12:47:37 +00:00

322 lines
9.0 KiB
C++

/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "peerconnection/samples/client/conductor.h"
#include "peerconnection/samples/client/defaults.h"
#include "talk/base/logging.h"
#include "talk/session/phone/videorendererfactory.h"
Conductor::Conductor(PeerConnectionClient* client, MainWnd* main_wnd)
: handshake_(NONE),
waiting_for_audio_(false),
waiting_for_video_(false),
peer_id_(-1),
video_channel_(-1),
audio_channel_(-1),
client_(client),
main_wnd_(main_wnd) {
// Create a window for posting notifications back to from other threads.
bool ok = Create(HWND_MESSAGE, L"Conductor", 0, 0, 0, 0, 0, 0);
ASSERT(ok);
client_->RegisterObserver(this);
main_wnd->RegisterObserver(this);
}
Conductor::~Conductor() {
ASSERT(peer_connection_.get() == NULL);
Destroy();
DeletePeerConnection();
}
bool Conductor::has_video() const {
return video_channel_ != -1;
}
bool Conductor::has_audio() const {
return audio_channel_ != -1;
}
bool Conductor::connection_active() const {
return peer_connection_.get() != NULL;
}
void Conductor::Close() {
if (peer_connection_.get()) {
peer_connection_->Close();
} else {
client_->SignOut();
}
}
bool Conductor::InitializePeerConnection() {
ASSERT(peer_connection_.get() == NULL);
peer_connection_.reset(new webrtc::PeerConnection(GetPeerConnectionString()));
peer_connection_->RegisterObserver(this);
if (!peer_connection_->Init()) {
DeletePeerConnection();
} else {
bool audio = peer_connection_->SetAudioDevice("", "", 0);
LOG(INFO) << "SetAudioDevice " << (audio ? "succeeded." : "failed.");
}
return peer_connection_.get() != NULL;
}
void Conductor::DeletePeerConnection() {
peer_connection_.reset();
handshake_ = NONE;
}
void Conductor::StartCaptureDevice() {
ASSERT(peer_connection_.get());
if (main_wnd_->IsWindow()) {
main_wnd_->SwitchToStreamingUI();
if (peer_connection_->SetVideoCapture("")) {
peer_connection_->SetLocalVideoRenderer(main_wnd_->local_renderer());
} else {
ASSERT(false);
}
}
}
//
// PeerConnectionObserver implementation.
//
void Conductor::OnError() {
LOG(INFO) << __FUNCTION__;
ASSERT(false);
}
void Conductor::OnSignalingMessage(const std::string& msg) {
LOG(INFO) << __FUNCTION__;
bool shutting_down = (video_channel_ == -1 && audio_channel_ == -1);
if (handshake_ == OFFER_RECEIVED && !shutting_down)
StartCaptureDevice();
// Send our answer/offer/shutting down message.
// If we're the initiator, this will be our offer. If we just received
// an offer, this will be an answer. If PeerConnection::Close has been
// called, then this is our signal to the other end that we're shutting
// down.
if (handshake_ != QUIT_SENT) {
SendMessage(handle(), SEND_MESSAGE_TO_PEER, 0,
reinterpret_cast<LPARAM>(&msg));
}
if (shutting_down) {
handshake_ = QUIT_SENT;
PostMessage(handle(), PEER_CONNECTION_CLOSED, 0, 0);
}
}
// Called when a remote stream is added
void Conductor::OnAddStream(const std::string& stream_id, int channel_id,
bool video) {
LOG(INFO) << __FUNCTION__ << " " << stream_id;
bool send_notification = (waiting_for_video_ || waiting_for_audio_);
if (video) {
ASSERT(video_channel_ == -1);
video_channel_ = channel_id;
waiting_for_video_ = false;
LOG(INFO) << "Setting video renderer for channel: " << channel_id;
bool ok = peer_connection_->SetVideoRenderer(stream_id,
main_wnd_->remote_renderer());
ASSERT(ok);
} else {
ASSERT(audio_channel_ == -1);
audio_channel_ = channel_id;
waiting_for_audio_ = false;
}
if (send_notification && !waiting_for_audio_ && !waiting_for_video_)
PostMessage(handle(), MEDIA_CHANNELS_INITIALIZED, 0, 0);
}
void Conductor::OnRemoveStream(const std::string& stream_id, int channel_id,
bool video) {
LOG(INFO) << __FUNCTION__;
if (video) {
ASSERT(channel_id == video_channel_);
video_channel_ = -1;
} else {
ASSERT(channel_id == audio_channel_);
audio_channel_ = -1;
}
}
//
// PeerConnectionClientObserver implementation.
//
void Conductor::OnSignedIn() {
LOG(INFO) << __FUNCTION__;
main_wnd_->SwitchToPeerList(client_->peers());
}
void Conductor::OnDisconnected() {
LOG(INFO) << __FUNCTION__;
if (peer_connection_.get()) {
peer_connection_->Close();
} else if (main_wnd_->IsWindow()) {
main_wnd_->SwitchToConnectUI();
}
}
void Conductor::OnPeerConnected(int id, const std::string& name) {
LOG(INFO) << __FUNCTION__;
// Refresh the list if we're showing it.
if (main_wnd_->current_ui() == MainWnd::LIST_PEERS)
main_wnd_->SwitchToPeerList(client_->peers());
}
void Conductor::OnPeerDisconnected(int id, const std::string& name) {
LOG(INFO) << __FUNCTION__;
if (id == peer_id_) {
LOG(INFO) << "Our peer disconnected";
peer_id_ = -1;
if (peer_connection_.get())
peer_connection_->Close();
}
// Refresh the list if we're showing it.
if (main_wnd_->current_ui() == MainWnd::LIST_PEERS)
main_wnd_->SwitchToPeerList(client_->peers());
}
void Conductor::OnMessageFromPeer(int peer_id, const std::string& message) {
ASSERT(peer_id_ == peer_id || peer_id_ == -1);
if (handshake_ == NONE) {
handshake_ = OFFER_RECEIVED;
peer_id_ = peer_id;
if (!peer_connection_.get()) {
// Got an offer. Give it to the PeerConnection instance.
// Once processed, we will get a callback to OnSignalingMessage with
// our 'answer' which we'll send to the peer.
LOG(INFO) << "Got an offer from our peer: " << peer_id;
if (!InitializePeerConnection()) {
LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
client_->SignOut();
return;
}
}
} else if (handshake_ == INITIATOR) {
LOG(INFO) << "Remote peer sent us an answer";
handshake_ = ANSWER_RECEIVED;
} else {
LOG(INFO) << "Remote peer is disconnecting";
handshake_ = QUIT_SENT;
}
peer_connection_->SignalingMessage(message);
if (handshake_ == QUIT_SENT) {
DisconnectFromCurrentPeer();
}
}
//
// MainWndCallback implementation.
//
void Conductor::StartLogin(const std::string& server, int port) {
ASSERT(!client_->is_connected());
if (!client_->Connect(server, port, GetPeerName())) {
MessageBoxA(main_wnd_->handle(),
("Failed to connect to " + server).c_str(),
"Error", MB_OK | MB_ICONERROR);
}
}
void Conductor::DisconnectFromServer() {
if (!client_->is_connected())
return;
client_->SignOut();
}
void Conductor::ConnectToPeer(int peer_id) {
ASSERT(peer_id_ == -1);
ASSERT(peer_id != -1);
ASSERT(handshake_ == NONE);
if (handshake_ != NONE)
return;
if (InitializePeerConnection()) {
peer_id_ = peer_id;
waiting_for_video_ = peer_connection_->AddStream(kVideoLabel, true);
waiting_for_audio_ = peer_connection_->AddStream(kAudioLabel, false);
if (waiting_for_video_ || waiting_for_audio_)
handshake_ = INITIATOR;
ASSERT(waiting_for_video_ || waiting_for_audio_);
}
if (handshake_ == NONE) {
::MessageBoxA(main_wnd_->handle(), "Failed to initialize PeerConnection",
"Error", MB_OK | MB_ICONERROR);
}
}
void Conductor::DisconnectFromCurrentPeer() {
if (peer_connection_.get())
peer_connection_->Close();
}
//
// Win32Window implementation.
//
bool Conductor::OnMessage(UINT msg, WPARAM wp, LPARAM lp,
LRESULT& result) { // NOLINT
bool ret = true;
if (msg == MEDIA_CHANNELS_INITIALIZED) {
ASSERT(handshake_ == INITIATOR);
bool ok = peer_connection_->Connect();
ASSERT(ok);
StartCaptureDevice();
// When we get an OnSignalingMessage notification, we'll send our
// json encoded signaling message to the peer, which is the first step
// of establishing a connection.
} else if (msg == PEER_CONNECTION_CLOSED) {
LOG(INFO) << "PEER_CONNECTION_CLOSED";
DeletePeerConnection();
::InvalidateRect(main_wnd_->handle(), NULL, TRUE);
waiting_for_audio_ = false;
waiting_for_video_ = false;
peer_id_ = -1;
ASSERT(video_channel_ == -1);
ASSERT(audio_channel_ == -1);
if (main_wnd_->IsWindow()) {
if (client_->is_connected()) {
main_wnd_->SwitchToPeerList(client_->peers());
} else {
main_wnd_->SwitchToConnectUI();
}
} else {
DisconnectFromServer();
}
} else if (msg == SEND_MESSAGE_TO_PEER) {
bool ok = client_->SendToPeer(peer_id_,
*reinterpret_cast<std::string*>(lp));
if (!ok) {
LOG(LS_ERROR) << "SendToPeer failed";
DisconnectFromServer();
}
} else {
ret = false;
}
return ret;
}