@@ -1,4 +1,5 @@ | |||
/include | |||
/include/webrtc | |||
/libs | |||
/depot_tools | |||
/webrtc-checkout | |||
/build |
@@ -1,4 +1,5 @@ | |||
WEBRTC_DIR ?= . | |||
WEBRTC_BASE ?= . | |||
WEBRTC_DIR ?= $(WEBRTC_BASE) | |||
WEBRTC_VERSION ?= m79 | |||
WEBRTC_OUT ?= Release | |||
WEBRTC_GN_ARGS ?= \ | |||
@@ -11,18 +12,29 @@ WEBRTC_GN_ARGS ?= \ | |||
WEBRTC_TARGETS ?= default $(WEBRTC_TARGETS_EXTRA) | |||
WEBRTC_LIBS ?= libwebrtc.a $(WEBRTC_LIBS_EXTRA) | |||
WEBRTC_INCLUDES = \ | |||
api audio base common_audio common_video logging media modules p2p pc \ | |||
rtc_base rtc_tools video common_types.h \ | |||
api audio base call common_audio common_video logging media modules p2p pc \ | |||
system_wrappers rtc_base rtc_tools video third_party common_types.h \ | |||
$(WEBRTC_INCLUDES_EXTRA) | |||
SETPATH = PATH=$(WEBRTC_DIR)/depot_tools:"$$PATH" | |||
WEBRTC_PLATFORM ?= POSIX | |||
WEBRTC_FLAGS ?= \ | |||
-I$(WEBRTC_BASE)/include -I$(WEBRTC_BASE)/include/webrtc \ | |||
-I$(WEBRTC_BASE)/include/webrtc/third_party/abseil-cpp \ | |||
-DWEBRTC_$(WEBRTC_PLATFORM) | |||
WEBRTC_SETPATH = PATH=$(WEBRTC_DIR)/depot_tools:"$$PATH" | |||
RTC_STAMP_DEPOT = $(WEBRTC_DIR)/depot_tools/.stamp | |||
RTC_STAMP_REPO = $(WEBRTC_DIR)/webrtc-checkout/.stamp | |||
RTC_STAMP_VERSION = $(WEBRTC_DIR)/webrtc-checkout/.stamps/stamp-$(WEBRTC_VERSION) | |||
RTC_STAMP_COMPILE = $(WEBRTC_DIR)/webrtc-checkout/src/out/$(WEBRTC_OUT)/.stamp | |||
RTC_STAMP_INCLUDES = include/webrtc/.stamp | |||
RTC_STAMP_INCLUDES = $(WEBRTC_BASE)/include/webrtc/.stamp | |||
all: include/webrtc/.stamp $(patsubst %,libs/%,$(WEBRTC_LIBS)) | |||
.PHONY: rtcall | |||
rtcall: | |||
$(WEBRTC_BASE)/include/webrtc/.stamp \ | |||
$(patsubst %,$(WEBRTC_BASE)/libs/%,$(WEBRTC_LIBS)) \ | |||
$(WEBRTC_BASE)/libs/libutil.a | |||
# Get depot_tools, which contains all the tools required to work with Google software | |||
$(RTC_STAMP_DEPOT): | |||
@@ -35,7 +47,7 @@ $(RTC_STAMP_REPO): $(RTC_STAMP_DEPOT) | |||
rm -rf $(WEBRTC_DIR)/webrtc-checkout && mkdir $(WEBRTC_DIR)/webrtc-checkout | |||
# | |||
# Fetch webrtc, thit will take time... | |||
cd $(WEBRTC_DIR)/webrtc-checkout && $(SETPATH) fetch --nohooks --no-history webrtc | |||
cd $(WEBRTC_DIR)/webrtc-checkout && $(WEBRTC_SETPATH) fetch --nohooks --no-history webrtc | |||
touch $@ | |||
# Check out the correct WebRTC branch/commit | |||
@@ -44,13 +56,13 @@ $(RTC_STAMP_VERSION): $(RTC_STAMP_REPO) | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && git checkout branch-heads/$(WEBRTC_VERSION) | |||
# | |||
# Sync webrtc, this will take time... | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(SETPATH) gclient sync -D --nohooks | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(WEBRTC_SETPATH) gclient sync -D --nohooks | |||
touch $@ | |||
# Compile | |||
$(RTC_STAMP_COMPILE): | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(SETPATH) gn gen out/$(WEBRTC_OUT) --args='$(WEBRTC_GN_ARGS)' | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(SETPATH) ninja -C out/$(WEBRTC_OUT) $(WEBRTC_TARGETS) | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(WEBRTC_SETPATH) gn gen out/$(WEBRTC_OUT) --args='$(WEBRTC_GN_ARGS)' | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(WEBRTC_SETPATH) ninja -C out/$(WEBRTC_OUT) $(WEBRTC_TARGETS) | |||
touch $@ | |||
# Includes | |||
@@ -62,15 +74,31 @@ $(RTC_STAMP_INCLUDES): $(RTC_STAMP_VERSION) | |||
touch $@ | |||
# Libraries | |||
libs/%.a: $(WEBRTC_DIR)/webrtc-checkout/src/out/$(WEBRTC_OUT)/obj/%.a | |||
$(WEBRTC_BASE)/libs/%.a: $(WEBRTC_DIR)/webrtc-checkout/src/out/$(WEBRTC_OUT)/obj/%.a | |||
@mkdir -p $(@D) | |||
cp $< $@ | |||
.PHONY: clean | |||
clean: | |||
# Util | |||
$(WEBRTC_BASE)/libs/libutil.a: $(WEBRTC_BASE)/build/util/Conductor.cc.o | |||
@mkdir -p $(@D) | |||
ar cr $@ $^ | |||
$(WEBRTC_BASE)/build/%.cc.o: $(WEBRTC_BASE)/%.cc $(RTC_STAMP_INCLUDES) $(wildcard $(WEBRTC_BASE)/util/*.h) | |||
@mkdir -p $(@D) | |||
$(CXX) $(CXXFLAGS) $(WEBRTC_FLAGS) -c $< -o $@ | |||
.PHONY: rtcclean | |||
rtcclean: | |||
rm -rf include libs build | |||
.PHONY: rtccleanall | |||
rtccleanall: rtcclean | |||
rm -rf $(WEBRTC_DIR)/depot_tools $(WEBRTC_DIR)/webrtc-checkout | |||
rm -rf include libs | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(WEBRTC_SETPATH) gn clean out/$(WEBRTC_OUT) | |||
.PHONY: gn-clean | |||
gn-clean: | |||
cd $(WEBRTC_DIR)/webrtc-checkout/src && $(SETPATH) gn clean out/$(WEBRTC_OUT) | |||
.PHONY: mockstamps | |||
rtcmockstamps: | |||
mkdir -p $(dir $(RTC_STAMP_DEPOT)) && touch $(RTC_STAMP_DEPOT) | |||
mkdir -p $(dir $(RTC_STAMP_REPO)) && touch $(RTC_STAMP_REPO) | |||
mkdir -p $(dir $(RTC_STAMP_VERSION)) && touch $(RTC_STAMP_VERSION) | |||
mkdir -p $(dir $(RTC_STAMP_COMPILE)) && touch $(RTC_STAMP_COMPILE) | |||
mkdir -p $(dir $(RTC_STAMP_INCLUDES)) && touch $(RTC_STAMP_INCLUDES) |
@@ -0,0 +1,71 @@ | |||
#include <webrtc/api/peer_connection_interface.h> | |||
#include <memory> | |||
namespace rtcutil { | |||
class ConductorObserver { | |||
public: | |||
enum class ErrorType { | |||
WARNING, | |||
RECEIVE_OFFER, | |||
RECEIVE_ICE_CANDIDATE, | |||
CREATE_ANSWER, | |||
}; | |||
virtual void onError(ErrorType type, std::string err); | |||
virtual void onIceCandidate(std::string mid, int index, std::string sdp) = 0; | |||
virtual void onAnswer(std::string sdp) = 0; | |||
virtual void onRemoteTrack(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track); | |||
virtual void removeRemoteTrack(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track); | |||
}; | |||
class Conductor: | |||
public webrtc::PeerConnectionObserver, | |||
public webrtc::CreateSessionDescriptionObserver { | |||
public: | |||
Conductor(ConductorObserver &observer): observer_(observer) {} | |||
void receiveOffer(const std::string &sdp); | |||
void receiveOffer(std::unique_ptr<webrtc::SessionDescriptionInterface> offer); | |||
void receiveIceCandidate(std::string mid, int index, std::string sdp); | |||
void ensurePeerConnection(); | |||
protected: | |||
// PeerConnectionObserver | |||
void OnAddTrack( | |||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, | |||
const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override; | |||
void OnRemoveTrack( | |||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override; | |||
void OnIceCandidate(const webrtc::IceCandidateInterface *candidate) override; | |||
void OnSignalingChange( | |||
webrtc::PeerConnectionInterface::SignalingState new_state) override {} | |||
void OnDataChannel( | |||
rtc::scoped_refptr<webrtc::DataChannelInterface> channel) override {} | |||
void OnRenegotiationNeeded() override {} | |||
void OnIceConnectionChange( | |||
webrtc::PeerConnectionInterface::IceConnectionState new_state) override {} | |||
void OnIceGatheringChange( | |||
webrtc::PeerConnectionInterface::IceGatheringState new_state) override {} | |||
void OnIceConnectionReceivingChange(bool receiving) override {} | |||
// CreateSessionDescriptionObserver | |||
void OnSuccess(webrtc::SessionDescriptionInterface* desc) override; | |||
void OnFailure(webrtc::RTCError error) override; | |||
// Overridables for consumers | |||
virtual rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> | |||
doCreatePeerConnectionFactory(); | |||
virtual rtc::scoped_refptr<webrtc::PeerConnectionInterface> | |||
doCreatePeerConnection(webrtc::PeerConnectionFactoryInterface &factory); | |||
virtual void doAddTracks(webrtc::PeerConnectionInterface &conn) {}; | |||
ConductorObserver &observer_; | |||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> peer_conn_factory_; | |||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_conn_; | |||
}; | |||
} |
@@ -0,0 +1,164 @@ | |||
#include "Conductor.h" | |||
#include <webrtc/api/create_peerconnection_factory.h> | |||
#include <webrtc/api/audio_codecs/builtin_audio_encoder_factory.h> | |||
#include <webrtc/api/audio_codecs/builtin_audio_decoder_factory.h> | |||
#include <webrtc/api/video_codecs/builtin_video_encoder_factory.h> | |||
#include <webrtc/api/video_codecs/builtin_video_decoder_factory.h> | |||
#include <webrtc/pc/video_track_source.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
namespace rtcutil { | |||
void ConductorObserver::onError(ErrorType type, std::string err) { | |||
if (type == ErrorType::WARNING) { | |||
fprintf(stderr, "Warning: %s\n", err.c_str()); | |||
} else { | |||
fprintf(stderr, "Error: %s\n", err.c_str()); | |||
abort(); | |||
} | |||
} | |||
class SetSessionDescriptionObserver: public webrtc::SetSessionDescriptionObserver { | |||
public: | |||
SetSessionDescriptionObserver(ConductorObserver &observer): observer_(observer) {} | |||
static SetSessionDescriptionObserver* Create(ConductorObserver &observer) { | |||
return new rtc::RefCountedObject<SetSessionDescriptionObserver>(observer); | |||
} | |||
virtual void OnSuccess() {} | |||
virtual void OnFailure(webrtc::RTCError error) { | |||
observer_.onError(ConductorObserver::ErrorType::RECEIVE_OFFER, | |||
error.message()); | |||
} | |||
private: | |||
ConductorObserver &observer_; | |||
}; | |||
void Conductor::receiveOffer(const std::string &sdp) { | |||
webrtc::SdpParseError error; | |||
std::unique_ptr<webrtc::SessionDescriptionInterface> desc = | |||
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, sdp, &error); | |||
if (!desc.get()) { | |||
observer_.onError(ConductorObserver::ErrorType::RECEIVE_OFFER, | |||
std::move(error.description)); | |||
return; | |||
} | |||
receiveOffer(std::move(desc)); | |||
} | |||
void Conductor::receiveOffer(std::unique_ptr<webrtc::SessionDescriptionInterface> offer) { | |||
ensurePeerConnection(); | |||
peer_conn_->SetRemoteDescription( | |||
SetSessionDescriptionObserver::Create(observer_), | |||
offer.release()); | |||
peer_conn_->CreateAnswer( | |||
this, webrtc::PeerConnectionInterface::RTCOfferAnswerOptions()); | |||
} | |||
void Conductor::receiveIceCandidate(std::string mid, int index, std::string sdp) { | |||
webrtc::SdpParseError error; | |||
std::unique_ptr<webrtc::IceCandidateInterface> candidate( | |||
webrtc::CreateIceCandidate(mid, index, sdp, &error)); | |||
if (!candidate.get()) { | |||
observer_.onError(ConductorObserver::ErrorType::WARNING, | |||
std::move(error.description)); | |||
return; | |||
} | |||
if (!peer_conn_->AddIceCandidate(candidate.get())) { | |||
observer_.onError(ConductorObserver::ErrorType::WARNING, | |||
"Failed to apply the received candidate"); | |||
return; | |||
} | |||
} | |||
void Conductor::ensurePeerConnection() { | |||
if (peer_conn_factory_.get()) | |||
return; | |||
peer_conn_factory_ = doCreatePeerConnectionFactory(); | |||
peer_conn_ = doCreatePeerConnection(*peer_conn_factory_); | |||
} | |||
void Conductor::OnAddTrack( | |||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, | |||
const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) { | |||
observer_.onRemoteTrack(std::move(receiver->track())); | |||
} | |||
void Conductor::OnRemoveTrack( | |||
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) { | |||
observer_.removeRemoteTrack(std::move(receiver->track())); | |||
} | |||
void Conductor::OnIceCandidate(const webrtc::IceCandidateInterface* candidate) { | |||
std::string sdp; | |||
if (!candidate->ToString(&sdp)) { | |||
observer_.onError(ConductorObserver::ErrorType::WARNING, | |||
"Failed to serialize candidate"); | |||
return; | |||
} | |||
observer_.onIceCandidate( | |||
std::move(candidate->sdp_mid()), | |||
candidate->sdp_mline_index(), | |||
std::move(sdp)); | |||
} | |||
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> | |||
Conductor::doCreatePeerConnectionFactory() { | |||
return webrtc::CreatePeerConnectionFactory( | |||
nullptr /* network_thread */, nullptr /* worker_thread */, | |||
nullptr /* signaling_thread */, nullptr /* default_adm */, | |||
webrtc::CreateBuiltinAudioEncoderFactory(), | |||
webrtc::CreateBuiltinAudioDecoderFactory(), | |||
webrtc::CreateBuiltinVideoEncoderFactory(), | |||
webrtc::CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */, | |||
nullptr /* audio_processing */); | |||
} | |||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> | |||
Conductor::doCreatePeerConnection(webrtc::PeerConnectionFactoryInterface &factory) { | |||
webrtc::PeerConnectionInterface::RTCConfiguration config; | |||
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan; | |||
webrtc::PeerConnectionInterface::IceServer server; | |||
const char *uri = getenv("WEBRTC_CONNECT"); | |||
if (uri) { | |||
server.uri = uri; | |||
} else { | |||
server.uri = "stun:stun.l.google.com:19302"; | |||
} | |||
config.servers.push_back(server); | |||
rtc::scoped_refptr<webrtc::PeerConnectionInterface> conn = | |||
factory.CreatePeerConnection( | |||
config, nullptr, nullptr, this); | |||
doAddTracks(*conn); | |||
return conn; | |||
} | |||
void Conductor::OnSuccess(webrtc::SessionDescriptionInterface *desc) { | |||
peer_conn_->SetLocalDescription( | |||
SetSessionDescriptionObserver::Create(observer_), desc); | |||
std::string sdp; | |||
desc->ToString(&sdp); | |||
observer_.onAnswer(std::move(sdp)); | |||
} | |||
void Conductor::OnFailure(webrtc::RTCError error) { | |||
observer_.onError(ConductorObserver::ErrorType::WARNING, | |||
error.message()); | |||
} | |||
} |