mirror of
https://github.com/UltraCoderRU/libwebrtc.git
synced 2026-01-28 03:15:11 +00:00
Add Samples subdirectory, with a very basic sample program
This commit is contained in:
parent
d2b245e7a2
commit
6a6f80d5e9
20 changed files with 940 additions and 1 deletions
|
|
@ -67,3 +67,7 @@ set(LIBWEBRTC_BUILD_ROOT ${CMAKE_SOURCE_DIR}/src/out/Default)
|
||||||
set(WEBRTC_CHROMIUM_DEPS git@github.com:aisouard/libwebrtc-chromium-deps.git)
|
set(WEBRTC_CHROMIUM_DEPS git@github.com:aisouard/libwebrtc-chromium-deps.git)
|
||||||
|
|
||||||
add_subdirectory(Targets)
|
add_subdirectory(Targets)
|
||||||
|
|
||||||
|
if(BUILD_SAMPLES)
|
||||||
|
add_subdirectory(Samples)
|
||||||
|
endif(BUILD_SAMPLES)
|
||||||
1
Samples/CMakeLists.txt
Normal file
1
Samples/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
add_subdirectory(PeerConnection)
|
||||||
35
Samples/PeerConnection/CMakeLists.txt
Normal file
35
Samples/PeerConnection/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
project(PeerConnection)
|
||||||
|
|
||||||
|
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
|
||||||
|
set(PEERCONNECTION_SOURCE_FILES
|
||||||
|
main.cpp
|
||||||
|
Core.cpp
|
||||||
|
CreateSessionObserver.cpp
|
||||||
|
DataChannelObserver.cpp
|
||||||
|
Peer.cpp
|
||||||
|
PeerConnectionObserver.cpp
|
||||||
|
SetLocalSessionDescriptionObserver.cpp
|
||||||
|
SetRemoteSessionDescriptionObserver.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(${CMAKE_SOURCE_DIR}/out/src)
|
||||||
|
|
||||||
|
if(WIN)
|
||||||
|
add_definitions(-DWEBRTC_WIN)
|
||||||
|
else(WIN)
|
||||||
|
add_definitions(-DWEBRTC_POSIX -std=c++11 -fno-rtti -D_GLIBCXX_USE_CXX11_ABI=0)
|
||||||
|
set(PEERCONNECTION_SOURCE_FILES ${PEERCONNECTION_SOURCE_FILES} UnixConsole.cpp)
|
||||||
|
endif(WIN)
|
||||||
|
|
||||||
|
add_executable(PeerConnection ${PEERCONNECTION_SOURCE_FILES})
|
||||||
|
|
||||||
|
set(PEERCONNECTION_LIBRARIES ${CMAKE_BINARY_DIR}/${LIBWEBRTC_LIBRARY} Threads::Threads)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(PEERCONNECTION_LIBRARIES ${PEERCONNECTION_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||||
|
endif(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
|
target_link_libraries(PeerConnection ${PEERCONNECTION_LIBRARIES})
|
||||||
76
Samples/PeerConnection/Core.cpp
Normal file
76
Samples/PeerConnection/Core.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 24/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "webrtc/base/ssladapter.h"
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
rtc::Thread *Core::_signalingThread = NULL;
|
||||||
|
rtc::Thread *Core::_workerThread = NULL;
|
||||||
|
webrtc::PeerConnectionFactoryInterface *Core::_peerConnectionFactory = NULL;
|
||||||
|
|
||||||
|
bool Core::Init() {
|
||||||
|
rtc::InitializeSSL();
|
||||||
|
rtc::InitRandom(rtc::Time());
|
||||||
|
rtc::ThreadManager::Instance()->WrapCurrentThread();
|
||||||
|
|
||||||
|
_signalingThread = new rtc::Thread();
|
||||||
|
_workerThread = new rtc::Thread();
|
||||||
|
|
||||||
|
_signalingThread->SetName("signaling_thread", NULL);
|
||||||
|
_workerThread->SetName("worker_thread", NULL);
|
||||||
|
|
||||||
|
if (!_signalingThread->Start() || !_workerThread->Start()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_peerConnectionFactory =
|
||||||
|
webrtc::CreatePeerConnectionFactory(_signalingThread,
|
||||||
|
_workerThread,
|
||||||
|
NULL, NULL, NULL).release();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Update() {
|
||||||
|
return rtc::Thread::Current()->ProcessMessages(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Core::Cleanup() {
|
||||||
|
_peerConnectionFactory->Release();
|
||||||
|
_peerConnectionFactory = NULL;
|
||||||
|
|
||||||
|
_signalingThread->Stop();
|
||||||
|
_workerThread->Stop();
|
||||||
|
|
||||||
|
delete _signalingThread;
|
||||||
|
delete _workerThread;
|
||||||
|
|
||||||
|
_signalingThread = NULL;
|
||||||
|
_workerThread = NULL;
|
||||||
|
|
||||||
|
return rtc::CleanupSSL();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::Thread *Core::GetSignalingThread() {
|
||||||
|
return _signalingThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::Thread *Core::GetWorkerThread() {
|
||||||
|
return _workerThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
webrtc::PeerConnectionFactoryInterface *Core::GetPeerConnectionFactory() {
|
||||||
|
return _peerConnectionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
28
Samples/PeerConnection/Core.h
Normal file
28
Samples/PeerConnection/Core.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 24/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_CORE_H
|
||||||
|
#define LIBWEBRTC_CORE_H
|
||||||
|
|
||||||
|
#include "webrtc/api/peerconnectioninterface.h"
|
||||||
|
#include "webrtc/base/thread.h"
|
||||||
|
|
||||||
|
class Core {
|
||||||
|
public:
|
||||||
|
static bool Init();
|
||||||
|
static bool Update();
|
||||||
|
static bool Cleanup();
|
||||||
|
|
||||||
|
static rtc::Thread *GetSignalingThread();
|
||||||
|
static rtc::Thread *GetWorkerThread();
|
||||||
|
static webrtc::PeerConnectionFactoryInterface *GetPeerConnectionFactory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static rtc::Thread *_signalingThread;
|
||||||
|
static rtc::Thread *_workerThread;
|
||||||
|
static webrtc::PeerConnectionFactoryInterface *_peerConnectionFactory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_CORE_H
|
||||||
24
Samples/PeerConnection/CreateSessionObserver.cpp
Normal file
24
Samples/PeerConnection/CreateSessionObserver.cpp
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "CreateSessionObserver.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
#include "Peer.h"
|
||||||
|
#include "SetLocalSessionDescriptionObserver.h"
|
||||||
|
|
||||||
|
using namespace webrtc;
|
||||||
|
|
||||||
|
CreateSessionObserver::CreateSessionObserver(Peer *peer): _peer(peer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSessionObserver::OnSuccess(SessionDescriptionInterface* desc) {
|
||||||
|
rtc::scoped_refptr<SetLocalSessionDescriptionObserver> observer =
|
||||||
|
new rtc::RefCountedObject<SetLocalSessionDescriptionObserver>(desc);
|
||||||
|
|
||||||
|
_peer->SetLocalSessionDescription(desc, observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSessionObserver::OnFailure(const std::string& error) {
|
||||||
|
Console::Print("[CreateSessionObserver::OnFailure] %s", error.c_str());
|
||||||
|
}
|
||||||
26
Samples/PeerConnection/CreateSessionObserver.h
Normal file
26
Samples/PeerConnection/CreateSessionObserver.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_CREATEOFFEROBSERVER_H
|
||||||
|
#define LIBWEBRTC_CREATEOFFEROBSERVER_H
|
||||||
|
|
||||||
|
#include <webrtc/api/jsep.h>
|
||||||
|
#include "Peer.h"
|
||||||
|
|
||||||
|
class CreateSessionObserver: public webrtc::CreateSessionDescriptionObserver {
|
||||||
|
public:
|
||||||
|
CreateSessionObserver(Peer *peer);
|
||||||
|
|
||||||
|
void OnSuccess(webrtc::SessionDescriptionInterface* desc);
|
||||||
|
void OnFailure(const std::string& error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Peer *_peer;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~CreateSessionObserver() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_CREATEOFFEROBSERVER_H
|
||||||
31
Samples/PeerConnection/DataChannelObserver.cpp
Normal file
31
Samples/PeerConnection/DataChannelObserver.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DataChannelObserver.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
|
||||||
|
|
||||||
|
DataChannelObserver::DataChannelObserver(
|
||||||
|
webrtc::DataChannelInterface *dataChannel): _dataChannel(dataChannel) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataChannelObserver::OnStateChange() {
|
||||||
|
Console::Print("[DataChannelObserver::OnStateChange] %s",
|
||||||
|
webrtc::DataChannelInterface::DataStateString(_dataChannel->state()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataChannelObserver::OnMessage(const webrtc::DataBuffer& buffer) {
|
||||||
|
size_t len = buffer.size();
|
||||||
|
const unsigned char *data = buffer.data.cdata();
|
||||||
|
char *message = new char[len + 1];
|
||||||
|
|
||||||
|
memcpy(message, data, len);
|
||||||
|
message[len] = '\0';
|
||||||
|
|
||||||
|
Console::Print("<Remote> %s", message);
|
||||||
|
delete[] message;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataChannelObserver::OnBufferedAmountChange(uint64_t previous_amount) {
|
||||||
|
}
|
||||||
22
Samples/PeerConnection/DataChannelObserver.h
Normal file
22
Samples/PeerConnection/DataChannelObserver.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_DATACHANNELOBSERVER_H
|
||||||
|
#define LIBWEBRTC_DATACHANNELOBSERVER_H
|
||||||
|
|
||||||
|
#include <webrtc/api/datachannelinterface.h>
|
||||||
|
|
||||||
|
class DataChannelObserver: public webrtc::DataChannelObserver {
|
||||||
|
public:
|
||||||
|
DataChannelObserver(webrtc::DataChannelInterface *dataChannel);
|
||||||
|
|
||||||
|
void OnStateChange();
|
||||||
|
void OnMessage(const webrtc::DataBuffer& buffer);
|
||||||
|
void OnBufferedAmountChange(uint64_t previous_amount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
webrtc::DataChannelInterface *_dataChannel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_DATACHANNELOBSERVER_H
|
||||||
186
Samples/PeerConnection/Peer.cpp
Normal file
186
Samples/PeerConnection/Peer.cpp
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 24/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <third_party/jsoncpp/source/include/json/writer.h>
|
||||||
|
#include "Peer.h"
|
||||||
|
#include "Core.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
#include "DataChannelObserver.h"
|
||||||
|
|
||||||
|
using webrtc::PeerConnectionInterface;
|
||||||
|
using webrtc::MediaConstraintsInterface;
|
||||||
|
using webrtc::DataChannelInit;
|
||||||
|
using webrtc::MediaStreamInterface;
|
||||||
|
using webrtc::DataChannelInterface;
|
||||||
|
using webrtc::IceCandidateInterface;
|
||||||
|
using webrtc::SessionDescriptionInterface;
|
||||||
|
|
||||||
|
Peer::Peer() {
|
||||||
|
PeerConnectionInterface::RTCConfiguration config;
|
||||||
|
PeerConnectionInterface::IceServer googleIceServer;
|
||||||
|
|
||||||
|
googleIceServer.uri = "stun:stun.l.google.com:19302";
|
||||||
|
googleIceServer.urls.push_back("stun:stun.l.google.com:19302");
|
||||||
|
googleIceServer.urls.push_back("stun:stun1.l.google.com:19302");
|
||||||
|
googleIceServer.urls.push_back("stun:stun2.l.google.com:19302");
|
||||||
|
googleIceServer.urls.push_back("stun:stun3.l.google.com:19302");
|
||||||
|
googleIceServer.urls.push_back("stun:stun4.l.google.com:19302");
|
||||||
|
|
||||||
|
config.servers.push_back(googleIceServer);
|
||||||
|
|
||||||
|
_dataChannel = NULL;
|
||||||
|
_dataChannelObserver = NULL;
|
||||||
|
_peerConnection = Core::GetPeerConnectionFactory()->
|
||||||
|
CreatePeerConnection(config, &_mediaConstraints,
|
||||||
|
NULL, NULL, this);
|
||||||
|
|
||||||
|
_mediaConstraints.AddOptional(
|
||||||
|
MediaConstraintsInterface::kEnableDtlsSrtp,
|
||||||
|
MediaConstraintsInterface::kValueTrue);
|
||||||
|
|
||||||
|
_mediaConstraints.AddMandatory(
|
||||||
|
MediaConstraintsInterface::kOfferToReceiveAudio,
|
||||||
|
MediaConstraintsInterface::kValueFalse);
|
||||||
|
|
||||||
|
_mediaConstraints.AddMandatory(
|
||||||
|
MediaConstraintsInterface::kOfferToReceiveVideo,
|
||||||
|
MediaConstraintsInterface::kValueFalse);
|
||||||
|
}
|
||||||
|
|
||||||
|
Peer::~Peer() {
|
||||||
|
if (_dataChannel) {
|
||||||
|
_dataChannel->Close();
|
||||||
|
_dataChannel = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_peerConnection->Close();
|
||||||
|
_peerConnection = NULL;
|
||||||
|
|
||||||
|
if (_dataChannelObserver) {
|
||||||
|
_dataChannelObserver = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::CreateOffer(webrtc::CreateSessionDescriptionObserver *createSDPObserver) {
|
||||||
|
DataChannelInit init;
|
||||||
|
|
||||||
|
init.reliable = true;
|
||||||
|
_dataChannel = _peerConnection->CreateDataChannel("MyDataChannel", &init);
|
||||||
|
_dataChannelObserver = new DataChannelObserver(_dataChannel);
|
||||||
|
_dataChannel->RegisterObserver(_dataChannelObserver);
|
||||||
|
|
||||||
|
_peerConnection->CreateOffer(createSDPObserver, &_mediaConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::CreateAnswer(webrtc::CreateSessionDescriptionObserver *createSDPObserver) {
|
||||||
|
_peerConnection->CreateAnswer(createSDPObserver, &_mediaConstraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Peer::AddIceCandidate(webrtc::IceCandidateInterface *candidate) {
|
||||||
|
return _peerConnection->AddIceCandidate(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::SetLocalSessionDescription(SessionDescriptionInterface* desc,
|
||||||
|
webrtc::SetSessionDescriptionObserver *obs) {
|
||||||
|
_peerConnection->SetLocalDescription(obs, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::SetRemoteSessionDescription(SessionDescriptionInterface* desc,
|
||||||
|
webrtc::SetSessionDescriptionObserver *obs) {
|
||||||
|
_peerConnection->SetRemoteDescription(obs, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Peer::IsConnected() {
|
||||||
|
if (!_dataChannel) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _dataChannel->state() == webrtc::DataChannelInterface::kOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::SendMessage(const std::string& message) {
|
||||||
|
webrtc::DataBuffer buffer(message);
|
||||||
|
|
||||||
|
_dataChannel->Send(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* webrtc::PeerConnectionObserver methods
|
||||||
|
*/
|
||||||
|
void Peer::OnSignalingChange(
|
||||||
|
PeerConnectionInterface::SignalingState new_state) {
|
||||||
|
Console::Print("[Peer::OnSignalingChange] new signaling state: %d",
|
||||||
|
new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnAddStream(rtc::scoped_refptr<MediaStreamInterface> stream) {
|
||||||
|
Console::Print("[Peer::OnAddStream]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnRemoveStream(rtc::scoped_refptr<MediaStreamInterface> stream) {
|
||||||
|
Console::Print("[Peer::OnRemoveStream]");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnDataChannel(
|
||||||
|
rtc::scoped_refptr<DataChannelInterface> data_channel) {
|
||||||
|
Console::Print("[Peer::OnDataChannel] %s", data_channel->label().c_str());
|
||||||
|
_dataChannel = data_channel;
|
||||||
|
|
||||||
|
_dataChannelObserver = new DataChannelObserver(_dataChannel);
|
||||||
|
_dataChannel->RegisterObserver(_dataChannelObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnRenegotiationNeeded() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnIceConnectionChange(
|
||||||
|
PeerConnectionInterface::IceConnectionState new_state) {
|
||||||
|
if (new_state == PeerConnectionInterface::kIceConnectionCompleted) {
|
||||||
|
Console::Print("Connected!");
|
||||||
|
} else if (new_state > PeerConnectionInterface::kIceConnectionCompleted) {
|
||||||
|
Console::Print("Disconnected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnIceGatheringChange(
|
||||||
|
PeerConnectionInterface::IceGatheringState new_state) {
|
||||||
|
if (new_state == PeerConnectionInterface::kIceGatheringGathering) {
|
||||||
|
Console::Print("Gathering ICE candidates, please wait.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_state != PeerConnectionInterface::kIceGatheringComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::FastWriter writer;
|
||||||
|
writer.write(_iceCandidates);
|
||||||
|
|
||||||
|
Console::Print("Done, paste this array of ICE candidates once requested." \
|
||||||
|
"\n\n%s", writer.write(_iceCandidates).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnIceCandidate(const IceCandidateInterface* candidate) {
|
||||||
|
Json::Value jmessage;
|
||||||
|
|
||||||
|
jmessage["sdpMid"] = candidate->sdp_mid();
|
||||||
|
jmessage["sdpMLineIndex"] = candidate->sdp_mline_index();
|
||||||
|
std::string sdp;
|
||||||
|
if (!candidate->ToString(&sdp)) {
|
||||||
|
Console::Print("[Peer::OnIceCandidate] Failed to serialize candidate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
jmessage["candidate"] = sdp;
|
||||||
|
_iceCandidates.append(jmessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnIceCandidatesRemoved(
|
||||||
|
const std::vector<cricket::Candidate>& candidates) {
|
||||||
|
Console::Print("[Peer::OnIceCandidatesRemoved]");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peer::OnIceConnectionReceivingChange(bool receiving) {
|
||||||
|
}
|
||||||
62
Samples/PeerConnection/Peer.h
Normal file
62
Samples/PeerConnection/Peer.h
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 24/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_PEER_H
|
||||||
|
#define LIBWEBRTC_PEER_H
|
||||||
|
|
||||||
|
#include <third_party/jsoncpp/source/include/json/value.h>
|
||||||
|
#include "webrtc/api/test/fakeconstraints.h"
|
||||||
|
#include "webrtc/api/peerconnectioninterface.h"
|
||||||
|
|
||||||
|
class Peer : public webrtc::PeerConnectionObserver {
|
||||||
|
public:
|
||||||
|
Peer();
|
||||||
|
~Peer();
|
||||||
|
|
||||||
|
void CreateOffer(webrtc::CreateSessionDescriptionObserver *createSDPObserver);
|
||||||
|
void CreateAnswer(webrtc::CreateSessionDescriptionObserver *createSDPObserver);
|
||||||
|
|
||||||
|
bool AddIceCandidate(webrtc::IceCandidateInterface *candidate);
|
||||||
|
|
||||||
|
void SetLocalSessionDescription(webrtc::SessionDescriptionInterface* desc,
|
||||||
|
webrtc::SetSessionDescriptionObserver *setSDPObserver);
|
||||||
|
void SetRemoteSessionDescription(webrtc::SessionDescriptionInterface* desc,
|
||||||
|
webrtc::SetSessionDescriptionObserver *setSDPObserver);
|
||||||
|
|
||||||
|
bool IsConnected();
|
||||||
|
void SendMessage(const std::string& message);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* webrtc::PeerConnectionObserver methods
|
||||||
|
*/
|
||||||
|
void OnSignalingChange(
|
||||||
|
webrtc::PeerConnectionInterface::SignalingState new_state);
|
||||||
|
|
||||||
|
void OnAddStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
|
||||||
|
void OnRemoveStream(rtc::scoped_refptr<webrtc::MediaStreamInterface> stream);
|
||||||
|
|
||||||
|
void OnDataChannel(
|
||||||
|
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
|
||||||
|
|
||||||
|
void OnRenegotiationNeeded();
|
||||||
|
|
||||||
|
void OnIceConnectionChange(
|
||||||
|
webrtc::PeerConnectionInterface::IceConnectionState new_state);
|
||||||
|
void OnIceGatheringChange(
|
||||||
|
webrtc::PeerConnectionInterface::IceGatheringState new_state);
|
||||||
|
|
||||||
|
void OnIceCandidate(const webrtc::IceCandidateInterface* candidate);
|
||||||
|
void OnIceCandidatesRemoved(
|
||||||
|
const std::vector<cricket::Candidate>& candidates);
|
||||||
|
void OnIceConnectionReceivingChange(bool receiving);
|
||||||
|
|
||||||
|
private:
|
||||||
|
rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
|
||||||
|
webrtc::FakeConstraints _mediaConstraints;
|
||||||
|
rtc::scoped_refptr<webrtc::DataChannelInterface> _dataChannel;
|
||||||
|
webrtc::DataChannelObserver *_dataChannelObserver;
|
||||||
|
Json::Value _iceCandidates;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_PEER_H
|
||||||
5
Samples/PeerConnection/PeerConnectionObserver.cpp
Normal file
5
Samples/PeerConnection/PeerConnectionObserver.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PeerConnectionObserver.h"
|
||||||
14
Samples/PeerConnection/PeerConnectionObserver.h
Normal file
14
Samples/PeerConnection/PeerConnectionObserver.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_PEERCONNECTIONOBSERVER_H
|
||||||
|
#define LIBWEBRTC_PEERCONNECTIONOBSERVER_H
|
||||||
|
|
||||||
|
|
||||||
|
class PeerConnectionObserver {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_PEERCONNECTIONOBSERVER_H
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <third_party/jsoncpp/source/include/json/writer.h>
|
||||||
|
#include "SetLocalSessionDescriptionObserver.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
|
||||||
|
SetLocalSessionDescriptionObserver::SetLocalSessionDescriptionObserver(
|
||||||
|
webrtc::SessionDescriptionInterface* desc): _desc(desc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLocalSessionDescriptionObserver::OnSuccess() {
|
||||||
|
std::string sdp;
|
||||||
|
|
||||||
|
_desc->ToString(&sdp);
|
||||||
|
|
||||||
|
Json::FastWriter writer;
|
||||||
|
Json::Value jmessage;
|
||||||
|
jmessage["type"] = _desc->type();
|
||||||
|
jmessage["sdp"] = sdp;
|
||||||
|
|
||||||
|
Console::Print("Here is the SDP, paste it to the remote client and paste " \
|
||||||
|
"their answer here.\n\n%s", writer.write(jmessage).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLocalSessionDescriptionObserver::OnFailure(const std::string& error) {
|
||||||
|
Console::Print("[SetLocalSessionDescriptionObserver::OnFailure] %s",
|
||||||
|
error.c_str());
|
||||||
|
}
|
||||||
27
Samples/PeerConnection/SetLocalSessionDescriptionObserver.h
Normal file
27
Samples/PeerConnection/SetLocalSessionDescriptionObserver.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_SETLOCALSESSIONDESCRIPTIONOBSERVER_H
|
||||||
|
#define LIBWEBRTC_SETLOCALSESSIONDESCRIPTIONOBSERVER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <webrtc/api/jsep.h>
|
||||||
|
|
||||||
|
class SetLocalSessionDescriptionObserver:
|
||||||
|
public webrtc::SetSessionDescriptionObserver {
|
||||||
|
public:
|
||||||
|
SetLocalSessionDescriptionObserver(webrtc::SessionDescriptionInterface* desc);
|
||||||
|
|
||||||
|
void OnSuccess();
|
||||||
|
void OnFailure(const std::string& error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
webrtc::SessionDescriptionInterface* _desc;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~SetLocalSessionDescriptionObserver() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_SETLOCALSESSIONDESCRIPTIONOBSERVER_H
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SetRemoteSessionDescriptionObserver.h"
|
||||||
|
#include "CreateSessionObserver.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
|
||||||
|
|
||||||
|
SetRemoteSessionDescriptionObserver::SetRemoteSessionDescriptionObserver(
|
||||||
|
Peer *peer, webrtc::SessionDescriptionInterface* desc):
|
||||||
|
_peer(peer), _desc(desc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRemoteSessionDescriptionObserver::OnSuccess() {
|
||||||
|
if (_desc->type() == webrtc::SessionDescriptionInterface::kOffer) {
|
||||||
|
rtc::scoped_refptr<CreateSessionObserver> createAnswerObserver =
|
||||||
|
new rtc::RefCountedObject<CreateSessionObserver>(_peer);
|
||||||
|
|
||||||
|
_peer->CreateAnswer(createAnswerObserver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRemoteSessionDescriptionObserver::OnFailure(const std::string& error) {
|
||||||
|
Console::Print("[SetRemoteSessionDescriptionObserver::OnFailure] %s",
|
||||||
|
error.c_str());
|
||||||
|
}
|
||||||
28
Samples/PeerConnection/SetRemoteSessionDescriptionObserver.h
Normal file
28
Samples/PeerConnection/SetRemoteSessionDescriptionObserver.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_SETREMOTESESSIONDESCRIPTIONOBSERVER_H
|
||||||
|
#define LIBWEBRTC_SETREMOTESESSIONDESCRIPTIONOBSERVER_H
|
||||||
|
|
||||||
|
#include <webrtc/api/jsep.h>
|
||||||
|
#include "Peer.h"
|
||||||
|
|
||||||
|
class SetRemoteSessionDescriptionObserver:
|
||||||
|
public webrtc::SetSessionDescriptionObserver {
|
||||||
|
public:
|
||||||
|
SetRemoteSessionDescriptionObserver(Peer *peer, webrtc::SessionDescriptionInterface* desc);
|
||||||
|
|
||||||
|
void OnSuccess();
|
||||||
|
void OnFailure(const std::string& error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Peer *_peer;
|
||||||
|
webrtc::SessionDescriptionInterface* _desc;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~SetRemoteSessionDescriptionObserver() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_SETREMOTESESSIONDESCRIPTIONOBSERVER_H
|
||||||
153
Samples/PeerConnection/UnixConsole.cpp
Normal file
153
Samples/PeerConnection/UnixConsole.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
|
||||||
|
static int ttyErase;
|
||||||
|
static int ttyEof;
|
||||||
|
static struct termios ttyTc;
|
||||||
|
|
||||||
|
static size_t cursor;
|
||||||
|
static std::string buffer;
|
||||||
|
|
||||||
|
bool Console::Init() {
|
||||||
|
struct termios tc;
|
||||||
|
const char* term = getenv("TERM");
|
||||||
|
|
||||||
|
signal(SIGTTIN, SIG_IGN);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
signal(SIGCONT, Console::Reset);
|
||||||
|
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK );
|
||||||
|
|
||||||
|
if (!(isatty(STDIN_FILENO) &&
|
||||||
|
!(term && (!strcmp(term, "raw") || !strcmp(term, "dumb"))))) {
|
||||||
|
std::cerr << "Input is not a tty." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcgetattr (STDIN_FILENO, &ttyTc);
|
||||||
|
ttyErase = ttyTc.c_cc[VERASE];
|
||||||
|
ttyEof = ttyTc.c_cc[VEOF];
|
||||||
|
|
||||||
|
tc = ttyTc;
|
||||||
|
tc.c_lflag &= ~(ECHO | ICANON);
|
||||||
|
tc.c_iflag &= ~(ISTRIP | INPCK);
|
||||||
|
tc.c_cc[VMIN] = 1;
|
||||||
|
tc.c_cc[VTIME] = 0;
|
||||||
|
tcsetattr (STDIN_FILENO, TCSADRAIN, &tc);
|
||||||
|
|
||||||
|
cursor = 0;
|
||||||
|
buffer.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Console::Update(std::string &input) {
|
||||||
|
char key;
|
||||||
|
ssize_t avail = read(STDIN_FILENO, &key, 1);
|
||||||
|
|
||||||
|
input.clear();
|
||||||
|
if (avail == -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == ttyEof) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((key == ttyErase) || (key == 127) || (key == 8)) && cursor > 0)
|
||||||
|
{
|
||||||
|
buffer.erase(--cursor, 1);
|
||||||
|
Console::Back();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == '\n') {
|
||||||
|
input = buffer;
|
||||||
|
cursor = 0;
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
key = '>';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
key = ' ';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key < ' ') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor++;
|
||||||
|
buffer.append(1, key);
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Cleanup() {
|
||||||
|
tcsetattr (STDIN_FILENO, TCSADRAIN, &ttyTc);
|
||||||
|
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Reset(int num) {
|
||||||
|
Console::Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Show() {
|
||||||
|
char key;
|
||||||
|
|
||||||
|
key = '>';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
key = ' ';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cursor; i++) {
|
||||||
|
key = buffer.at(i);
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Hide() {
|
||||||
|
for (int i = 0; i < cursor + 2; i++) {
|
||||||
|
Console::Back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Print(const std::string &fmt, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
char string[1024];
|
||||||
|
|
||||||
|
if (!fmt.length()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
vsnprintf(string, sizeof(string), fmt.c_str(), argptr);
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
Console::Hide();
|
||||||
|
std::cout << string << std::endl;
|
||||||
|
Console::Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::Back()
|
||||||
|
{
|
||||||
|
char key;
|
||||||
|
|
||||||
|
key = '\b';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
key = ' ';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
key = '\b';
|
||||||
|
write(STDOUT_FILENO, &key, 1);
|
||||||
|
}
|
||||||
20
Samples/PeerConnection/UnixConsole.h
Normal file
20
Samples/PeerConnection/UnixConsole.h
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Created by ax on 25/09/16.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef LIBWEBRTC_UNIXCONSOLE_H
|
||||||
|
#define LIBWEBRTC_UNIXCONSOLE_H
|
||||||
|
|
||||||
|
class Console {
|
||||||
|
public:
|
||||||
|
static bool Init();
|
||||||
|
static bool Update(std::string &input);
|
||||||
|
static void Cleanup();
|
||||||
|
static void Reset(int num);
|
||||||
|
static void Print(const std::string &line, ...);
|
||||||
|
static void Show();
|
||||||
|
static void Hide();
|
||||||
|
static void Back();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //LIBWEBRTC_UNIXCONSOLE_H
|
||||||
140
Samples/PeerConnection/main.cpp
Normal file
140
Samples/PeerConnection/main.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <third_party/jsoncpp/source/include/json/reader.h>
|
||||||
|
#include "Core.h"
|
||||||
|
#include "CreateSessionObserver.h"
|
||||||
|
#include "DataChannelObserver.h"
|
||||||
|
#include "Peer.h"
|
||||||
|
#include "SetRemoteSessionDescriptionObserver.h"
|
||||||
|
#include "UnixConsole.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STATE_EXCHANGE = 0,
|
||||||
|
STATE_CHAT
|
||||||
|
};
|
||||||
|
|
||||||
|
static Peer *peer = NULL;
|
||||||
|
static int state = STATE_EXCHANGE;
|
||||||
|
|
||||||
|
void HandleSDP(Json::Value object) {
|
||||||
|
std::string type = object["type"].asString();
|
||||||
|
std::string sdp = object["sdp"].asString();
|
||||||
|
|
||||||
|
webrtc::SdpParseError error;
|
||||||
|
webrtc::SessionDescriptionInterface* desc(
|
||||||
|
webrtc::CreateSessionDescription(type, sdp, &error));
|
||||||
|
|
||||||
|
if (!desc) {
|
||||||
|
Console::Print("Can't parse the SDP: %s", error.description);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::scoped_refptr<SetRemoteSessionDescriptionObserver> observer =
|
||||||
|
new rtc::RefCountedObject<SetRemoteSessionDescriptionObserver>(peer, desc);
|
||||||
|
|
||||||
|
peer->SetRemoteSessionDescription(desc, observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleICECandidate(Json::Value object) {
|
||||||
|
std::string sdp_mid = object["sdpMid"].asString();
|
||||||
|
int sdp_mlineindex = object["sdpMLineIndex"].asInt();
|
||||||
|
std::string sdp = object["candidate"].asString();
|
||||||
|
|
||||||
|
webrtc::SdpParseError error;
|
||||||
|
std::unique_ptr<webrtc::IceCandidateInterface> candidate(
|
||||||
|
webrtc::CreateIceCandidate(sdp_mid, sdp_mlineindex, sdp, &error));
|
||||||
|
|
||||||
|
if (!candidate.get()) {
|
||||||
|
Console::Print("Can't parse the ICE candidate: %s", error.description);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!peer->AddIceCandidate(candidate.get())) {
|
||||||
|
Console::Print("Failed to add the ICE candidate.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleObject(Json::Value object) {
|
||||||
|
if (object.isMember("type") && object["type"].isString() &&
|
||||||
|
object.isMember("sdp") && object["sdp"].isString()) {
|
||||||
|
HandleSDP(object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.isMember("candidate") && object["candidate"].isString() &&
|
||||||
|
object.isMember("sdpMLineIndex") && object["sdpMLineIndex"].isNumeric() &&
|
||||||
|
object.isMember("sdpMid") && object["sdpMid"].isString()) {
|
||||||
|
HandleICECandidate(object);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::Print("Unknown object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleCommand(const std::string& input) {
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value jmessage;
|
||||||
|
|
||||||
|
if (peer->IsConnected()) {
|
||||||
|
peer->SendMessage(input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reader.parse(input, jmessage)) {
|
||||||
|
Console::Print("Invalid JSON string.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jmessage.isArray()) {
|
||||||
|
for (Json::ValueIterator it = jmessage.begin();
|
||||||
|
it != jmessage.end(); it++) {
|
||||||
|
if (!(*it).isObject()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleObject(*it);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jmessage.isObject()) {
|
||||||
|
HandleObject(jmessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::Print("Must be an array or object.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
std::string input;
|
||||||
|
|
||||||
|
if (!Console::Init()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core::Init();
|
||||||
|
|
||||||
|
peer = new Peer();
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
rtc::scoped_refptr<CreateSessionObserver> createOfferObserver =
|
||||||
|
new rtc::RefCountedObject<CreateSessionObserver>(peer);
|
||||||
|
|
||||||
|
peer->CreateOffer(createOfferObserver);
|
||||||
|
} else {
|
||||||
|
Console::Print("Recipient mode. Paste the offer made by the emitter.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Console::Update(input)) {
|
||||||
|
if (input.length()) {
|
||||||
|
HandleCommand(input);
|
||||||
|
}
|
||||||
|
Core::Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete peer;
|
||||||
|
|
||||||
|
Core::Cleanup();
|
||||||
|
Console::Cleanup();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue