[WebRTC] updated to upstream branch 49 and related.

this patch is based on 38d7a7883...226f2f0bd
This commit is contained in:
roytam1 2021-10-01 10:48:39 +08:00
commit a3239eaa4d
2838 changed files with 151221 additions and 159688 deletions

View file

@ -8,18 +8,18 @@ include('/build/gyp.mozbuild')
webrtc_non_unified_sources = [
'trunk/webrtc/common_audio/vad/vad_core.c', # Because of name clash in the kInitCheck variable
'trunk/webrtc/common_audio/vad/webrtc_vad.c', # Because of name clash in the kInitCheck variable
'trunk/webrtc/modules/audio_coding/acm2/codec_manager.cc', # Because of duplicate IsCodecRED/etc
'trunk/webrtc/modules/audio_coding/codecs/g722/g722_decode.c', # Because of name clash in the saturate function
'trunk/webrtc/modules/audio_coding/codecs/g722/g722_encode.c', # Because of name clash in the saturate function
'trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c', # Because of name clash in the kDampFilter variable
'trunk/webrtc/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c', # Because of name clash in the kDampFilter variable
'trunk/webrtc/modules/audio_coding/main/acm2/codec_manager.cc', # Because of duplicate IsCodecRED/etc
'trunk/webrtc/modules/audio_coding/neteq/audio_vector.cc', # Because of explicit template specializations
'trunk/webrtc/modules/audio_device/android/audio_manager.cc', # Because of TAG redefinition
'trunk/webrtc/modules/audio_device/android/audio_record_jni.cc', # Becuse of commonly named module static vars
'trunk/webrtc/modules/audio_device/android/audio_track_jni.cc', # Becuse of commonly named module static vars
'trunk/webrtc/modules/audio_device/android/audio_track_jni.cc', # Becuse of commonly named module static vars
'trunk/webrtc/modules/audio_device/android/opensles_player.cc', # Because of TAG redefinition
'trunk/webrtc/modules/audio_device/linux/audio_device_pulse_linux.cc', # Because of LATE()
'trunk/webrtc/modules/audio_device/linux/audio_mixer_manager_pulse_linux.cc',# Because of LATE()
'trunk/webrtc/modules/audio_device/opensl/opensles_input.cc', # Because of name clash in the kOption variable
'trunk/webrtc/modules/audio_device/opensl/opensles_output.cc', # Because of name clash in the kOption variable
'trunk/webrtc/modules/audio_device/opensl/single_rw_fifo.cc', # Because of name clash with #define FF
'trunk/webrtc/modules/audio_device/win/audio_device_core_win.cc', # Because of ordering assumptions in strsafe.h
'trunk/webrtc/modules/audio_processing/aec/aec_core.c', # Because of name clash in the ComfortNoise function
@ -34,12 +34,15 @@ webrtc_non_unified_sources = [
'trunk/webrtc/modules/audio_processing/gain_control_impl.cc', # Because of name clash in the Handle typedef
'trunk/webrtc/modules/audio_processing/high_pass_filter_impl.cc', # Because of name clash in the Handle typedef
'trunk/webrtc/modules/audio_processing/noise_suppression_impl.cc', # Because of name clash in the Handle typedef
'trunk/webrtc/modules/remote_bitrate_estimator/mimd_rate_control.cc', # Because of duplicate definitions of static consts against aimd_rate_control.cc
'trunk/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc', # Because of duplicate definitions of static consts against remote_bitrate_estimator_abs_send_time.cc
'trunk/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbn.cc', # Because of identically named functions and vars between tmmbr.cc and tmmbn.cc in an anonymous namespaces
'trunk/webrtc/modules/rtp_rtcp/source/rtcp_packet/tmmbr.cc', # Because of identically named functions and vars between tmmbr.cc and tmmbn.cc in an anonymous namespaces
'trunk/webrtc/modules/video_capture/android/device_info_android.cc', # Because of duplicate module static variable names
'trunk/webrtc/modules/video_capture/android/video_capture_android.cc', # Because of duplicate module static variable names
'trunk/webrtc/modules/video_capture/windows/device_info_ds.cc', # Because of the MEDIASUBTYPE_HDYC variable
'trunk/webrtc/modules/video_capture/windows/help_functions_ds.cc', # Because of initguid.h
'trunk/webrtc/modules/video_capture/windows/sink_filter_ds.cc', # Because of the MEDIASUBTYPE_HDYC variable and initguid.h
'trunk/webrtc/video_engine/overuse_frame_detector.cc', # Because of name clash with call_stats.cc on kWeightFactor
'trunk/webrtc/video/overuse_frame_detector.cc', # Because of name clash with call_stats.cc on kWeightFactor
]
GYP_DIRS += ['trunk']
@ -65,7 +68,6 @@ if CONFIG['MOZ_WEBRTC_SIGNALING']:
'signaling/src/common/browser_logging/CSFLog.cpp',
'signaling/src/jsep/JsepSessionImpl.cpp',
'signaling/src/media-conduit/AudioConduit.cpp',
'signaling/src/media-conduit/CodecStatistics.cpp',
'signaling/src/media-conduit/MediaCodecVideoCodec.cpp',
'signaling/src/media-conduit/VideoConduit.cpp',
'signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp',

View file

@ -94,8 +94,6 @@
'./src/media-conduit/AudioConduit.cpp',
'./src/media-conduit/VideoConduit.h',
'./src/media-conduit/VideoConduit.cpp',
'./src/media-conduit/CodecStatistics.h',
'./src/media-conduit/CodecStatistics.cpp',
'./src/media-conduit/RunningStat.h',
# Common
'./src/common/CommonTypes.h',

View file

@ -41,6 +41,18 @@ public:
scaleDownBy == constraints.scaleDownBy;
}
/**
* This returns true if the constraints affecting resolution are equal.
*/
bool ResolutionEquals(const EncodingConstraints& constraints) const
{
return
maxWidth == constraints.maxWidth &&
maxHeight == constraints.maxHeight &&
maxFs == constraints.maxFs &&
scaleDownBy == constraints.scaleDownBy;
}
uint32_t maxWidth;
uint32_t maxHeight;
uint32_t maxFps;

View file

@ -8,7 +8,7 @@
#include "mozilla/Attributes.h"
#include "webrtc/common_types.h"
#include "webrtc/transport.h"
namespace mozilla {
@ -18,6 +18,23 @@ namespace mozilla {
class NullTransport : public webrtc::Transport
{
public:
virtual bool SendRtp(const uint8_t* packet,
size_t length,
const webrtc::PacketOptions& options) override
{
(void) packet;
(void) length;
(void) options;
return true;
}
virtual bool SendRtcp(const uint8_t* packet, size_t length) override
{
(void) packet;
(void) length;
return true;
}
#if 0
virtual int SendPacket(int channel, const void *data, size_t len)
{
(void) channel; (void) data;
@ -29,7 +46,7 @@ public:
(void) channel; (void) data;
return len;
}
#endif
NullTransport() {}
virtual ~NullTransport() {}

View file

@ -6,7 +6,7 @@
#include "mozilla/Logging.h"
#include "prenv.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "nscore.h"
#ifdef MOZILLA_INTERNAL_API

View file

@ -4,6 +4,7 @@
#include "logging.h"
#include "webrtc/config.h"
#include "signaling/src/jsep/JsepSessionImpl.h"
#include <string>
#include <set>
@ -116,15 +117,35 @@ JsepSessionImpl::AddTrack(const RefPtr<JsepTrack>& track)
{
mLastError.clear();
MOZ_ASSERT(track->GetDirection() == sdp::kSend);
MOZ_MTLOG(ML_DEBUG, "Adding track.");
if (track->GetMediaType() != SdpMediaSection::kApplication) {
track->SetCNAME(mCNAME);
if (track->GetSsrcs().empty()) {
uint32_t ssrc;
// Establish minimum number of required SSRCs
// Note that AddTrack is only for send direction
size_t minimumSsrcCount = 0;
std::vector<JsepTrack::JsConstraints> constraints;
track->GetJsConstraints(&constraints);
for (auto constraint : constraints) {
if (constraint.rid != "") {
minimumSsrcCount++;
}
}
// We need at least 1 SSRC
minimumSsrcCount = std::max<size_t>(1, minimumSsrcCount);
size_t currSsrcCount = track->GetSsrcs().size();
if (currSsrcCount < minimumSsrcCount ) {
MOZ_MTLOG(ML_DEBUG,
"Adding " << (minimumSsrcCount - currSsrcCount) << " SSRCs.");
}
while (track->GetSsrcs().size() < minimumSsrcCount) {
uint32_t ssrc=0;
nsresult rv = CreateSsrc(&ssrc);
NS_ENSURE_SUCCESS(rv, rv);
track->AddSsrc(ssrc);
// Don't add duplicate ssrcs
std::vector<uint32_t> ssrcs = track->GetSsrcs();
if (std::find(ssrcs.begin(), ssrcs.end(), ssrc) == ssrcs.end()) {
track->AddSsrc(ssrc);
}
}
}
@ -287,19 +308,62 @@ JsepSessionImpl::SetParameters(const std::string& streamId,
// Add RtpStreamId Extmap
// SdpDirectionAttribute::Direction is a bitmask
SdpDirectionAttribute::Direction addVideoExt = SdpDirectionAttribute::kInactive;
SdpDirectionAttribute::Direction addAudioExt = SdpDirectionAttribute::kInactive;
for (auto constraintEntry: constraints) {
if (constraintEntry.rid != "") {
if (it->mTrack->GetMediaType() == SdpMediaSection::kVideo) {
addVideoExt = static_cast<SdpDirectionAttribute::Direction>(addVideoExt
| it->mTrack->GetDirection());
switch (it->mTrack->GetMediaType()) {
case SdpMediaSection::kVideo: {
addVideoExt = static_cast<SdpDirectionAttribute::Direction>(addVideoExt
| it->mTrack->GetDirection());
break;
}
case SdpMediaSection::kAudio: {
addAudioExt = static_cast<SdpDirectionAttribute::Direction>(addAudioExt
| it->mTrack->GetDirection());
break;
}
}
}
}
if (addVideoExt != SdpDirectionAttribute::kInactive) {
AddVideoRtpExtension("urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id", addVideoExt);
}
if (addAudioExt != SdpDirectionAttribute::kInactive) {
AddAudioRtpExtension("urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id", addAudioExt);
}
it->mTrack->SetJsConstraints(constraints);
auto track = it->mTrack;
if (track->GetDirection() == sdp::kSend) {
// Establish minimum number of required SSRCs
// Note that AddTrack is only for send direction
size_t minimumSsrcCount = 0;
std::vector<JsepTrack::JsConstraints> constraints;
track->GetJsConstraints(&constraints);
for (auto constraint : constraints) {
if (constraint.rid != "") {
minimumSsrcCount++;
}
}
// We need at least 1 SSRC
minimumSsrcCount = std::max<size_t>(1, minimumSsrcCount);
size_t currSsrcCount = track->GetSsrcs().size();
if (currSsrcCount < minimumSsrcCount ) {
MOZ_MTLOG(ML_DEBUG,
"Adding " << (minimumSsrcCount - currSsrcCount) << " SSRCs.");
}
while (track->GetSsrcs().size() < minimumSsrcCount) {
uint32_t ssrc=0;
nsresult rv = CreateSsrc(&ssrc);
NS_ENSURE_SUCCESS(rv, rv);
// Don't add duplicate ssrcs
std::vector<uint32_t> ssrcs = track->GetSsrcs();
if (std::find(ssrcs.begin(), ssrcs.end(), ssrc) == ssrcs.end()) {
track->AddSsrc(ssrc);
}
}
}
return NS_OK;
}
@ -2218,6 +2282,7 @@ JsepSessionImpl::SetupDefaultCodecs()
);
mSupportedCodecs.values.push_back(ulpfec);
mSupportedCodecs.values.push_back(new JsepApplicationCodecDescription(
"5000",
"webrtc-datachannel",

View file

@ -261,6 +261,9 @@ JsepTrack::CreateEncodings(
const std::vector<JsepCodecDescription*>& negotiatedCodecs,
JsepTrackNegotiatedDetails* negotiatedDetails)
{
negotiatedDetails->mTias = remote.GetBandwidth("TIAS");
// TODO add support for b=AS if TIAS is not set (bug 976521)
std::vector<SdpRidAttributeList::Rid> rids;
GetRids(remote, sdp::kRecv, &rids); // Get rids we will send
NegotiateRids(rids, &mJsEncodeConstraints);
@ -294,8 +297,6 @@ JsepTrack::CreateEncodings(
encoding->mConstraints = jsConstraints.constraints;
}
}
encoding->UpdateMaxBitrate(remote);
}
}

View file

@ -5,6 +5,7 @@
#ifndef _JSEPTRACK_H_
#define _JSEPTRACK_H_
#include <functional>
#include <algorithm>
#include <string>
#include <map>
@ -28,6 +29,10 @@ namespace mozilla {
class JsepTrackNegotiatedDetails
{
public:
JsepTrackNegotiatedDetails() :
mTias(0)
{}
size_t
GetEncodingCount() const
{
@ -51,17 +56,32 @@ public:
return nullptr;
}
void
ForEachRTPHeaderExtension(
const std::function<void(const SdpExtmapAttributeList::Extmap& extmap)> & fn) const
{
for(auto entry: mExtmap) {
fn(entry.second);
}
}
std::vector<uint8_t> GetUniquePayloadTypes() const
{
return mUniquePayloadTypes;
}
uint32_t GetTias() const
{
return mTias;
}
private:
friend class JsepTrack;
std::map<std::string, SdpExtmapAttributeList::Extmap> mExtmap;
std::vector<uint8_t> mUniquePayloadTypes;
PtrVector<JsepTrackEncoding> mEncodings;
uint32_t mTias; // bits per second
};
class JsepTrack

View file

@ -38,16 +38,6 @@ public:
return false;
}
void UpdateMaxBitrate(const SdpMediaSection& remote)
{
uint32_t tias = remote.GetBandwidth("TIAS");
// select minimum of the two which is not zero
mConstraints.maxBr = std::min(tias ? tias : mConstraints.maxBr,
mConstraints.maxBr ? mConstraints.maxBr :
tias);
// TODO add support for b=AS if TIAS is not set (bug 976521)
}
EncodingConstraints mConstraints;
std::string mRid;

View file

@ -25,11 +25,11 @@
#include "webrtc/common.h"
#include "webrtc/modules/audio_processing/include/audio_processing.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/voice_engine/include/voe_dtmf.h"
#include "webrtc/voice_engine/include/voe_errors.h"
#include "webrtc/voice_engine/voice_engine_impl.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace mozilla {
@ -89,7 +89,9 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoEBase->StopSend(mChannel);
mPtrVoEBase->StopReceive(mChannel);
mPtrVoEBase->DeleteChannel(mChannel);
mPtrVoEBase->Terminate();
// We don't Terminate() the VoEBase here, because the Call (owned by
// PeerConnectionMedia) actually owns the (shared) VoEBase/VoiceEngine
// here
}
// We shouldn't delete the VoiceEngine until all these are released!
@ -103,21 +105,24 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoERTP_RTCP = nullptr;
mPtrRTP = nullptr;
if(mVoiceEngine)
if (mVoiceEngine)
{
webrtc::VoiceEngine::Delete(mVoiceEngine);
}
}
bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc)
bool WebrtcAudioConduit::SetLocalSSRCs(const std::vector<unsigned int> & aSSRCs)
{
unsigned int oldSsrc;
if (!GetLocalSSRC(&oldSsrc)) {
// This should hold true until the WebRTC.org VoE refactor
MOZ_ASSERT(aSSRCs.size() == 1,"WebrtcAudioConduit::SetLocalSSRCs accepts exactly 1 ssrc.");
std::vector<unsigned int> oldSsrcs = GetLocalSSRCs();
if (oldSsrcs.empty()) {
MOZ_ASSERT(false, "GetLocalSSRC failed");
return false;
}
if (oldSsrc == ssrc) {
if (oldSsrcs == aSSRCs) {
return true;
}
@ -126,7 +131,7 @@ bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc)
return false;
}
if (mPtrRTP->SetLocalSSRC(mChannel, ssrc)) {
if (mPtrRTP->SetLocalSSRC(mChannel, aSSRCs[0])) {
return false;
}
@ -138,8 +143,12 @@ bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc)
return true;
}
bool WebrtcAudioConduit::GetLocalSSRC(unsigned int* ssrc) {
return !mPtrRTP->GetLocalSSRC(mChannel, *ssrc);
std::vector<unsigned int> WebrtcAudioConduit::GetLocalSSRCs() const {
unsigned int ssrc;
if (!mPtrRTP->GetLocalSSRC(mChannel, ssrc)) {
return std::vector<unsigned int>(1,ssrc);
}
return std::vector<unsigned int>();
}
bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
@ -270,6 +279,13 @@ MediaConduitErrorCode WebrtcAudioConduit::Init()
return kMediaConduitSessionNotInited;
}
// init the engine with our audio device layer
if(mPtrVoEBase->Init() == -1)
{
CSFLogError(logTag, "%s VoiceEngine Base Not Initialized", __FUNCTION__);
return kMediaConduitSessionNotInited;
}
if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
{
CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__);
@ -310,13 +326,6 @@ MediaConduitErrorCode WebrtcAudioConduit::Init()
return kMediaConduitSessionNotInited;
}
// init the engine with our audio device layer
if(mPtrVoEBase->Init() == -1)
{
CSFLogError(logTag, "%s VoiceEngine Base Not Initialized", __FUNCTION__);
return kMediaConduitSessionNotInited;
}
if( (mChannel = mPtrVoEBase->CreateChannel()) == -1)
{
CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__);
@ -857,7 +866,6 @@ WebrtcAudioConduit::StartReceiving()
return kMediaConduitUnknownError;
}
if(mPtrVoEBase->StartPlayout(mChannel) == -1)
{
CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
@ -871,9 +879,12 @@ WebrtcAudioConduit::StartReceiving()
//WebRTC::RTP Callback Implementation
// Called on AudioGUM or MSG thread
int WebrtcAudioConduit::SendPacket(int channel, const void* data, size_t len)
bool
WebrtcAudioConduit::SendRtp(const uint8_t* data,
size_t len,
const webrtc::PacketOptions& options)
{
CSFLogDebug(logTag, "%s : channel %d", __FUNCTION__, channel);
CSFLogDebug(logTag, "%s: len %lu", __FUNCTION__, (unsigned long)len);
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
@ -888,25 +899,30 @@ int WebrtcAudioConduit::SendPacket(int channel, const void* data, size_t len)
}
#endif
ReentrantMonitorAutoEnter enter(mTransportMonitor);
// XXX(pkerr) - the PacketOptions are being ignored. This parameter was added along
// with the Call API update in the webrtc.org codebase.
// The only field in it is the packet_id, which is used when the header
// extension for TransportSequenceNumber is being used, which we don't.
(void) options;
if(mTransmitterTransport &&
(mTransmitterTransport->SendRtpPacket(data, len) == NS_OK))
{
CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__);
return len;
return true;
} else {
CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__);
return -1;
return false;
}
}
// Called on WebRTC Process thread and perhaps others
int WebrtcAudioConduit::SendRTCPPacket(int channel, const void* data, size_t len)
bool
WebrtcAudioConduit::SendRtcp(const uint8_t* data, size_t len)
{
CSFLogDebug(logTag, "%s : channel %d , len %lu, first rtcp = %u ",
CSFLogDebug(logTag, "%s : len %lu, first rtcp = %u ",
__FUNCTION__,
channel,
(unsigned long) len,
static_cast<unsigned>(((uint8_t *) data)[1]));
static_cast<unsigned>(data[1]));
// We come here if we have only one pipeline/conduit setup,
// such as for unidirectional streams.
@ -917,14 +933,14 @@ int WebrtcAudioConduit::SendRTCPPacket(int channel, const void* data, size_t len
{
// Might be a sender report, might be a receiver report, we don't know.
CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__);
return len;
return true;
} else if(mTransmitterTransport &&
(mTransmitterTransport->SendRtcpPacket(data, len) == NS_OK)) {
CSFLogDebug(logTag, "%s Sent RTCP Packet (sender report) ", __FUNCTION__);
return len;
return true;
} else {
CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__);
return -1;
return false;
}
}

View file

@ -15,6 +15,7 @@
// Audio Engine Includes
#include "webrtc/common_types.h"
#include "webrtc/transport.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
#include "webrtc/voice_engine/include/voe_codec.h"
@ -45,8 +46,8 @@ NTPtoDOMHighResTimeStamp(uint32_t ntpHigh, uint32_t ntpLow);
* Concrete class for Audio session. Hooks up
* - media-source and target to external transport
*/
class WebrtcAudioConduit:public AudioSessionConduit
,public webrtc::Transport
class WebrtcAudioConduit: public AudioSessionConduit
, public webrtc::Transport
{
public:
//VoiceEngine defined constant for Payload Name Size.
@ -150,20 +151,22 @@ public:
* Webrtc transport implementation to send and receive RTP packet.
* AudioConduit registers itself as ExternalTransport to the VoiceEngine
*/
virtual int SendPacket(int channel, const void *data, size_t len) override;
virtual bool SendRtp(const uint8_t* data,
size_t len,
const webrtc::PacketOptions& options) override;
/**
* Webrtc transport implementation to send and receive RTCP packet.
* AudioConduit registers itself as ExternalTransport to the VoiceEngine
*/
virtual int SendRTCPPacket(int channel, const void *data, size_t len) override;
virtual bool SendRtcp(const uint8_t *data,
size_t len) override;
virtual uint64_t CodecPluginID() override { return 0; }
virtual void DeleteStreams() override {}
WebrtcAudioConduit():
explicit WebrtcAudioConduit():
mVoiceEngine(nullptr),
mTransportMonitor("WebrtcAudioConduit"),
mTransmitterTransport(nullptr),
@ -188,8 +191,17 @@ public:
int GetChannel() { return mChannel; }
webrtc::VoiceEngine* GetVoiceEngine() { return mVoiceEngine; }
bool SetLocalSSRC(unsigned int ssrc) override;
bool GetLocalSSRC(unsigned int* ssrc) override;
/* Set Local SSRC list.
* Note: Until the refactor of the VoE into the call API is complete
* this list should contain only a single ssrc.
*/
bool SetLocalSSRCs(const std::vector<unsigned int>& aSSRCs) override;
std::vector<unsigned int> GetLocalSSRCs() const override;
bool SetRemoteSSRC(unsigned int ssrc) override
{
return false;
}
bool GetRemoteSSRC(unsigned int* ssrc) override;
bool SetLocalCNAME(const char* cname) override;
bool GetVideoEncoderStats(double* framerateMean,

View file

@ -90,10 +90,15 @@ public:
bool mRembFbSet;
bool mFECFbSet;
uint32_t mTias;
EncodingConstraints mEncodingConstraints;
struct SimulcastEncoding {
std::string rid;
EncodingConstraints constraints;
bool operator==(const SimulcastEncoding& aOther) const {
return rid == aOther.rid &&
constraints == aOther.constraints;
}
};
std::vector<SimulcastEncoding> mSimulcastEncodings;
std::string mSpropParameterSets;
@ -103,6 +108,28 @@ public:
uint8_t mPacketizationMode;
// TODO: add external negotiated SPS/PPS
bool operator==(const VideoCodecConfig& aRhs) const {
if (mType != aRhs.mType ||
mName != aRhs.mName ||
mAckFbTypes != aRhs.mAckFbTypes ||
mNackFbTypes != aRhs.mNackFbTypes ||
mCcmFbTypes != aRhs.mCcmFbTypes ||
mRembFbSet != aRhs.mRembFbSet ||
mFECFbSet != aRhs.mFECFbSet ||
mTias != aRhs.mTias ||
!(mEncodingConstraints == aRhs.mEncodingConstraints) ||
!(mSimulcastEncodings == aRhs.mSimulcastEncodings) ||
mSpropParameterSets != aRhs.mSpropParameterSets ||
mProfile != aRhs.mProfile ||
mConstraints != aRhs.mConstraints ||
mLevel != aRhs.mLevel ||
mPacketizationMode != aRhs.mPacketizationMode) {
return false;
}
return true;
}
VideoCodecConfig(int type,
std::string name,
const EncodingConstraints& constraints,
@ -110,6 +137,7 @@ public:
mType(type),
mName(name),
mFECFbSet(false),
mTias(0),
mEncodingConstraints(constraints),
mProfile(0x42),
mConstraints(0xE0),
@ -125,6 +153,20 @@ public:
}
}
bool ResolutionEquals(const VideoCodecConfig& aConfig) const
{
if (mSimulcastEncodings.size() != aConfig.mSimulcastEncodings.size()) {
return false;
}
for (size_t i = 0; i < mSimulcastEncodings.size(); ++i) {
if (!mSimulcastEncodings[i].constraints.ResolutionEquals(
aConfig.mSimulcastEncodings[i].constraints)) {
return false;
}
}
return true;
}
// Nothing seems to use this right now. Do we intend to support this
// someday?
bool RtcpFbAckIsSet(const std::string& type) const

View file

@ -7,12 +7,12 @@
namespace mozilla {
VideoEncoder* GmpVideoCodec::CreateEncoder() {
return static_cast<VideoEncoder*>(new WebrtcVideoEncoderProxy());
WebrtcVideoEncoder* GmpVideoCodec::CreateEncoder() {
return new WebrtcVideoEncoderProxy();
}
VideoDecoder* GmpVideoCodec::CreateDecoder() {
return static_cast<VideoDecoder*>(new WebrtcVideoDecoderProxy());
WebrtcVideoDecoder* GmpVideoCodec::CreateDecoder() {
return new WebrtcVideoDecoderProxy();
}
}

View file

@ -10,8 +10,8 @@
namespace mozilla {
class GmpVideoCodec {
public:
static VideoEncoder* CreateEncoder();
static VideoDecoder* CreateDecoder();
static WebrtcVideoEncoder* CreateEncoder();
static WebrtcVideoDecoder* CreateDecoder();
};
}

View file

@ -12,7 +12,7 @@ namespace mozilla {
static const char* logTag ="MediaCodecVideoCodec";
VideoEncoder* MediaCodecVideoCodec::CreateEncoder(CodecType aCodecType) {
WebrtcVideoEncoder* MediaCodecVideoCodec::CreateEncoder(CodecType aCodecType) {
CSFLogDebug(logTag, "%s ", __FUNCTION__);
if (aCodecType == CODEC_VP8) {
return new WebrtcMediaCodecVP8VideoEncoder();
@ -20,7 +20,7 @@ VideoEncoder* MediaCodecVideoCodec::CreateEncoder(CodecType aCodecType) {
return nullptr;
}
VideoDecoder* MediaCodecVideoCodec::CreateDecoder(CodecType aCodecType) {
WebrtcVideoDecoder* MediaCodecVideoCodec::CreateDecoder(CodecType aCodecType) {
CSFLogDebug(logTag, "%s ", __FUNCTION__);
if (aCodecType == CODEC_VP8) {
return new WebrtcMediaCodecVP8VideoDecoder();

View file

@ -17,13 +17,13 @@ class MediaCodecVideoCodec {
* Create encoder object for codec type |aCodecType|. Return |nullptr| when
* failed.
*/
static VideoEncoder* CreateEncoder(CodecType aCodecType);
static WebrtcVideoEncoder* CreateEncoder(CodecType aCodecType);
/**
* Create decoder object for codec type |aCodecType|. Return |nullptr| when
* failed.
*/
static VideoDecoder* CreateDecoder(CodecType aCodecType);
static WebrtcVideoDecoder* CreateDecoder(CodecType aCodecType);
};
}

View file

@ -39,10 +39,10 @@ kMediaConduitKeyFrameRequestError, // Can't set KeyFrameRequest mode
kMediaConduitNACKStatusError, // Can't set NACK mode
kMediaConduitTMMBRStatusError, // Can't set TMMBR mode
kMediaConduitFECStatusError, // Can't set FEC mode
kMediaConduitHybridNACKFECStatusError // Can't set Hybrid NACK / FEC mode
kMediaConduitHybridNACKFECStatusError, // Can't set Hybrid NACK / FEC mode
kMediaConduitVideoSendStreamError // WebRTC video send stream failure
};
}
#endif

View file

@ -9,20 +9,64 @@
#include "nsXPCOM.h"
#include "nsDOMNavigationTiming.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RefCounted.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/utils.h"
#include "CodecConfig.h"
#include "VideoTypes.h"
#include "MediaConduitErrors.h"
#include "ImageContainer.h"
#include "webrtc/call.h"
#include "webrtc/config.h"
#include "webrtc/common_types.h"
namespace webrtc {
class I420VideoFrame;
}
#include <vector>
namespace webrtc {
class VideoFrame;
}
namespace mozilla {
// Wrap the webrtc.org Call class adding mozilla add/ref support.
class WebRtcCallWrapper : public RefCounted<WebRtcCallWrapper>
{
public:
typedef webrtc::Call::Config Config;
static RefPtr<WebRtcCallWrapper> Create(const Config& config)
{
return new WebRtcCallWrapper(webrtc::Call::Create(config));
}
webrtc::Call* Call() const
{
return mCall.get();
}
virtual ~WebRtcCallWrapper()
{
if (mCall->voice_engine()) {
webrtc::VoiceEngine* voice_engine = mCall->voice_engine();
mCall.reset(nullptr); // Force it to release the voice engine reference
// Delete() must be after all refs are released
webrtc::VoiceEngine::Delete(voice_engine);
}
}
MOZ_DECLARE_REFCOUNTED_TYPENAME(WebRtcCallWrapper)
private:
WebRtcCallWrapper() = delete;
explicit WebRtcCallWrapper(webrtc::Call* aCall)
: mCall(aCall) {}
DISALLOW_COPY_AND_ASSIGN(WebRtcCallWrapper);
UniquePtr<webrtc::Call> mCall;
};
/**
* Abstract Interface for transporting RTP packets - audio/vidoeo
* The consumers of this interface are responsible for passing in
@ -40,7 +84,7 @@ public:
* @param len : Length of the media packet
* @result : NS_OK on success, NS_ERROR_FAILURE otherwise
*/
virtual nsresult SendRtpPacket(const void* data, int len) = 0;
virtual nsresult SendRtpPacket(const uint8_t* data, size_t len) = 0;
/**
* RTCP Transport Function to be implemented by concrete transport implementation
@ -48,7 +92,7 @@ public:
* @param len : Length of the RTCP packet
* @result : NS_OK on success, NS_ERROR_FAILURE otherwise
*/
virtual nsresult SendRtcpPacket(const void* data, int len) = 0;
virtual nsresult SendRtcpPacket(const uint8_t* data, size_t len) = 0;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TransportInterface)
};
@ -193,9 +237,15 @@ public:
*/
virtual MediaConduitErrorCode SetReceiverTransport(RefPtr<TransportInterface> aTransport) = 0;
virtual bool SetLocalSSRC(unsigned int ssrc) = 0;
virtual bool GetLocalSSRC(unsigned int* ssrc) = 0;
/* Sets the local SSRCs
* @return true iff the local ssrcs == aSSRCs upon return
* Note: this is an ordered list and {a,b,c} != {b,a,c}
*/
virtual bool SetLocalSSRCs(const std::vector<unsigned int>& aSSRCs) = 0;
virtual std::vector<unsigned int> GetLocalSSRCs() const = 0;
virtual bool GetRemoteSSRC(unsigned int* ssrc) = 0;
virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
virtual bool SetLocalCNAME(const char* cname) = 0;
/**
@ -265,10 +315,12 @@ class VideoSessionConduit : public MediaSessionConduit
public:
/**
* Factory function to create and initialize a Video Conduit Session
* return: Concrete VideoSessionConduitObject or nullptr in the case
* @param webrtc::Call instance shared by paired audio and video
* media conduits
* @result Concrete VideoSessionConduitObject or nullptr in the case
* of failure
*/
static RefPtr<VideoSessionConduit> Create();
static RefPtr<VideoSessionConduit> Create(RefPtr<WebRtcCallWrapper> aCall);
enum FrameRequestType
{
@ -287,15 +339,28 @@ public:
virtual Type type() const { return VIDEO; }
/**
* Adds negotiated RTP extensions
*/
virtual void AddLocalRTPExtensions(const std::vector<webrtc::RtpExtension>& extensions) = 0;
/**
* Returns the negotiated RTP extensions
*/
virtual std::vector<webrtc::RtpExtension> GetLocalRTPExtensions() const = 0;
/**
* Function to attach Renderer end-point of the Media-Video conduit.
* @param aRenderer : Reference to the concrete Video renderer implementation
* Note: Multiple invocations of this API shall remove an existing renderer
* and attaches the new to the Conduit.
*/
virtual MediaConduitErrorCode AttachRenderer(RefPtr<VideoRenderer> aRenderer) = 0;
virtual MediaConduitErrorCode AttachRenderer(RefPtr<mozilla::VideoRenderer> aRenderer) = 0;
virtual void DetachRenderer() = 0;
virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
/**
* Function to deliver a capture video frame for encoding and transport
* @param video_frame: pointer to captured video-frame.
@ -313,7 +378,7 @@ public:
unsigned short height,
VideoType video_type,
uint64_t capture_time) = 0;
virtual MediaConduitErrorCode SendVideoFrame(webrtc::I420VideoFrame& frame) = 0;
virtual MediaConduitErrorCode SendVideoFrame(webrtc::VideoFrame& frame) = 0;
virtual MediaConduitErrorCode ConfigureCodecMode(webrtc::VideoCodecMode) = 0;
/**
@ -335,31 +400,7 @@ public:
*
*/
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0;
/**
* Set an external encoder
* @param encoder
* @result: on success, we will use the specified encoder
*/
virtual MediaConduitErrorCode SetExternalSendCodec(VideoCodecConfig* config,
VideoEncoder* encoder) = 0;
/**
* Set an external decoder
* @param decoder
* @result: on success, we will use the specified decoder
*/
virtual MediaConduitErrorCode SetExternalRecvCodec(VideoCodecConfig* config,
VideoDecoder* decoder) = 0;
/**
* Function to enable the RTP Stream ID (RID) extension
* @param enabled: enable extension
* @param id: id to be used for this rtp header extension
* NOTE: See VideoConduit for more information
*/
virtual MediaConduitErrorCode EnableRTPStreamIdExtension(bool enabled, uint8_t id) = 0;
const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0;
/**
* These methods allow unit tests to double-check that the
@ -410,11 +451,13 @@ class AudioSessionConduit : public MediaSessionConduit
{
public:
/**
* Factory function to create and initialize an Audio Conduit Session
* return: Concrete AudioSessionConduitObject or nullptr in the case
* of failure
*/
/**
* Factory function to create and initialize an Audio Conduit Session
* @param webrtc::Call instance shared by paired audio and video
* media conduits
* @result Concrete AudioSessionConduitObject or nullptr in the case
* of failure
*/
static RefPtr<AudioSessionConduit> Create();
virtual ~AudioSessionConduit() {}

View file

@ -10,7 +10,7 @@
namespace mozilla {
VideoEncoder*
WebrtcVideoEncoder*
OMXVideoCodec::CreateEncoder(CodecType aCodecType)
{
if (aCodecType == CODEC_H264) {
@ -19,7 +19,7 @@ OMXVideoCodec::CreateEncoder(CodecType aCodecType)
return nullptr;
}
VideoDecoder*
WebrtcVideoDecoder*
OMXVideoCodec::CreateDecoder(CodecType aCodecType) {
if (aCodecType == CODEC_H264) {
return new WebrtcOMXH264VideoDecoder();

View file

@ -18,13 +18,13 @@ class OMXVideoCodec {
* Create encoder object for codec type |aCodecType|. Return |nullptr| when
* failed.
*/
static VideoEncoder* CreateEncoder(CodecType aCodecType);
static WebrtcVideoEncoder* CreateEncoder(CodecType aCodecType);
/**
* Create decoder object for codec type |aCodecType|. Return |nullptr| when
* failed.
*/
static VideoDecoder* CreateDecoder(CodecType aCodecType);
static WebrtcVideoDecoder* CreateDecoder(CodecType aCodecType);
};
}

File diff suppressed because it is too large Load diff

View file

@ -5,59 +5,54 @@
#ifndef VIDEO_SESSION_H_
#define VIDEO_SESSION_H_
#include "nsAutoPtr.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/SharedThreadPool.h"
#include "nsAutoPtr.h"
#include "nsITimer.h"
#include "LoadManager.h"
#include "LoadManagerFactory.h"
#include "MediaConduitInterface.h"
#include "MediaEngineWrapper.h"
#include "CodecStatistics.h"
#include "LoadManagerFactory.h"
#include "LoadManager.h"
#include "RunningStat.h"
#include "runnable_utils.h"
// conflicts with #include of scoped_ptr.h
#undef FF
// Video Engine Includes
#include "webrtc/call.h"
#include "webrtc/common_types.h"
#ifdef FF
#undef FF // Avoid name collision between scoped_ptr.h and nsCRTGlue.h.
#endif
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_external_codec.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_engine/include/vie_network.h"
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
#include "webrtc/video_decoder.h"
#include "webrtc/video_encoder.h"
#include <functional>
#include <memory>
/** This file hosts several structures identifying different aspects
* of a RTP Session.
*/
using webrtc::ViEBase;
using webrtc::ViENetwork;
using webrtc::ViECodec;
using webrtc::ViECapture;
using webrtc::ViERender;
using webrtc::ViEExternalCapture;
using webrtc::ViEExternalCodec;
namespace mozilla {
const int kVideoMtu = 1200;
const int kQpMax = 56;
class WebrtcAudioConduit;
class nsThread;
// Interface of external video encoder for WebRTC.
class WebrtcVideoEncoder:public VideoEncoder
,public webrtc::VideoEncoder
{};
class WebrtcVideoEncoder : public VideoEncoder
, public webrtc::VideoEncoder
{
};
// Interface of external video decoder for WebRTC.
class WebrtcVideoDecoder:public VideoDecoder
,public webrtc::VideoDecoder
{};
class WebrtcVideoDecoder : public VideoDecoder
, public webrtc::VideoDecoder
{
};
/**
* Concrete class for Video session. Hooks up
@ -65,12 +60,30 @@ class WebrtcVideoDecoder:public VideoDecoder
*/
class WebrtcVideoConduit : public VideoSessionConduit
, public webrtc::Transport
, public webrtc::ExternalRenderer
, public webrtc::VideoRenderer
{
public:
/* Default minimum bitrate for video streams. */
static const uint32_t kDefaultMinBitrate_bps;
/* Default start a.k.a. target bitrate for video streams. */
static const uint32_t kDefaultStartBitrate_bps;
/* Default maximum bitrate for video streams. */
static const uint32_t kDefaultMaxBitrate_bps;
//VoiceEngine defined constant for Payload Name Size.
static const unsigned int CODEC_PLNAME_SIZE;
/**
* Add rtp extensions to the the VideoSendStream
* Note: upon a name collision the old extension is removed and the new one
* takes its place.
* TODO(@@NG) promote this the MediaConduitInterface when the VoE rework
* hits Webrtc.org.
*/
void AddLocalRTPExtensions(const std::vector<webrtc::RtpExtension>& extensions) override;
std::vector<webrtc::RtpExtension> GetLocalRTPExtensions() const override;
/**
* Set up A/V sync between this (incoming) VideoConduit and an audio conduit.
*/
@ -78,24 +91,24 @@ public:
/**
* Function to attach Renderer end-point for the Media-Video conduit.
* @param aRenderer : Reference to the concrete Video renderer implementation
* @param aRenderer : Reference to the concrete mozilla Video renderer implementation
* Note: Multiple invocations of this API shall remove an existing renderer
* and attaches the new to the Conduit.
*/
virtual MediaConduitErrorCode AttachRenderer(RefPtr<VideoRenderer> aVideoRenderer) override;
virtual MediaConduitErrorCode AttachRenderer(RefPtr<mozilla::VideoRenderer> aVideoRenderer) override;
virtual void DetachRenderer() override;
/**
* APIs used by the registered external transport to this Conduit to
* feed in received RTP Frames to the VideoEngine for decoding
*/
virtual MediaConduitErrorCode ReceivedRTPPacket(const void *data, int len) override;
virtual MediaConduitErrorCode ReceivedRTPPacket(const void* data, int len) override;
/**
* APIs used by the registered external transport to this Conduit to
* feed in received RTP Frames to the VideoEngine for decoding
*/
virtual MediaConduitErrorCode ReceivedRTCPPacket(const void *data, int len) override;
virtual MediaConduitErrorCode ReceivedRTCPPacket(const void* data, int len) override;
virtual MediaConduitErrorCode StopTransmitting() override;
virtual MediaConduitErrorCode StartTransmitting() override;
@ -127,7 +140,7 @@ public:
* transmission sub-system on the engine.
*/
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
const std::vector<VideoCodecConfig* >& codecConfigList) override;
const std::vector<VideoCodecConfig* >& codecConfigList) override;
/**
* Register Transport for this Conduit. RTP and RTCP frames from the VideoEngine
@ -142,15 +155,13 @@ public:
* @param width, height: dimensions of the frame
* @param cap: user-enforced max bitrate, or 0
* @param aLastFramerateTenths: holds the current input framerate
* @param out_start, out_min, out_max: bitrate results
* @param aVideoStream stream to apply bitrates to
*/
void SelectBitrates(unsigned short width,
unsigned short height,
unsigned int cap,
mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths,
unsigned int& out_min,
unsigned int& out_start,
unsigned int& out_max);
int cap,
int32_t aLastFramerateTenths,
webrtc::VideoStream& aVideoStream);
/**
* Function to select and change the encoding resolution based on incoming frame size
@ -160,7 +171,7 @@ public:
*/
bool SelectSendResolution(unsigned short width,
unsigned short height,
webrtc::I420VideoFrame *frame);
webrtc::VideoFrame* frame);
/**
* Function to reconfigure the current send codec for a different
@ -170,7 +181,7 @@ public:
*/
nsresult ReconfigureSendCodec(unsigned short width,
unsigned short height,
webrtc::I420VideoFrame *frame);
webrtc::VideoFrame* frame);
/**
* Function to select and change the encoding frame rate based on incoming frame rate
@ -178,7 +189,10 @@ public:
* @param current framerate
* @result new framerate
*/
unsigned int SelectSendFrameRate(unsigned int framerate) const;
unsigned int SelectSendFrameRate(const VideoCodecConfig* codecConfig,
unsigned int old_framerate,
unsigned short sending_width,
unsigned short sending_height) const;
/**
* Function to deliver a capture video frame for encoding and transport
@ -192,66 +206,44 @@ public:
* This ensures the inserted video-frames can be transmitted by the conduit
*/
virtual MediaConduitErrorCode SendVideoFrame(unsigned char* video_frame,
unsigned int video_frame_length,
unsigned short width,
unsigned short height,
VideoType video_type,
uint64_t capture_time) override;
virtual MediaConduitErrorCode SendVideoFrame(webrtc::I420VideoFrame& frame) override;
unsigned int video_frame_length,
unsigned short width,
unsigned short height,
VideoType video_type,
uint64_t capture_time) override;
virtual MediaConduitErrorCode SendVideoFrame(webrtc::VideoFrame& frame) override;
/**
* Set an external encoder object |encoder| to the payload type |pltype|
* for sender side codec.
*/
virtual MediaConduitErrorCode SetExternalSendCodec(VideoCodecConfig* config,
VideoEncoder* encoder) override;
/**
* Set an external decoder object |decoder| to the payload type |pltype|
* for receiver side codec.
*/
virtual MediaConduitErrorCode SetExternalRecvCodec(VideoCodecConfig* config,
VideoDecoder* decoder) override;
/**
* Enables use of Rtp Stream Id, and sets the extension ID.
*/
virtual MediaConduitErrorCode EnableRTPStreamIdExtension(bool enabled, uint8_t id) override;
/**
/**
* webrtc::Transport method implementation
* ---------------------------------------
* Webrtc transport implementation to send and receive RTP packet.
* VideoConduit registers itself as ExternalTransport to the VideoEngine
* VideoConduit registers itself as ExternalTransport to the VideoStream
*/
virtual int SendPacket(int channel, const void *data, size_t len) override;
virtual bool SendRtp(const uint8_t* packet, size_t length,
const webrtc::PacketOptions& options) override;
/**
* webrtc::Transport method implementation
* ---------------------------------------
* Webrtc transport implementation to send and receive RTCP packet.
* VideoConduit registers itself as ExternalTransport to the VideoEngine
*/
virtual int SendRTCPPacket(int channel, const void *data, size_t len) override;
virtual bool SendRtcp(const uint8_t* packet, size_t length) override;
/**
* Webrtc External Renderer Implementation APIs.
* Raw I420 Frames are delivred to the VideoConduit by the VideoEngine
* webrtc::VideoRenderer implementation
* ------------------------------------
* webrtc::VideoFrames are delivered to the VideoConduit by the VideoReceiveStream.
*/
virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int) override;
virtual int DeliverFrame(unsigned char*, size_t, uint32_t , int64_t,
int64_t, void *handle) override;
virtual int DeliverFrame(unsigned char*, size_t, uint32_t, uint32_t, uint32_t , int64_t,
int64_t, void *handle);
virtual int DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame) override;
virtual void RenderFrame(const webrtc::VideoFrame& video_frame,
int time_to_render_ms) override;
/**
* Does DeliverFrame() support a null buffer and non-null handle
* (video texture)?
* B2G support it (when using HW video decoder with graphic buffer output).
* XXX Investigate! Especially for Android
* webrtc::VideoRenderer implementation
* ------------------------------------
*/
virtual bool IsTextureSupported() override {
virtual bool IsTextureSupported() const override {
#ifdef WEBRTC_GONK
return true;
#else
@ -259,6 +251,14 @@ public:
#endif
}
/**
* webrtc::VideoRenderer implementation
* ------------------------------------
*/
virtual bool SmoothsRenderedFrames() const override {
return false;
}
virtual uint64_t CodecPluginID() override;
unsigned short SendingWidth() override {
@ -285,17 +285,17 @@ public:
return 0;
}
WebrtcVideoConduit();
explicit WebrtcVideoConduit(RefPtr<WebRtcCallWrapper> aCall);
virtual ~WebrtcVideoConduit();
MediaConduitErrorCode InitMain();
virtual MediaConduitErrorCode Init();
int GetChannel() { return mChannel; }
webrtc::VideoEngine* GetVideoEngine() { return mVideoEngine; }
bool GetLocalSSRC(unsigned int* ssrc) override;
bool SetLocalSSRC(unsigned int ssrc) override;
std::vector<unsigned int> GetLocalSSRCs() const override;
bool SetLocalSSRCs(const std::vector<unsigned int> & ssrcs) override;
bool GetRemoteSSRC(unsigned int* ssrc) override;
bool SetRemoteSSRC(unsigned int ssrc) override;
bool SetLocalCNAME(const char* cname) override;
bool GetVideoEncoderStats(double* framerateMean,
double* framerateStdDev,
@ -325,25 +325,91 @@ public:
private:
DISALLOW_COPY_AND_ASSIGN(WebrtcVideoConduit);
static inline bool OnThread(nsIEventTarget *thread)
{
bool on;
nsresult rv;
rv = thread->IsOnCurrentThread(&on);
/** Shared statistics for receive and transmit video streams
*/
class StreamStatistics {
public:
void Update(const double aFrameRate, const double aBitrate);
/**
* Returns gathered stream statistics
* @param aOutFrMean: mean framerate
* @param aOutFrStdDev: standard deviation of framerate
* @param aOutBrMean: mean bitrate
* @param aOutBrStdDev: standard deviation of bitrate
*/
bool GetVideoStreamStats(double& aOutFrMean,
double& aOutFrStdDev,
double& aOutBrMean,
double& aOutBrStdDev) const;
private:
RunningStat mFrameRate;
RunningStat mBitrate;
};
// If the target thread has already shut down, we don't want to assert.
if (rv != NS_ERROR_NOT_INITIALIZED) {
MOZ_ASSERT(NS_SUCCEEDED(rv));
/**
* Statistics for sending streams
*/
class SendStreamStatistics : public StreamStatistics {
public:
/**
* Returns the calculate number of dropped frames
* @param aOutDroppedFrames: the number of dropped frames
*/
void DroppedFrames(uint32_t& aOutDroppedFrames) const;
void Update(const webrtc::VideoSendStream::Stats& aStats);
/**
* Call once for every frame delivered for encoding
*/
void SentFrame() {
++mSentFrames;
}
private:
uint32_t mDroppedFrames = 0;
mozilla::Atomic<int32_t> mSentFrames;
};
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
return on;
}
//Local database of currently applied receive codecs
typedef std::vector<VideoCodecConfig* > RecvCodecList;
/** Statistics for receiving streams
*/
class ReceiveStreamStatistics : public StreamStatistics {
public:
/**
* Returns the number of discarded packets
* @param aOutDiscPackets: number of discarded packets
*/
void DiscardedPackets(uint32_t& aOutDiscPackets) const;
void Update(const webrtc::VideoReceiveStream::Stats& aStats);
private:
uint32_t mDiscardedPackets = 0;
};
/*
* Stores encoder configuration information and produces
* a VideoEncoderConfig from it.
*/
class VideoEncoderConfigBuilder {
public:
/**
* Stores extended data for Simulcast Streams
*/
class SimulcastStreamConfig {
public:
int jsMaxBitrate; // user-controlled max bitrate
double jsScaleDownBy=1.0; // user-controlled downscale
};
void SetEncoderSpecificSettings(void* aSettingsObj);
void SetMinTransmitBitrateBps(int aXmitMinBps);
void SetContentType(webrtc::VideoEncoderConfig::ContentType aContentType);
void SetResolutionDivisor(unsigned char aDivisor);
void AddStream(webrtc::VideoStream aStream);
void AddStream(webrtc::VideoStream aStream,const SimulcastStreamConfig& aSimulcastConfig);
size_t StreamCount();
void ClearStreams();
void ForEachStream(
const std::function<void(webrtc::VideoStream&, SimulcastStreamConfig&, const size_t index)> && f);
webrtc::VideoEncoderConfig GenerateConfig();
private:
webrtc::VideoEncoderConfig mConfig;
std::vector<SimulcastStreamConfig> mSimulcastStreams;
};
//Function to convert between WebRTC and Conduit codec structures
void CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
@ -355,36 +421,37 @@ private:
//Utility function to dump recv codec database
void DumpCodecDB() const;
bool CodecsDifferent(const nsTArray<UniquePtr<VideoCodecConfig>>& a,
const nsTArray<UniquePtr<VideoCodecConfig>>& b);
// Video Latency Test averaging filter
void VideoLatencyUpdate(uint64_t new_sample);
// Utility function to determine RED and ULPFEC payload types
bool DetermineREDAndULPFECPayloadTypes(uint8_t &payload_type_red, uint8_t &payload_type_ulpfec);
MediaConduitErrorCode CreateSendStream();
void DeleteSendStream();
MediaConduitErrorCode CreateRecvStream();
void DeleteRecvStream();
webrtc::VideoDecoder* CreateDecoder(webrtc::VideoDecoder::DecoderType aType);
webrtc::VideoEncoder* CreateEncoder(webrtc::VideoEncoder::EncoderType aType,
bool enable_simulcast);
MediaConduitErrorCode DeliverPacket(const void *data, int len);
webrtc::VideoEngine* mVideoEngine;
mozilla::ReentrantMonitor mTransportMonitor;
RefPtr<TransportInterface> mTransmitterTransport;
RefPtr<TransportInterface> mReceiverTransport;
RefPtr<VideoRenderer> mRenderer;
ScopedCustomReleasePtr<webrtc::ViEBase> mPtrViEBase;
ScopedCustomReleasePtr<webrtc::ViECapture> mPtrViECapture;
ScopedCustomReleasePtr<webrtc::ViECodec> mPtrViECodec;
ScopedCustomReleasePtr<webrtc::ViENetwork> mPtrViENetwork;
ScopedCustomReleasePtr<webrtc::ViERender> mPtrViERender;
ScopedCustomReleasePtr<webrtc::ViERTP_RTCP> mPtrRTP;
ScopedCustomReleasePtr<webrtc::ViEExternalCodec> mPtrExtCodec;
webrtc::ViEExternalCapture* mPtrExtCapture;
RefPtr<mozilla::VideoRenderer> mRenderer;
// Engine state we are concerned with.
mozilla::Atomic<bool> mEngineTransmitting; //If true ==> Transmit Sub-system is up and running
mozilla::Atomic<bool> mEngineReceiving; // if true ==> Receive Sus-sysmtem up and running
int mChannel; // Video Channel for this conduit
int mCapId; // Capturer for this conduit
//Local database of currently applied receive codecs
nsTArray<UniquePtr<VideoCodecConfig>> mRecvCodecList;
Mutex mCodecMutex; // protects mCurrSendCodecConfig
Mutex mCodecMutex; // protects mCurrSendCodecConfig, mVideoSend/RecvStreamStats
nsAutoPtr<VideoCodecConfig> mCurSendCodecConfig;
bool mInReconfig;
@ -400,10 +467,11 @@ private:
unsigned short mNumReceivingStreams;
bool mVideoLatencyTestEnable;
uint64_t mVideoLatencyAvg;
uint32_t mMinBitrate;
uint32_t mStartBitrate;
uint32_t mMaxBitrate;
uint32_t mMinBitrateEstimate;
int mMinBitrate;
int mStartBitrate;
int mPrefMaxBitrate;
int mMinBitrateEstimate;
int mNegotiatedMaxBitrate;
bool mRtpStreamIdEnabled;
uint8_t mRtpStreamIdExtId;
@ -414,16 +482,33 @@ private:
RefPtr<WebrtcAudioConduit> mSyncedTo;
nsAutoPtr<VideoCodecConfig> mExternalSendCodec;
nsAutoPtr<VideoCodecConfig> mExternalRecvCodec;
nsAutoPtr<VideoEncoder> mExternalSendCodecHandle;
nsAutoPtr<VideoDecoder> mExternalRecvCodecHandle;
// statistics object for video codec;
nsAutoPtr<VideoCodecStatistics> mVideoCodecStat;
nsAutoPtr<LoadManager> mLoadManager;
webrtc::VideoCodecMode mCodecMode;
// WEBRTC.ORG Call API
RefPtr<WebRtcCallWrapper> mCall;
webrtc::VideoSendStream* mSendStream;
// Must call webrtc::Call::DestroyVideoSendStream to delete
webrtc::VideoSendStream::Config mSendStreamConfig;
VideoEncoderConfigBuilder mEncoderConfig;
webrtc::VideoCodecH264 mEncoderSpecificH264;
webrtc::VideoReceiveStream* mRecvStream;
// Must call webrtc::Call::DestroyVideoReceiveStream to delete
webrtc::VideoReceiveStream::Config mRecvStreamConfig;
// The lifetime of these codecs are maintained by the VideoConduit instance.
// They are passed to the webrtc::VideoSendStream or VideoReceiveStream,
// on construction.
nsAutoPtr<webrtc::VideoEncoder> mEncoder; // only one encoder for now
std::vector<std::unique_ptr<webrtc::VideoDecoder>> mDecoders;
WebrtcVideoEncoder* mSendCodecPlugin;
WebrtcVideoDecoder* mRecvCodecPlugin;
nsCOMPtr<nsITimer> mVideoStatsTimer;
SendStreamStatistics mSendStreamStats;
ReceiveStreamStatistics mRecvStreamStats;
};
} // end namespace

View file

@ -23,8 +23,6 @@
#include "gmp-video-frame-i420.h"
#include "gmp-video-frame-encoded.h"
#include "webrtc/video_engine/include/vie_external_codec.h"
namespace mozilla {
#ifdef LOG
@ -105,28 +103,22 @@ WebrtcGmpVideoEncoder::~WebrtcGmpVideoEncoder()
}
static int
WebrtcFrameTypeToGmpFrameType(webrtc::VideoFrameType aIn,
WebrtcFrameTypeToGmpFrameType(webrtc::FrameType aIn,
GMPVideoFrameType *aOut)
{
MOZ_ASSERT(aOut);
switch(aIn) {
case webrtc::kKeyFrame:
case webrtc::kVideoFrameKey:
*aOut = kGMPKeyFrame;
break;
case webrtc::kDeltaFrame:
case webrtc::kVideoFrameDelta:
*aOut = kGMPDeltaFrame;
break;
case webrtc::kGoldenFrame:
*aOut = kGMPGoldenFrame;
break;
case webrtc::kAltRefFrame:
*aOut = kGMPAltRefFrame;
break;
case webrtc::kSkipFrame:
case webrtc::kEmptyFrame:
*aOut = kGMPSkipFrame;
break;
default:
MOZ_CRASH("Unexpected VideoFrameType");
MOZ_CRASH("Unexpected webrtc::FrameType");
}
return WEBRTC_VIDEO_CODEC_OK;
@ -134,24 +126,18 @@ WebrtcFrameTypeToGmpFrameType(webrtc::VideoFrameType aIn,
static int
GmpFrameTypeToWebrtcFrameType(GMPVideoFrameType aIn,
webrtc::VideoFrameType *aOut)
webrtc::FrameType *aOut)
{
MOZ_ASSERT(aOut);
switch(aIn) {
case kGMPKeyFrame:
*aOut = webrtc::kKeyFrame;
*aOut = webrtc::kVideoFrameKey;
break;
case kGMPDeltaFrame:
*aOut = webrtc::kDeltaFrame;
break;
case kGMPGoldenFrame:
*aOut = webrtc::kGoldenFrame;
break;
case kGMPAltRefFrame:
*aOut = webrtc::kAltRefFrame;
*aOut = webrtc::kVideoFrameDelta;
break;
case kGMPSkipFrame:
*aOut = webrtc::kSkipFrame;
*aOut = webrtc::kEmptyFrame;
break;
default:
MOZ_CRASH("Unexpected GMPVideoFrameType");
@ -327,9 +313,9 @@ WebrtcGmpVideoEncoder::InitEncoderForSize(unsigned short aWidth,
int32_t
WebrtcGmpVideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
WebrtcGmpVideoEncoder::Encode(const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
const std::vector<webrtc::FrameType>* aFrameTypes)
{
MOZ_ASSERT(aInputImage.width() >= 0 && aInputImage.height() >= 0);
// Would be really nice to avoid this sync dispatch, but it would require a
@ -375,9 +361,9 @@ WebrtcGmpVideoEncoder::RegetEncoderForResolutionChange(
}
int32_t
WebrtcGmpVideoEncoder::Encode_g(const webrtc::I420VideoFrame* aInputImage,
WebrtcGmpVideoEncoder::Encode_g(const webrtc::VideoFrame* aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
const std::vector<webrtc::FrameType>* aFrameTypes)
{
if (!mGMP) {
// destroyed via Terminate(), failed to init, or just not initted yet
@ -540,7 +526,7 @@ WebrtcGmpVideoEncoder::Encoded(GMPVideoEncodedFrame* aEncodedFrame,
{
MutexAutoLock lock(mCallbackMutex);
if (mCallback) {
webrtc::VideoFrameType ft;
webrtc::FrameType ft;
GmpFrameTypeToWebrtcFrameType(aEncodedFrame->FrameType(), &ft);
uint32_t timestamp = (aEncodedFrame->TimeStamp() * 90ll + 999)/1000;
@ -941,7 +927,7 @@ WebrtcGmpVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
{
MutexAutoLock lock(mCallbackMutex);
if (mCallback) {
webrtc::I420VideoFrame image;
webrtc::VideoFrame image;
int ret = image.CreateFrame(aDecodedFrame->Buffer(kGMPYPlane),
aDecodedFrame->Buffer(kGMPUPlane),
aDecodedFrame->Buffer(kGMPVPlane),

View file

@ -45,7 +45,7 @@
#include "MediaConduitInterface.h"
#include "AudioConduit.h"
#include "VideoConduit.h"
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
#include "gmp-video-host.h"
#include "GMPVideoDecoderProxy.h"
@ -142,9 +142,9 @@ public:
int32_t aNumberOfCores,
uint32_t aMaxPayloadSize);
virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage,
virtual int32_t Encode(const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
const std::vector<webrtc::FrameType>* aFrameTypes);
virtual int32_t RegisterEncodeCompleteCallback(
webrtc::EncodedImageCallback* aCallback);
@ -220,9 +220,9 @@ private:
uint32_t mMaxPayloadSize;
};
int32_t Encode_g(const webrtc::I420VideoFrame* aInputImage,
int32_t Encode_g(const webrtc::VideoFrame* aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes);
const std::vector<webrtc::FrameType>* aFrameTypes);
void RegetEncoderForResolutionChange(
uint32_t aWidth,
uint32_t aHeight,
@ -316,9 +316,9 @@ class WebrtcVideoEncoderProxy : public WebrtcVideoEncoder
}
int32_t Encode(
const webrtc::I420VideoFrame& aInputImage,
const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes) override
const std::vector<webrtc::FrameType>* aFrameTypes) override
{
return mEncoderImpl->Encode(aInputImage,
aCodecSpecificInfo,

View file

@ -23,6 +23,8 @@
#include "libyuv/convert.h"
#include "libyuv/row.h"
#include "webrtc/modules/video_coding/include/video_error_codes.h"
#include <webrtc/common_video/libyuv/include/webrtc_libyuv.h>
using namespace mozilla;
@ -266,7 +268,7 @@ public:
void GenerateVideoFrame(
size_t width, size_t height, uint32_t timeStamp,
void* decoded,
webrtc::I420VideoFrame* videoFrame, int color_format) {
webrtc::VideoFrame* videoFrame, int color_format) {
CSFLogDebug(logTag, "%s ", __FUNCTION__);
@ -532,7 +534,7 @@ class OutputDrain : public MediaCodecOutputDrain
MediaCodec::GlobalRef mCoder;
webrtc::EncodedImageCallback* mEncoderCallback;
webrtc::DecodedImageCallback* mDecoderCallback;
webrtc::I420VideoFrame mVideoFrame;
webrtc::VideoFrame mVideoFrame;
jobjectArray mInputBuffers;
jobjectArray mOutputBuffers;
@ -546,7 +548,7 @@ class OutputDrain : public MediaCodecOutputDrain
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebrtcAndroidMediaCodec)
};
static bool I420toNV12(uint8_t* dstY, uint16_t* dstUV, const webrtc::I420VideoFrame& inputImage) {
static bool I420toNV12(uint8_t* dstY, uint16_t* dstUV, const webrtc::VideoFrame& inputImage) {
uint8_t* buffer = dstY;
uint8_t* dst_y = buffer;
int dst_stride_y = inputImage.stride(webrtc::kYPlane);
@ -630,9 +632,9 @@ int32_t WebrtcMediaCodecVP8VideoEncoder::InitEncode(
}
int32_t WebrtcMediaCodecVP8VideoEncoder::Encode(
const webrtc::I420VideoFrame& inputImage,
const webrtc::VideoFrame& inputImage,
const webrtc::CodecSpecificInfo* codecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* frame_types) {
const std::vector<webrtc::FrameType>* frame_types) {
CSFLogDebug(logTag, "%s, w = %d, h = %d", __FUNCTION__, inputImage.width(), inputImage.height());
if (!mMediaCodecEncoder) {
@ -765,9 +767,9 @@ int32_t WebrtcMediaCodecVP8VideoEncoder::Encode(
void* directBuffer = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer)) + offset;
if (flags == MediaCodec::BUFFER_FLAG_SYNC_FRAME) {
mEncodedImage._frameType = webrtc::kKeyFrame;
mEncodedImage._frameType = webrtc::kVideoFrameKey;
} else {
mEncodedImage._frameType = webrtc::kDeltaFrame;
mEncodedImage._frameType = webrtc::kVideoFrameDelta;
}
mEncodedImage._completeFrame = true;
@ -910,7 +912,7 @@ int32_t WebrtcMediaCodecVP8VideoDecoder::Decode(
return WEBRTC_VIDEO_CODEC_ERROR;
}
if (inputImage._frameType == webrtc::kKeyFrame) {
if (inputImage._frameType == webrtc::kVideoFrameKey) {
CSFLogDebug(logTag, "%s, inputImage is Golden frame",
__FUNCTION__);
mFrameWidth = inputImage._encodedWidth;

View file

@ -5,6 +5,8 @@
#ifndef WebrtcMediaCodecVP8VideoCodec_h__
#define WebrtcMediaCodecVP8VideoCodec_h__
#include <jni.h>
#include "mozilla/Mutex.h"
#include "nsThreadUtils.h"
#include "nsAutoPtr.h"
@ -13,6 +15,8 @@
#include "AudioConduit.h"
#include "VideoConduit.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
namespace mozilla {
struct EncodedFrame {
@ -37,9 +41,9 @@ public:
int32_t numberOfCores,
size_t maxPayloadSize) override;
virtual int32_t Encode(const webrtc::I420VideoFrame& inputImage,
virtual int32_t Encode(const webrtc::VideoFrame& inputImage,
const webrtc::CodecSpecificInfo* codecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* frame_types) override;
const std::vector<webrtc::FrameType>* frame_types) override;
virtual int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* callback) override;

View file

@ -532,7 +532,7 @@ public:
CODEC_LOGD("Decoder NewFrame: %dx%d, timestamp %lld, renderTimeMs %lld",
picSize.width, picSize.height, timestamp, renderTimeMs);
nsAutoPtr<webrtc::I420VideoFrame> videoFrame(new webrtc::I420VideoFrame(
nsAutoPtr<webrtc::VideoFrame> videoFrame(new webrtc::VideoFrame(
new ImageNativeHandle(grallocImage.forget()),
picSize.width,
picSize.height,
@ -857,9 +857,9 @@ WebrtcOMXH264VideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
}
int32_t
WebrtcOMXH264VideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
WebrtcOMXH264VideoEncoder::Encode(const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes)
const std::vector<webrtc::FrameType>* aFrameTypes)
{
MOZ_ASSERT(mOMX != nullptr);
if (mOMX == nullptr) {
@ -973,7 +973,7 @@ WebrtcOMXH264VideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
#endif
}
// Wrap I420VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder.
// Wrap VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder.
layers::PlanarYCbCrData yuvData;
yuvData.mYChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kYPlane));
yuvData.mYSize = gfx::IntSize(aInputImage.width(), aInputImage.height());

View file

@ -42,9 +42,9 @@ public:
int32_t aNumOfCores,
size_t aMaxPayloadSize) override;
virtual int32_t Encode(const webrtc::I420VideoFrame& aInputImage,
virtual int32_t Encode(const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes) override;
const std::vector<webrtc::FrameType>* aFrameTypes) override;
virtual int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* aCallback) override;

View file

@ -57,9 +57,7 @@
#include "mozilla/Sprintf.h"
#include "webrtc/common_types.h"
#include "webrtc/common_video/interface/native_handle.h"
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
#include "webrtc/video_engine/include/vie_errors.h"
#include "logging.h"
@ -93,7 +91,7 @@ public:
VideoType aVideoType,
uint64_t aCaptureTime) = 0;
virtual void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) = 0;
virtual void OnVideoFrameConverted(webrtc::VideoFrame& aVideoFrame) = 0;
protected:
virtual ~VideoConverterListener() {}
@ -249,7 +247,7 @@ protected:
}
}
void VideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame)
void VideoFrameConverted(webrtc::VideoFrame& aVideoFrame)
{
MutexAutoLock lock(mMutex);
@ -317,7 +315,7 @@ protected:
if (destFormat != mozilla::kVideoI420) {
unsigned char *video_frame = static_cast<unsigned char*>(basePtr);
webrtc::I420VideoFrame i420_frame;
webrtc::VideoFrame i420_frame;
int stride_y = width;
int stride_uv = (width + 1) / 2;
int target_width = width;
@ -366,7 +364,7 @@ protected:
uint32_t width = yuv->GetSize().width;
uint32_t height = yuv->GetSize().height;
webrtc::I420VideoFrame i420_frame;
webrtc::VideoFrame i420_frame;
int rv = i420_frame.CreateFrame(y, cb, cr, width, height,
yStride, cbCrStride, cbCrStride,
webrtc::kVideoRotation_0);
@ -747,25 +745,24 @@ MediaPipeline::UpdateTransport_s(int level,
void
MediaPipeline::SelectSsrc_m(size_t ssrc_index)
{
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
this,
&MediaPipeline::SelectSsrc_s,
ssrc_index),
NS_DISPATCH_NORMAL);
if (ssrc_index < ssrcs_received_.size()) {
uint32_t ssrc = ssrcs_received_[ssrc_index];
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
this,
&MediaPipeline::SelectSsrc_s,
ssrc),
NS_DISPATCH_NORMAL);
conduit_->SetRemoteSSRC(ssrc);
}
}
void
MediaPipeline::SelectSsrc_s(size_t ssrc_index)
MediaPipeline::SelectSsrc_s(uint32_t ssrc)
{
filter_ = new MediaPipelineFilter;
if (ssrc_index < ssrcs_received_.size()) {
filter_->AddRemoteSSRC(ssrcs_received_[ssrc_index]);
} else {
MOZ_MTLOG(ML_WARNING, "SelectSsrc called with " << ssrc_index << " but we "
<< "have only seen " << ssrcs_received_.size()
<< " ssrcs");
}
filter_->AddRemoteSSRC(ssrc);
}
void MediaPipeline::StateChange(TransportFlow *flow, TransportLayer::State state) {
@ -1274,7 +1271,7 @@ public:
aVideoFrame, aVideoFrameLength, aWidth, aHeight, aVideoType, aCaptureTime);
}
void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame)
void OnVideoFrameConverted(webrtc::VideoFrame& aVideoFrame)
{
MOZ_ASSERT(conduit_->type() == MediaSessionConduit::VIDEO);
static_cast<VideoSessionConduit*>(conduit_.get())->SendVideoFrame(aVideoFrame);
@ -1368,7 +1365,7 @@ public:
aWidth, aHeight, aVideoType, aCaptureTime);
}
void OnVideoFrameConverted(webrtc::I420VideoFrame& aVideoFrame) override
void OnVideoFrameConverted(webrtc::VideoFrame& aVideoFrame) override
{
MutexAutoLock lock(mutex_);
@ -1638,19 +1635,18 @@ MediaPipeline::TransportInfo* MediaPipeline::GetTransportInfo_s(
}
nsresult MediaPipeline::PipelineTransport::SendRtpPacket(
const void *data, int len) {
const uint8_t* data, size_t len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len, len + SRTP_MAX_EXPANSION));
nsAutoPtr<DataBuffer> buf(new DataBuffer(data, len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, true),
NS_DISPATCH_NORMAL);
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, true),
NS_DISPATCH_NORMAL);
return NS_OK;
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
@ -1705,19 +1701,18 @@ nsresult MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket(
const void *data, int len) {
const uint8_t* data, size_t len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len, len + SRTP_MAX_EXPANSION));
nsAutoPtr<DataBuffer> buf(new DataBuffer(data, len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, false),
NS_DISPATCH_NORMAL);
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, false),
NS_DISPATCH_NORMAL);
return NS_OK;
return NS_OK;
}
void MediaPipelineTransmit::PipelineListener::
@ -2212,12 +2207,14 @@ public:
{
#ifdef MOZILLA_INTERNAL_API
ReentrantMonitorAutoEnter enter(monitor_);
#endif // MOZILLA_INTERNAL_API
#if defined(MOZILLA_INTERNAL_API)
if (buffer) {
// Create a video frame using |buffer|.
#ifdef MOZ_WIDGET_GONK
RefPtr<PlanarYCbCrImage> yuvImage = new GrallocImage();
#else
RefPtr<PlanarYCbCrImage> yuvImage = image_container_->CreatePlanarYCbCrImage();
#endif // MOZ_WIDGET_GONK
uint8_t* frame = const_cast<uint8_t*>(static_cast<const uint8_t*> (buffer));
PlanarYCbCrData yuvData;

View file

@ -23,7 +23,7 @@
#include "AudioPacketizer.h"
#include "StreamTracks.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
// Should come from MediaEngine.h, but that's a pain to include here
// because of the MOZILLA_EXTERNAL_LINKAGE stuff.
@ -124,7 +124,7 @@ class MediaPipeline : public sigslot::has_slots<> {
// Used only for testing; installs a MediaPipelineFilter that filters
// everything but the nth ssrc
void SelectSsrc_m(size_t ssrc_index);
void SelectSsrc_s(size_t ssrc_index);
void SelectSsrc_s(uint32_t ssrc);
virtual Direction direction() const { return direction_; }
virtual const std::string& trackid() const { return track_id_; }
@ -154,11 +154,6 @@ class MediaPipeline : public sigslot::has_slots<> {
MAX_RTP_TYPE
} RtpType;
protected:
virtual ~MediaPipeline();
virtual void DetachMedia() {}
nsresult AttachTransport_s();
// Separate class to allow ref counting
class PipelineTransport : public TransportInterface {
public:
@ -171,8 +166,8 @@ class MediaPipeline : public sigslot::has_slots<> {
void Detach() { pipeline_ = nullptr; }
MediaPipeline *pipeline() const { return pipeline_; }
virtual nsresult SendRtpPacket(const void* data, int len);
virtual nsresult SendRtcpPacket(const void* data, int len);
virtual nsresult SendRtpPacket(const uint8_t* data, size_t len);
virtual nsresult SendRtcpPacket(const uint8_t* data, size_t len);
private:
nsresult SendRtpRtcpPacket_s(nsAutoPtr<DataBuffer> data,
@ -181,6 +176,15 @@ class MediaPipeline : public sigslot::has_slots<> {
MediaPipeline *pipeline_; // Raw pointer to avoid cycles
nsCOMPtr<nsIEventTarget> sts_thread_;
};
RefPtr<PipelineTransport> GetPiplelineTransport() {
return transport_;
}
protected:
virtual ~MediaPipeline();
virtual void DetachMedia() {}
nsresult AttachTransport_s();
friend class PipelineTransport;
class TransportInfo {

View file

@ -9,7 +9,7 @@
#include "MediaPipelineFilter.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/common_types.h"
namespace mozilla {

View file

@ -27,16 +27,6 @@
#include "MediaEngine.h"
#endif
#include "GmpVideoCodec.h"
#ifdef MOZ_WEBRTC_OMX
#include "OMXVideoCodec.h"
#include "OMXCodecWrapper.h"
#endif
#ifdef MOZ_WEBRTC_MEDIACODEC
#include "MediaCodecVideoCodec.h"
#endif
#ifdef MOZILLA_INTERNAL_API
#include "mozilla/Preferences.h"
#endif
@ -167,6 +157,8 @@ NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
return NS_ERROR_INVALID_ARG;
}
config->mTias = aDetails.GetTias();
for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
if (jsepEncoding.HasFormat(codec->mDefaultPt)) {
@ -176,6 +168,7 @@ NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
config->mSimulcastEncodings.push_back(encoding);
}
}
aConfigs->values.push_back(config);
}
@ -453,12 +446,14 @@ MediaPipelineFactory::CreateOrUpdateMediaPipeline(
RefPtr<MediaSessionConduit> conduit;
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
rv = GetOrCreateAudioConduit(aTrackPair, aTrack, &conduit);
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
return rv;
}
} else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
rv = GetOrCreateVideoConduit(aTrackPair, aTrack, &conduit);
if (NS_FAILED(rv))
if (NS_FAILED(rv)) {
return rv;
}
} else {
// We've created the TransportFlow, nothing else to do here.
return NS_OK;
@ -730,17 +725,16 @@ MediaPipelineFactory::GetOrCreateAudioConduit(
if (!aTrackPair.mSending) {
// No send track, but we still need to configure an SSRC for receiver
// reports.
if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) {
if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
return NS_ERROR_FAILURE;
}
}
} else {
// For now we only expect to have one ssrc per local track.
auto ssrcs = aTrack.GetSsrcs();
if (!ssrcs.empty()) {
if (!conduit->SetLocalSSRC(ssrcs.front())) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
if (!conduit->SetLocalSSRCs(ssrcs)) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
return NS_ERROR_FAILURE;
}
}
@ -786,7 +780,6 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
const JsepTrack& aTrack,
RefPtr<MediaSessionConduit>* aConduitp)
{
if (!aTrack.GetNegotiatedDetails()) {
MOZ_ASSERT(false, "Track is missing negotiated details");
return NS_ERROR_INVALID_ARG;
@ -798,7 +791,7 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
mPCMedia->GetVideoConduit(aTrackPair.mLevel);
if (!conduit) {
conduit = VideoSessionConduit::Create();
conduit = VideoSessionConduit::Create(mPCMedia->mCall);
if (!conduit) {
MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
return NS_ERROR_FAILURE;
@ -822,103 +815,80 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
return NS_ERROR_FAILURE;
}
const std::vector<uint32_t>* ssrcs;
if (receiving) {
// NOTE(pkerr) - the Call API requires the both local_ssrc and remote_ssrc be
// set to a non-zero value or the CreateVideo...Stream call will fail.
if (aTrackPair.mSending) {
auto ssrcs = &aTrackPair.mSending->GetSsrcs();
ssrcs = &aTrackPair.mSending->GetSsrcs();
if (!ssrcs->empty()) {
if (!conduit->SetLocalSSRC(ssrcs->front())) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed(1)");
return NS_ERROR_FAILURE;
}
} else {
MOZ_MTLOG(ML_ERROR, "Sending without an SSRC??");
return NS_ERROR_FAILURE;
conduit->SetLocalSSRCs(*ssrcs);
}
} else {
// No send track, but we still need to configure an SSRC for receiver
// reports.
if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed(2)");
if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
return NS_ERROR_FAILURE;
}
}
// Prune out stuff we cannot actually do. We should work to eliminate the
// need for this.
bool configuredH264 = false;
for (size_t i = 0; i < configs.values.size();) {
// TODO(bug 1200768): We can only handle configuring one recv H264 codec
if (configuredH264 && (configs.values[i]->mName == "H264")) {
delete configs.values[i];
configs.values.erase(configs.values.begin() + i);
continue;
}
// TODO(bug 1018791): This really should be checked sooner
if (EnsureExternalCodec(*conduit, configs.values[i], false)) {
delete configs.values[i];
configs.values.erase(configs.values.begin() + i);
continue;
}
if (configs.values[i]->mName == "H264") {
configuredH264 = true;
}
++i;
ssrcs = &aTrack.GetSsrcs();
// NOTE(pkerr) - this is new behavior. Needed because the CreateVideoReceiveStream
// method of the Call API will assert (in debug) and fail if a value is not provided
// for the remote_ssrc that will be used by the far-end sender.
if (ssrcs->empty()) {
MOZ_MTLOG(ML_ERROR, "No SSRC set for receive track");
return NS_ERROR_FAILURE;
}
conduit->SetRemoteSSRC(ssrcs->front());
auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
if (error) {
MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
return NS_ERROR_FAILURE;
}
} else {
} else { //Create a send side
// For now we only expect to have one ssrc per local track.
auto ssrcs = aTrack.GetSsrcs();
if (!ssrcs.empty()) {
if (!conduit->SetLocalSSRC(ssrcs.front())) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
return NS_ERROR_FAILURE;
}
ssrcs = &aTrack.GetSsrcs();
if (ssrcs->empty()) {
MOZ_MTLOG(ML_ERROR, "No SSRC set for send track");
return NS_ERROR_FAILURE;
}
if (!conduit->SetLocalSSRCs(*ssrcs)) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
return NS_ERROR_FAILURE;
}
conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
rv = ConfigureVideoCodecMode(aTrack,*conduit);
rv = ConfigureVideoCodecMode(aTrack, *conduit);
if (NS_FAILED(rv)) {
return rv;
}
// TODO(bug 1018791): This really should be checked sooner
if (EnsureExternalCodec(*conduit, configs.values[0], true)) {
MOZ_MTLOG(ML_ERROR, "External codec not available");
return NS_ERROR_FAILURE;
}
auto error = conduit->ConfigureSendMediaCodec(configs.values[0]);
const SdpExtmapAttributeList::Extmap* rtpStreamIdExt =
aTrack.GetNegotiatedDetails()->GetExt(
"urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id");
if (rtpStreamIdExt) {
MOZ_MTLOG(ML_DEBUG, "Calling EnableRTPSenderIdExtension");
error = conduit->EnableRTPStreamIdExtension(true, rtpStreamIdExt->entry);
if (error) {
MOZ_MTLOG(ML_ERROR, "EnableRTPSenderIdExtension failed: " << error);
return NS_ERROR_FAILURE;
}
}
if (error) {
MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
return NS_ERROR_FAILURE;
}
}
const JsepTrackNegotiatedDetails* details = aTrack.GetNegotiatedDetails();
if (details) {
// @@NG read extmap from track
std::vector<webrtc::RtpExtension> extmaps;
details->ForEachRTPHeaderExtension(
[&conduit,&extmaps](const SdpExtmapAttributeList::Extmap& extmap)
{
extmaps.emplace_back(extmap.extensionname,extmap.entry);
});
conduit->AddLocalRTPExtensions(extmaps);
}
*aConduitp = conduit;
return NS_OK;
@ -970,107 +940,5 @@ MediaPipelineFactory::ConfigureVideoCodecMode(const JsepTrack& aTrack,
return NS_OK;
}
/*
* Add external H.264 video codec.
*/
MediaConduitErrorCode
MediaPipelineFactory::EnsureExternalCodec(VideoSessionConduit& aConduit,
VideoCodecConfig* aConfig,
bool aIsSend)
{
if (aConfig->mName == "VP8") {
#ifdef MOZ_WEBRTC_MEDIACODEC
if (aIsSend) {
#ifdef MOZILLA_INTERNAL_API
bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_encode.acceleration_enabled", false);
#else
bool enabled = false;
#endif
if (enabled) {
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
int32_t status;
nsCString discardFailureId;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_ENCODE, discardFailureId, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
NS_WARNING("VP8 encoder hardware is not whitelisted: disabling.\n");
} else {
VideoEncoder* encoder = nullptr;
encoder = MediaCodecVideoCodec::CreateEncoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
if (encoder) {
return aConduit.SetExternalSendCodec(aConfig, encoder);
}
return kMediaConduitNoError;
}
}
}
}
} else {
#ifdef MOZILLA_INTERNAL_API
bool enabled = mozilla::Preferences::GetBool("media.navigator.hardware.vp8_decode.acceleration_enabled", false);
#else
bool enabled = false;
#endif
if (enabled) {
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
int32_t status;
nsCString discardFailureId;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBRTC_HW_ACCELERATION_DECODE, discardFailureId, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
NS_WARNING("VP8 decoder hardware is not whitelisted: disabling.\n");
} else {
VideoDecoder* decoder;
decoder = MediaCodecVideoCodec::CreateDecoder(MediaCodecVideoCodec::CodecType::CODEC_VP8);
if (decoder) {
return aConduit.SetExternalRecvCodec(aConfig, decoder);
}
return kMediaConduitNoError;
}
}
}
}
}
#endif
return kMediaConduitNoError;
}
if (aConfig->mName == "VP9") {
return kMediaConduitNoError;
}
if (aConfig->mName == "H264") {
if (aConduit.CodecPluginID() != 0) {
return kMediaConduitNoError;
}
// Register H.264 codec.
if (aIsSend) {
VideoEncoder* encoder = nullptr;
#ifdef MOZ_WEBRTC_OMX
encoder =
OMXVideoCodec::CreateEncoder(OMXVideoCodec::CodecType::CODEC_H264);
#else
encoder = GmpVideoCodec::CreateEncoder();
#endif
if (encoder) {
return aConduit.SetExternalSendCodec(aConfig, encoder);
}
return kMediaConduitInvalidSendCodec;
}
VideoDecoder* decoder = nullptr;
#ifdef MOZ_WEBRTC_OMX
decoder =
OMXVideoCodec::CreateDecoder(OMXVideoCodec::CodecType::CODEC_H264);
#else
decoder = GmpVideoCodec::CreateDecoder();
#endif
if (decoder) {
return aConduit.SetExternalRecvCodec(aConfig, decoder);
}
return kMediaConduitInvalidReceiveCodec;
}
MOZ_MTLOG(ML_ERROR,
"Invalid video codec configured: " << aConfig->mName.c_str());
return aIsSend ? kMediaConduitInvalidSendCodec
: kMediaConduitInvalidReceiveCodec;
}
} // namespace mozilla

View file

@ -52,10 +52,6 @@ private:
const JsepTrack& aTrack,
RefPtr<MediaSessionConduit>* aConduitp);
MediaConduitErrorCode EnsureExternalCodec(VideoSessionConduit& aConduit,
VideoCodecConfig* aConfig,
bool aIsSend);
nsresult CreateOrGetTransportFlow(size_t aLevel, bool aIsRtcp,
const JsepTransport& transport,
RefPtr<TransportFlow>* out);

View file

@ -2745,7 +2745,11 @@ PeerConnectionImpl::ReplaceTrack(MediaStreamTrack& aThisTrack,
// We update the media pipelines here so we can apply different codec
// settings for different sources (e.g. screensharing as opposed to camera.)
// TODO: We should probably only do this if the source has in fact changed.
mMedia->UpdateMediaPipelines(*mJsepSession);
if (NS_FAILED((rv = mMedia->UpdateMediaPipelines(*mJsepSession)))) {
CSFLogError(logTag, "Error Updating MediaPipelines");
return rv;
}
pco->OnReplaceTrackSuccess(jrv);
if (jrv.Failed()) {
@ -3108,7 +3112,11 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
// transports, but nothing further needs to be done.
mMedia->ActivateOrRemoveTransports(*mJsepSession);
if (!rollback) {
mMedia->UpdateMediaPipelines(*mJsepSession);
if (NS_FAILED(mMedia->UpdateMediaPipelines(*mJsepSession))) {
CSFLogError(logTag, "Error Updating MediaPipelines");
NS_ASSERTION(false, "Error Updating MediaPipelines in SetSignalingState_m()");
// XXX what now? Not much we can do but keep going, without major restructuring
}
InitializeDataChannel();
mMedia->StartIceChecks(*mJsepSession);
}
@ -3663,15 +3671,17 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
idstr.AppendLiteral("_");
idstr.AppendInt(mp.level());
// TODO(@@NG):ssrcs handle Conduits having multiple stats at the same level
// This is pending spec work
// Gather pipeline stats.
switch (mp.direction()) {
case MediaPipeline::TRANSMIT: {
nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr;
nsString remoteId;
nsString ssrc;
unsigned int ssrcval;
if (mp.Conduit()->GetLocalSSRC(&ssrcval)) {
ssrc.AppendInt(ssrcval);
std::vector<unsigned int> ssrcvals = mp.Conduit()->GetLocalSSRCs();
if (!ssrcvals.empty()) {
ssrc.AppendInt(ssrcvals[0]);
}
{
// First, fill in remote stat with rtcp receiver data, if present.

View file

@ -67,6 +67,14 @@ using namespace dom;
static const char* logTag = "PeerConnectionMedia";
//XXX(pkerr) What about bitrate settings? Going with the defaults for now.
RefPtr<WebRtcCallWrapper>
CreateCall()
{
WebRtcCallWrapper::Config call_config;
return WebRtcCallWrapper::Create(call_config);
}
nsresult
PeerConnectionMedia::ReplaceTrack(const std::string& aOldStreamId,
const std::string& aOldTrackId,
@ -406,6 +414,9 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
}
ConnectSignals(mIceCtxHdlr->ctx().get());
// This webrtc:Call instance will be shared by audio and video media conduits.
mCall = CreateCall();
return NS_OK;
}
@ -567,6 +578,7 @@ nsresult PeerConnectionMedia::UpdateMediaPipelines(
JsepTrackPair pair = *i;
if (pair.mReceiving) {
rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mReceiving);
if (NS_FAILED(rv)) {
return rv;

View file

@ -410,15 +410,15 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
static_cast<VideoSessionConduit*>(it->second.second.get()));
}
void AddVideoConduit(size_t level, const RefPtr<VideoSessionConduit> &aConduit) {
mConduits[level] = std::make_pair(true, aConduit);
}
// Add a conduit
void AddAudioConduit(size_t level, const RefPtr<AudioSessionConduit> &aConduit) {
mConduits[level] = std::make_pair(false, aConduit);
}
void AddVideoConduit(size_t level, const RefPtr<VideoSessionConduit> &aConduit) {
mConduits[level] = std::make_pair(true, aConduit);
}
// ICE state signals
sigslot::signal2<NrIceCtx*, NrIceCtx::GatheringState>
SignalIceGatheringStateChange;
@ -433,6 +433,8 @@ class PeerConnectionMedia : public sigslot::has_slots<> {
sigslot::signal1<uint16_t>
SignalEndOfLocalCandidates;
RefPtr<WebRtcCallWrapper> mCall;
private:
nsresult InitProxy();
class ProtocolProxyQueryHandler : public nsIProtocolProxyCallback {

View file

@ -34,7 +34,7 @@
#include "runnable_utils.h"
#include "PeerConnectionCtx.h"
#include "PeerConnectionImpl.h"
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/include/trace.h"
static const char* logTag = "WebrtcGlobalInformation";

View file

@ -34,7 +34,7 @@
#include "mtransport_test_utils.h"
#include "runnable_utils.h"
#include "webrtc/modules/interface/module_common_types.h"
#include "webrtc/modules/include/module_common_types.h"
#include "FakeIPC.h"
#include "FakeIPC.cpp"

View file

@ -1,19 +1,21 @@
# Names should be added to this file like so:
# Name or Organization <email address>
Andrew MacDonald <andrew@webrtc.org>
Anil Kumar <an1kumar@gmail.com>
Ben Strong <bstrong@gmail.com>
Bob Withers <bwit@pobox.com>
Bridger Maxwell <bridgeyman@gmail.com>
Christophe Dumez <ch.dumez@samsung.com>
Colin Plumb
Eric Rescorla, RTFM Inc.
Eric Rescorla, RTFM Inc. <ekr@rtfm.com>
Giji Gangadharan <giji.g@samsung.com>
Graham Yoakum <gyoakum@skobalt.com>
Jake Hilton <jakehilton@gmail.com>
James H. Brown <jbrown@burgoyne.com>
Jiawei Ou <jiawei.ou@gmail.com>
Jie Mao <maojie0924@gmail.com>
Luke Weber
Luke Weber <luke.weber@gmail.com>
Manish Jethani <manish.jethani@gmail.com>
Martin Storsjo <martin@martin.st>
Matthias Liebig <matthias.gcode@gmail.com>
@ -21,8 +23,8 @@ Pali Rohar
Paul Kapustin <pkapustin@gmail.com>
Rafael Lopez Diez <rafalopezdiez@gmail.com>
Ralph Giles <giles@ghostscript.com>
Robert Nagy
Ron Rivest
Riku Voipio <riku.voipio@linaro.org>
Robert Nagy <robert.nagy@gmail.com>
Ryan Yoakum <ryoakum@skobalt.com>
Sarah Thompson <sarah@telergy.com>
Saul Kravitz <Saul.Kravitz@celera.com>
@ -30,13 +32,19 @@ Silviu Caragea <silviu.cpp@gmail.com>
Steve Reid <sreid@sea-to-sky.net>
Vicken Simonian <vsimon@gmail.com>
Victor Costan <costan@gmail.com>
Alexander Brauckmann <a.brauckmann@gmail.com>
&yet LLC
Agora IO
ARM Holdings
BroadSoft Inc.
Google Inc.
Intel Corporation
MIPS Technologies
Mozilla Foundation
Opera Software ASA
Sinch AB
struktur AG
Telenor Digital AS
Temasys Communications
Vonage Holdings Corp.

View file

@ -6,7 +6,7 @@
vars = {
'extra_gyp_flag': '-Dextra_gyp_flag=0',
'chromium_git': 'https://chromium.googlesource.com',
'chromium_revision': '719b83983be9613eb80e99a0bc645776d59b76b3',
'chromium_revision': '099be58b08dadb64b1dc9f359ae097e978df5416',
}
# NOTE: Prefer revision numbers to tags for svn deps. Use http rather than
@ -17,14 +17,14 @@ deps = {
'src/third_party/gflags/src':
Var('chromium_git') + '/external/gflags/src@e7390f9185c75f8d902c05ed7d20bb94eb914d0c', # from svn revision 82
'src/third_party/junit':
'src/third_party/junit-jar':
Var('chromium_git') + '/external/webrtc/deps/third_party/junit@f35596b476aa6e62fd3b3857b9942ddcd13ce35e', # from svn revision 3367
}
deps_os = {
'win': {
'src/third_party/winsdk_samples/src':
Var('chromium_git') + '/external/webrtc/deps/third_party/winsdk_samples_v71@c0cbedd854cb610a53226d9817416c4ab9a7d1e9', # from svn revision 7951
Var('chromium_git') + '/external/webrtc/deps/third_party/winsdk_samples_v71@e71b549167a665d7424d6f1dadfbff4b4aad1589',
},
}
@ -34,18 +34,16 @@ include_rules = [
# WebRTC production code.
'-base',
'-chromium',
'+external/webrtc/webrtc', # Android platform build.
'+gflags',
'+libyuv',
'+net',
'+talk',
'+testing',
'+third_party',
'+unicode',
'+webrtc',
]
# checkdeps.py shouldn't check include paths for files in these dirs:
skip_child_includes = [
'webrtc/overrides',
'+vpx',
]
hooks = [
@ -72,6 +70,21 @@ hooks = [
'pattern': '.',
'action': ['python', 'src/setup_links.py'],
},
{
# This clobbers when necessary (based on get_landmines.py). It should be
# an early hook but it will need to be run after syncing Chromium and
# setting up the links, so the script actually exists.
'name': 'landmines',
'pattern': '.',
'action': [
'python',
'src/build/landmines.py',
'--landmine-scripts',
'src/webrtc/build/get_landmines.py',
'--src-dir',
'src',
],
},
{
# Pull sanitizer-instrumented third-party libraries if requested via
# GYP_DEFINES. This could be done as part of sync_chromium.py above
@ -89,6 +102,7 @@ hooks = [
'--recursive',
'--num_threads=10',
'--no_auth',
'--quiet',
'--bucket', 'chromium-webrtc-resources',
'src/resources'],
},

View file

@ -1,4 +1,3 @@
andrew@webrtc.org
henrika@webrtc.org
mflodman@webrtc.org
niklas.enbom@webrtc.org
@ -6,6 +5,7 @@ tina.legrand@webrtc.org
tommi@webrtc.org
per-file .gitignore=*
per-file AUTHORS=*
per-file .gn=kjellander@webrtc.org
per-file BUILD.gn=kjellander@webrtc.org
per-file DEPS=*
per-file PRESUBMIT.py=kjellander@webrtc.org

View file

@ -1,12 +0,0 @@
This folder can be used to pull together the chromium version of webrtc
and libjingle, and build the peerconnection sample client and server. This will
check out a new repository in which you can build peerconnection_server.
Steps:
1) Create a new directory for the new repository (outside the webrtc repo):
mkdir peerconnection
cd peerconnection
2) gclient config --name trunk http://webrtc.googlecode.com/svn/trunk/peerconnection
3) gclient sync
4) cd trunk
5) make peerconnection_server peerconnection_client

View file

@ -0,0 +1,23 @@
**WebRTC is a free, open software project** that provides browsers and mobile
applications with Real-Time Communications (RTC) capabilities via simple APIs.
The WebRTC components have been optimized to best serve this purpose.
**Our mission:** To enable rich, high-quality RTC applications to be
developed for the browser, mobile platforms, and IoT devices, and allow them
all to communicate via a common set of protocols.
The WebRTC initiative is a project supported by Google, Mozilla and Opera,
amongst others. This page is maintained by the Google Chrome team.
### Development
See http://www.webrtc.org/native-code/development for instructions on how to get
started developing with the native code.
### More info
* Official web site: http://www.webrtc.org
* Master source code repo: https://chromium.googlesource.com/external/webrtc
* Samples and reference apps: https://github.com/webrtc
* Mailing list: http://groups.google.com/group/discuss-webrtc
* Continuous build: http://build.chromium.org/p/client.webrtc

View file

@ -917,23 +917,24 @@
'android_app_version_name%': 'Developer Build',
'android_app_version_code%': 0,
'sas_dll_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))',
'wix_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))',
'sas_dll_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))',
'wix_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))',
'windows_sdk_default_path': '<(DEPTH)/third_party/platformsdk_win8/files',
'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
# 'directx_sdk_default_path': '<(DEPTH)/third_party/directxsdk/files',
'windows_sdk_path%': '<(windows_sdk_default_path)',
'conditions': [
['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', {
'windows_sdk_path%': '<(windows_sdk_default_path)',
}, {
'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
}],
['OS=="win" and "<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(directx_sdk_default_path))"=="True"', {
'directx_sdk_path%': '<(directx_sdk_default_path)',
}, {
'directx_sdk_path%': '$(DXSDK_DIR)',
}],
#['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', {
# 'windows_sdk_path%': '<(windows_sdk_default_path)',
#}, {
# 'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
#}],
#['OS=="win" and "<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(directx_sdk_default_path))"=="True"', {
# 'directx_sdk_path%': '<(directx_sdk_default_path)',
#}, {
# 'directx_sdk_path%': '$(DXSDK_DIR)',
#}],
# If use_official_google_api_keys is already set (to 0 or 1), we
# do none of the implicit checking. If it is set to 1 and the
# internal keys file is missing, the build will fail at compile
@ -3410,7 +3411,7 @@
'<(windows_sdk_path)/Include/shared',
'<(windows_sdk_path)/Include/um',
'<(windows_sdk_path)/Include/winrt',
'<(directx_sdk_path)/Include',
# '<(directx_sdk_path)/Include',
'$(VSInstallDir)/VC/atlmfc/include',
],
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
@ -3442,7 +3443,7 @@
'VCLibrarianTool': {
'AdditionalOptions': ['/ignore:4221'],
'AdditionalLibraryDirectories': [
'<(directx_sdk_path)/Lib/x86',
# '<(directx_sdk_path)/Lib/x86',
'<(windows_sdk_path)/Lib/win8/um/x86',
],
},
@ -3488,7 +3489,7 @@
}],
],
'AdditionalLibraryDirectories': [
'<(directx_sdk_path)/Lib/x86',
# '<(directx_sdk_path)/Lib/x86', XXXX
'<(windows_sdk_path)/Lib/win8/um/x86',
],
'GenerateDebugInformation': 'true',

View file

@ -7,10 +7,13 @@
# be found in the AUTHORS file in the root of the source tree.
{
'includes': [ 'webrtc/build/common.gypi', ],
'includes': [
'webrtc/build/common.gypi',
'webrtc/video/webrtc_video.gypi',
],
'variables': {
'peerconnection_sample': 'third_party/libjingle/source/talk/examples/peerconnection',
},
},
# for mozilla, we want to force stuff to build but we don't want peerconnection_client or server
# for unknown reasons, 'targets' must be outside of conditions. And don't try to build a dummy
@ -22,19 +25,21 @@
'target_name': 'dummy',
'type': 'none',
'dependencies': [
'webrtc/webrtc.gyp:webrtc_lib',
'webrtc/modules/modules.gyp:audio_device',
'webrtc/modules/modules.gyp:video_capture_module',
'webrtc/modules/modules.gyp:video_capture_module_internal_impl',
'webrtc/modules/modules.gyp:video_capture_module_internal_impl',
'webrtc/modules/modules.gyp:video_render',
# 'webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers',
# 'webrtc/system_wrappers/source/system_wrappers.gyp:metrics_default',
'webrtc/video_engine/video_engine.gyp:video_engine_core',
'webrtc/voice_engine/voice_engine.gyp:voice_engine',
# 'webrtc/system_wrappers/source/system_wrappers.gyp:metrics_default',
# 'webrtc/video_engine/video_engine.gyp:video_engine_core',
'webrtc/voice_engine/voice_engine.gyp:voice_engine',
# '<@(webrtc_video_dependencies)',
],
'conditions': [
['OS!="android" and OS!="ios"', {
'dependencies': [
'webrtc/modules/modules.gyp:desktop_capture',
'webrtc/modules/modules.gyp:desktop_capture',
],
},
]],
@ -86,8 +91,8 @@
},
},
'dependencies': [
'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
#'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
#'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
],
'include_dirs': [
'src',
@ -114,8 +119,8 @@
'<(peerconnection_sample)/client/peer_connection_client.h',
],
'dependencies': [
'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
#'third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
#'third_party/libjingle/libjingle.gyp:libjingle_peerconnection',
# TODO(tommi): Switch to this and remove specific gtk dependency
# sections below for cflags and link_settings.
# '<(DEPTH)/build/linux/system.gyp:gtk',

View file

@ -46,10 +46,13 @@ def FindBuildFiles():
build_files.append(file)
return build_files
#TODO @@NG Find correct way to pass circular_check to Load
# Causes a pickle error in gyp.input.CircularException
# see http://stackoverflow.com/questions/4677012/python-cant-pickle-type-x-attribute-lookup-failed
# we'll live without the check - jesup
def Load(build_files, format, default_variables={},
includes=[], depth='.', params=None, check=False,
circular_check=True, duplicate_basename_check=True):
circular_check=False, duplicate_basename_check=True):
"""
Loads one or more specified build files.
default_variables and includes will be copied before use.

View file

@ -1,2 +1,29 @@
# This file is for projects that checkout webrtc/ directly (e.g. Chromium).
*.mk
# This file is for projects that checkout webrtc/ directly (e.g. Chromium). It
# is a truncated copy of the .gitignore file in the parent directory.
*.DS_Store
*.Makefile
*.host.mk
*.ncb
*.ninja
*.props
*.pyc
*.rules
*.scons
*.sdf
*.sln
*.suo
*.target.mk
*.targets
*.user
*.vcproj
*.vcxproj
*.vcxproj.filters
*.vpj
*.vpw
*.vpwhistu
*.vtg
*.xcodeproj
*_proto.xml
*_proto_cpp.xml
*~
.*.sw?

View file

@ -8,9 +8,10 @@
# TODO(kjellander): Rebase this to webrtc/build/common.gypi changes after r6330.
import("//build/config/crypto.gni")
import("//build/config/linux/pkg_config.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("build/webrtc.gni")
import("//third_party/protobuf/proto_library.gni")
# Contains the defines and includes in common.gypi that are duplicated both as
# target_defaults and direct_dependent_settings.
@ -20,13 +21,12 @@ config("common_inherited_config") {
defines += [ "WEBRTC_MOZILLA_BUILD" ]
}
if (build_with_chromium) {
defines = [
"WEBRTC_CHROMIUM_BUILD",
]
defines = [ "WEBRTC_CHROMIUM_BUILD" ]
include_dirs = [
# overrides must be included first as that is the mechanism for
# The overrides must be included first as that is the mechanism for
# selecting the override headers in Chromium.
"overrides",
"../webrtc_overrides",
# Allow includes to be prefixed with webrtc/ in case it is not an
# immediate subdirectory of the top-level.
"..",
@ -41,6 +41,9 @@ config("common_inherited_config") {
"WEBRTC_IOS",
]
}
if (is_ios && rtc_use_objc_h264) {
defines += [ "WEBRTC_OBJC_H264" ]
}
if (is_linux) {
defines += [ "WEBRTC_LINUX" ]
}
@ -55,9 +58,6 @@ config("common_inherited_config") {
"WEBRTC_LINUX",
"WEBRTC_ANDROID",
]
if (rtc_enable_android_opensl) {
defines += [ "WEBRTC_ANDROID_OPENSLES" ]
}
}
}
@ -76,6 +76,7 @@ config("common_config") {
if (rtc_have_dbus_glib) {
defines += [ "HAVE_DBUS_GLIB" ]
# TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h>
# is still not found even if the execution of
# build/config/linux/pkg-config.py dbus-glib-1 returns correct include
@ -96,6 +97,7 @@ config("common_config") {
if (current_cpu != "arm64" || !is_android) {
cflags = [
"-Wextra",
# We need to repeat some flags from Chromium"s common.gypi
# here that get overridden by -Wextra.
"-Wno-unused-parameter",
@ -104,6 +106,7 @@ config("common_config") {
]
cflags_cc = [
"-Wnon-virtual-dtor",
# This is enabled for clang; enable for gcc as well.
"-Woverloaded-virtual",
]
@ -116,13 +119,8 @@ config("common_config") {
}
if (current_cpu == "arm64") {
defines += [ "WEBRTC_ARCH_ARM" ]
# TODO(zhongwei) Defining an unique WEBRTC_NEON and
# distinguishing ARMv7 NEON and ARM64 NEON by
# WEBRTC_ARCH_ARM_V7 and WEBRTC_ARCH_ARM64 should be better.
# This macro is used to distinguish ARMv7 NEON and ARM64 NEON
defines += [ "WEBRTC_ARCH_ARM64_NEON" ]
defines += [ "WEBRTC_ARCH_ARM64" ]
defines += [ "WEBRTC_HAS_NEON" ]
}
if (current_cpu == "arm") {
@ -130,9 +128,9 @@ config("common_config") {
if (arm_version >= 7) {
defines += [ "WEBRTC_ARCH_ARM_V7" ]
if (arm_use_neon) {
defines += [ "WEBRTC_ARCH_ARM_NEON" ]
} else if (is_android) {
defines += [ "WEBRTC_DETECT_ARM_NEON" ]
defines += [ "WEBRTC_HAS_NEON" ]
} else if (arm_optionally_use_neon) {
defines += [ "WEBRTC_DETECT_NEON" ]
}
}
}
@ -155,10 +153,7 @@ config("common_config") {
}
}
# TODO(kjellander): Handle warnings on Windows where WebRTC differ from the
# default warnings set in build/config/compiler/BUILD.gn.
if (is_android && is_clang) {
if (is_android && !is_clang) {
# The Android NDK doesn"t provide optimized versions of these
# functions. Ensure they are disabled for all compilers.
cflags += [
@ -174,17 +169,19 @@ source_set("webrtc") {
sources = [
"call.h",
"config.h",
"experiments.h",
"frame_callback.h",
"transport.h",
]
defines = []
configs += [ ":common_config" ]
public_configs = [ ":common_inherited_config"]
public_configs = [ ":common_inherited_config" ]
deps = [
":webrtc_common",
"audio",
"base:rtc_base",
"call",
"common_audio",
"common_video",
"modules/audio_coding",
@ -201,16 +198,20 @@ source_set("webrtc") {
"system_wrappers",
"tools",
"video",
"video_engine",
"voice_engine",
]
if (build_with_chromium) {
deps += [
"modules/video_capture",
"modules/video_render",
"modules/video_capture",
"modules/video_render",
]
}
if (rtc_enable_protobuf) {
defines += [ "ENABLE_RTC_EVENT_LOG" ]
deps += [ ":rtc_event_log_proto" ]
}
}
if (!build_with_chromium) {
@ -218,8 +219,8 @@ if (!build_with_chromium) {
testonly = true
deps = [
":webrtc",
"modules/video_render:video_render_internal_impl",
"modules/video_capture:video_capture_internal_impl",
"modules/video_render:video_render_internal_impl",
"test",
]
}
@ -229,14 +230,20 @@ source_set("webrtc_common") {
sources = [
"common_types.cc",
"common_types.h",
"config.h",
"config.cc",
"config.h",
"engine_configurations.h",
"typedefs.h",
]
configs += [ ":common_config" ]
public_configs = [ ":common_inherited_config" ]
if (is_clang && !is_nacl) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
}
source_set("gtest_prod") {
@ -244,3 +251,48 @@ source_set("gtest_prod") {
"test/testsupport/gtest_prod_util.h",
]
}
if (rtc_enable_protobuf) {
proto_library("rtc_event_log_proto") {
sources = [
"call/rtc_event_log.proto",
]
proto_out_dir = "webrtc/call"
}
}
source_set("rtc_event_log") {
sources = [
"call/rtc_event_log.cc",
"call/rtc_event_log.h",
]
defines = []
configs += [ ":common_config" ]
public_configs = [ ":common_inherited_config" ]
deps = [
":webrtc_common",
]
if (rtc_enable_protobuf) {
defines += [ "ENABLE_RTC_EVENT_LOG" ]
deps += [ ":rtc_event_log_proto" ]
}
if (is_clang && !is_nacl) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
}
if (use_libfuzzer || use_drfuzz) {
# This target is only here for gn to discover fuzzer build targets under
# webrtc/test/fuzzers/.
group("webrtc_fuzzers_dummy") {
testonly = true
deps = [
"test/fuzzers:webrtc_fuzzer_main",
]
}
}

View file

@ -0,0 +1,76 @@
# Copyright (c) 2015 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.
import("../build/webrtc.gni")
config("ios_config") {
libs = [
"CoreGraphics.framework",
"GLKit.framework",
"OpenGLES.framework",
"QuartzCore.framework",
]
}
if (is_ios) {
source_set("rtc_api_objc") {
deps = [
"//webrtc/base:rtc_base_objc",
#"//talk/libjingle:libjingle_peerconnection",
]
cflags = [
"-fobjc-arc",
"-Wobjc-missing-property-synthesis",
]
sources = [
# Add these when there's a BUILD.gn for peer connection APIs
#"objc/RTCIceCandidate+Private.h",
#"objc/RTCIceCandidate.h",
#"objc/RTCIceCandidate.mm",
#"objc/RTCMediaSource+Private.h",
#"objc/RTCMediaSource.h",
#"objc/RTCMediaSource.mm",
#"objc/RTCMediaStreamTrack+Private.h",
#"objc/RTCMediaStreamTrack.h",
#"objc/RTCMediaStreamTrack.mm",
"objc/RTCIceServer+Private.h",
"objc/RTCIceServer.h",
"objc/RTCIceServer.mm",
"objc/RTCMediaConstraints+Private.h",
"objc/RTCMediaConstraints.h",
"objc/RTCMediaConstraints.mm",
"objc/RTCOpenGLVideoRenderer.h",
"objc/RTCOpenGLVideoRenderer.mm",
"objc/RTCSessionDescription+Private.h",
"objc/RTCSessionDescription.h",
"objc/RTCSessionDescription.mm",
"objc/RTCStatsReport+Private.h",
"objc/RTCStatsReport.h",
"objc/RTCStatsReport.mm",
"objc/RTCVideoFrame+Private.h",
"objc/RTCVideoFrame.h",
"objc/RTCVideoFrame.mm",
"objc/RTCVideoRenderer.h",
"objc/WebRTC-Prefix.pch",
]
if (is_ios) {
sources += [
"objc/RTCEAGLVideoView.h",
"objc/RTCEAGLVideoView.m",
]
}
if (is_mac) {
sources += [
"objc/RTCNSGLVideoView.h",
"objc/RTCNSGLVideoView.m",
]
}
}
}

View file

@ -0,0 +1 @@
tkchin@webrtc.org

View file

@ -0,0 +1,83 @@
# Copyright (c) 2015 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.
{
'includes': [ '../build/common.gypi', ],
'conditions': [
['OS=="ios"', {
'targets': [
{
'target_name': 'rtc_api_objc',
'type': 'static_library',
'dependencies': [
'<(webrtc_root)/base/base.gyp:rtc_base_objc',
'../../talk/libjingle.gyp:libjingle_peerconnection',
],
'sources': [
'objc/RTCIceCandidate+Private.h',
'objc/RTCIceCandidate.h',
'objc/RTCIceCandidate.mm',
'objc/RTCIceServer+Private.h',
'objc/RTCIceServer.h',
'objc/RTCIceServer.mm',
'objc/RTCMediaConstraints+Private.h',
'objc/RTCMediaConstraints.h',
'objc/RTCMediaConstraints.mm',
'objc/RTCMediaSource+Private.h',
'objc/RTCMediaSource.h',
'objc/RTCMediaSource.mm',
'objc/RTCMediaStreamTrack+Private.h',
'objc/RTCMediaStreamTrack.h',
'objc/RTCMediaStreamTrack.mm',
'objc/RTCOpenGLVideoRenderer.h',
'objc/RTCOpenGLVideoRenderer.mm',
'objc/RTCSessionDescription+Private.h',
'objc/RTCSessionDescription.h',
'objc/RTCSessionDescription.mm',
'objc/RTCStatsReport+Private.h',
'objc/RTCStatsReport.h',
'objc/RTCStatsReport.mm',
'objc/RTCVideoFrame+Private.h',
'objc/RTCVideoFrame.h',
'objc/RTCVideoFrame.mm',
'objc/RTCVideoRenderer.h',
],
'conditions': [
['OS=="ios"', {
'sources': [
'objc/RTCEAGLVideoView.h',
'objc/RTCEAGLVideoView.m',
],
'all_dependent_settings': {
'xcode_settings': {
'OTHER_LDFLAGS': [
'-framework CoreGraphics',
'-framework GLKit',
'-framework OpenGLES',
'-framework QuartzCore',
]
}
}
}],
['OS=="mac"', {
'sources': [
'objc/RTCNSGLVideoView.h',
'objc/RTCNSGLVideoView.m',
],
}],
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
},
}
],
}], # OS=="ios"
],
}

View file

@ -0,0 +1,40 @@
# Copyright (c) 2015 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.
{
'includes': [ '../build/common.gypi', ],
'conditions': [
['OS=="ios"', {
'targets': [
{
'target_name': 'rtc_api_objc_test',
'type': 'executable',
'dependencies': [
'<(webrtc_root)/api/api.gyp:rtc_api_objc',
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
],
'sources': [
'objctests/RTCIceCandidateTest.mm',
'objctests/RTCIceServerTest.mm',
'objctests/RTCMediaConstraintsTest.mm',
'objctests/RTCSessionDescriptionTest.mm',
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
# |-ObjC| flag needed to make sure category method implementations
# are included:
# https://developer.apple.com/library/mac/qa/qa1490/_index.html
'OTHER_LDFLAGS': ['-ObjC'],
},
}
],
}], # OS=="ios"
],
}

View file

@ -0,0 +1 @@
tkchin@webrtc.org

View file

@ -0,0 +1,3 @@
This is a work-in-progress to update the Objective-C API according to the W3C
specification. The Objective-C API located at talk/app/webrtc/objc is
deprecated, but will remain for the time being.

View file

@ -0,0 +1,35 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RTCVideoRenderer.h"
NS_ASSUME_NONNULL_BEGIN
@class RTCEAGLVideoView;
@protocol RTCEAGLVideoViewDelegate
- (void)videoView:(RTCEAGLVideoView *)videoView didChangeVideoSize:(CGSize)size;
@end
/**
* RTCEAGLVideoView is an RTCVideoRenderer which renders video frames in its
* bounds using OpenGLES 2.0.
*/
@interface RTCEAGLVideoView : UIView <RTCVideoRenderer>
@property(nonatomic, weak) id<RTCEAGLVideoViewDelegate> delegate;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,259 @@
/*
* Copyright 2015 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.
*/
#import "RTCEAGLVideoView.h"
#import <GLKit/GLKit.h>
#import "RTCVideoFrame.h"
#import "RTCOpenGLVideoRenderer.h"
// RTCDisplayLinkTimer wraps a CADisplayLink and is set to fire every two screen
// refreshes, which should be 30fps. We wrap the display link in order to avoid
// a retain cycle since CADisplayLink takes a strong reference onto its target.
// The timer is paused by default.
@interface RTCDisplayLinkTimer : NSObject
@property(nonatomic) BOOL isPaused;
- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler;
- (void)invalidate;
@end
@implementation RTCDisplayLinkTimer {
CADisplayLink *_displayLink;
void (^_timerHandler)(void);
}
- (instancetype)initWithTimerHandler:(void (^)(void))timerHandler {
NSParameterAssert(timerHandler);
if (self = [super init]) {
_timerHandler = timerHandler;
_displayLink =
[CADisplayLink displayLinkWithTarget:self
selector:@selector(displayLinkDidFire:)];
_displayLink.paused = YES;
// Set to half of screen refresh, which should be 30fps.
[_displayLink setFrameInterval:2];
[_displayLink addToRunLoop:[NSRunLoop currentRunLoop]
forMode:NSRunLoopCommonModes];
}
return self;
}
- (void)dealloc {
[self invalidate];
}
- (BOOL)isPaused {
return _displayLink.paused;
}
- (void)setIsPaused:(BOOL)isPaused {
_displayLink.paused = isPaused;
}
- (void)invalidate {
[_displayLink invalidate];
}
- (void)displayLinkDidFire:(CADisplayLink *)displayLink {
_timerHandler();
}
@end
// RTCEAGLVideoView wraps a GLKView which is setup with
// enableSetNeedsDisplay = NO for the purpose of gaining control of
// exactly when to call -[GLKView display]. This need for extra
// control is required to avoid triggering method calls on GLKView
// that results in attempting to bind the underlying render buffer
// when the drawable size would be empty which would result in the
// error GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT. -[GLKView display] is
// the method that will trigger the binding of the render
// buffer. Because the standard behaviour of -[UIView setNeedsDisplay]
// is disabled for the reasons above, the RTCEAGLVideoView maintains
// its own |isDirty| flag.
@interface RTCEAGLVideoView () <GLKViewDelegate>
// |videoFrame| is set when we receive a frame from a worker thread and is read
// from the display link callback so atomicity is required.
@property(atomic, strong) RTCVideoFrame *videoFrame;
@property(nonatomic, readonly) GLKView *glkView;
@property(nonatomic, readonly) RTCOpenGLVideoRenderer *glRenderer;
@end
@implementation RTCEAGLVideoView {
RTCDisplayLinkTimer *_timer;
// This flag should only be set and read on the main thread (e.g. by
// setNeedsDisplay)
BOOL _isDirty;
}
@synthesize delegate = _delegate;
@synthesize videoFrame = _videoFrame;
@synthesize glkView = _glkView;
@synthesize glRenderer = _glRenderer;
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self configure];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self configure];
}
return self;
}
- (void)configure {
EAGLContext *glContext =
[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if (!glContext) {
glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}
_glRenderer = [[RTCOpenGLVideoRenderer alloc] initWithContext:glContext];
// GLKView manages a framebuffer for us.
_glkView = [[GLKView alloc] initWithFrame:CGRectZero
context:glContext];
_glkView.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
_glkView.drawableDepthFormat = GLKViewDrawableDepthFormatNone;
_glkView.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
_glkView.drawableMultisample = GLKViewDrawableMultisampleNone;
_glkView.delegate = self;
_glkView.layer.masksToBounds = YES;
_glkView.enableSetNeedsDisplay = NO;
[self addSubview:_glkView];
// Listen to application state in order to clean up OpenGL before app goes
// away.
NSNotificationCenter *notificationCenter =
[NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self
selector:@selector(willResignActive)
name:UIApplicationWillResignActiveNotification
object:nil];
[notificationCenter addObserver:self
selector:@selector(didBecomeActive)
name:UIApplicationDidBecomeActiveNotification
object:nil];
// Frames are received on a separate thread, so we poll for current frame
// using a refresh rate proportional to screen refresh frequency. This
// occurs on the main thread.
__weak RTCEAGLVideoView *weakSelf = self;
_timer = [[RTCDisplayLinkTimer alloc] initWithTimerHandler:^{
RTCEAGLVideoView *strongSelf = weakSelf;
[strongSelf displayLinkTimerDidFire];
}];
[self setupGL];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
UIApplicationState appState =
[UIApplication sharedApplication].applicationState;
if (appState == UIApplicationStateActive) {
[self teardownGL];
}
[_timer invalidate];
}
#pragma mark - UIView
- (void)setNeedsDisplay {
[super setNeedsDisplay];
_isDirty = YES;
}
- (void)setNeedsDisplayInRect:(CGRect)rect {
[super setNeedsDisplayInRect:rect];
_isDirty = YES;
}
- (void)layoutSubviews {
[super layoutSubviews];
_glkView.frame = self.bounds;
}
#pragma mark - GLKViewDelegate
// This method is called when the GLKView's content is dirty and needs to be
// redrawn. This occurs on main thread.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
// The renderer will draw the frame to the framebuffer corresponding to the
// one used by |view|.
[_glRenderer drawFrame:self.videoFrame];
}
#pragma mark - RTCVideoRenderer
// These methods may be called on non-main thread.
- (void)setSize:(CGSize)size {
__weak RTCEAGLVideoView *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
RTCEAGLVideoView *strongSelf = weakSelf;
[strongSelf.delegate videoView:strongSelf didChangeVideoSize:size];
});
}
- (void)renderFrame:(RTCVideoFrame *)frame {
self.videoFrame = frame;
}
#pragma mark - Private
- (void)displayLinkTimerDidFire {
// Don't render unless video frame have changed or the view content
// has explicitly been marked dirty.
if (!_isDirty && _glRenderer.lastDrawnFrame == self.videoFrame) {
return;
}
// Always reset isDirty at this point, even if -[GLKView display]
// won't be called in the case the drawable size is empty.
_isDirty = NO;
// Only call -[GLKView display] if the drawable size is
// non-empty. Calling display will make the GLKView setup its
// render buffer if necessary, but that will fail with error
// GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT if size is empty.
if (self.bounds.size.width > 0 && self.bounds.size.height > 0) {
[_glkView display];
}
}
- (void)setupGL {
self.videoFrame = nil;
[_glRenderer setupGL];
_timer.isPaused = NO;
}
- (void)teardownGL {
self.videoFrame = nil;
_timer.isPaused = YES;
[_glkView deleteDrawable];
[_glRenderer teardownGL];
}
- (void)didBecomeActive {
[self setupGL];
}
- (void)willResignActive {
[self teardownGL];
}
@end

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 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.
*/
#import "RTCIceCandidate.h"
#include "talk/app/webrtc/jsep.h"
#include "webrtc/base/scoped_ptr.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceCandidate ()
/**
* The native IceCandidateInterface representation of this RTCIceCandidate
* object. This is needed to pass to the underlying C++ APIs.
*/
@property(nonatomic, readonly)
rtc::scoped_ptr<webrtc::IceCandidateInterface> nativeCandidate;
/**
* Initialize an RTCIceCandidate from a native IceCandidateInterface. No
* ownership is taken of the native candidate.
*/
- (instancetype)initWithNativeCandidate:
(webrtc::IceCandidateInterface *)candidate;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,44 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceCandidate : NSObject
/**
* If present, the identifier of the "media stream identification" for the media
* component this candidate is associated with.
*/
@property(nonatomic, readonly, nullable) NSString *sdpMid;
/**
* The index (starting at zero) of the media description this candidate is
* associated with in the SDP.
*/
@property(nonatomic, readonly) NSInteger sdpMLineIndex;
/** The SDP string for this candidate. */
@property(nonatomic, readonly) NSString *sdp;
- (instancetype)init NS_UNAVAILABLE;
/**
* Initialize an RTCIceCandidate from SDP.
*/
- (instancetype)initWithSdp:(NSString *)sdp
sdpMLineIndex:(NSInteger)sdpMLineIndex
sdpMid:(nullable NSString *)sdpMid
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,70 @@
/*
* Copyright 2015 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.
*/
#import "RTCIceCandidate.h"
#import "webrtc/api/objc/RTCIceCandidate+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
#import "webrtc/base/objc/RTCLogging.h"
@implementation RTCIceCandidate
@synthesize sdpMid = _sdpMid;
@synthesize sdpMLineIndex = _sdpMLineIndex;
@synthesize sdp = _sdp;
- (instancetype)initWithSdp:(NSString *)sdp
sdpMLineIndex:(NSInteger)sdpMLineIndex
sdpMid:(NSString *)sdpMid {
NSParameterAssert(sdp.length);
if (self = [super init]) {
_sdpMid = [sdpMid copy];
_sdpMLineIndex = sdpMLineIndex;
_sdp = [sdp copy];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCIceCandidate:\n%@\n%ld\n%@",
_sdpMid,
(long)_sdpMLineIndex,
_sdp];
}
#pragma mark - Private
- (instancetype)initWithNativeCandidate:
(webrtc::IceCandidateInterface *)candidate {
NSParameterAssert(candidate);
std::string sdp;
candidate->ToString(&sdp);
return [self initWithSdp:[NSString stringForStdString:sdp]
sdpMLineIndex:candidate->sdp_mline_index()
sdpMid:[NSString stringForStdString:candidate->sdp_mid()]];
}
- (rtc::scoped_ptr<webrtc::IceCandidateInterface>)nativeCandidate {
webrtc::SdpParseError error;
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
_sdpMid.stdString, _sdpMLineIndex, _sdp.stdString, &error);
if (!candidate) {
RTCLog(@"Failed to create ICE candidate: %s\nline: %s",
error.description.c_str(),
error.line.c_str());
}
return rtc::scoped_ptr<webrtc::IceCandidateInterface>(candidate);
}
@end

View file

@ -0,0 +1,28 @@
/*
* Copyright 2015 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.
*/
#import "RTCIceServer.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceServer ()
/**
* IceServer struct representation of this RTCIceServer object's data.
* This is needed to pass to the underlying C++ APIs.
*/
@property(nonatomic, readonly)
webrtc::PeerConnectionInterface::IceServer iceServer;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,42 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceServer : NSObject
/** URI(s) for this server represented as NSStrings. */
@property(nonatomic, copy, readonly) NSArray<NSString *> *urlStrings;
/** Username to use if this RTCIceServer object is a TURN server. */
@property(nonatomic, copy, readonly, nullable) NSString *username;
/** Credential to use if this RTCIceServer object is a TURN server. */
@property(nonatomic, copy, readonly, nullable) NSString *credential;
- (instancetype)init NS_UNAVAILABLE;
/** Convenience initializer for a server with no authentication (e.g. STUN). */
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings;
/**
* Initialize an RTCIceServer with its associated URLs, optional username,
* optional credential, and credentialType.
*/
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(nullable NSString *)username
credential:(nullable NSString *)credential
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,64 @@
/*
* Copyright 2015 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.
*/
#import "RTCIceServer.h"
#import "webrtc/api/objc/RTCIceServer+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@implementation RTCIceServer
@synthesize urlStrings = _urlStrings;
@synthesize username = _username;
@synthesize credential = _credential;
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings {
NSParameterAssert(urlStrings.count);
return [self initWithURLStrings:urlStrings
username:nil
credential:nil];
}
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(NSString *)username
credential:(NSString *)credential {
NSParameterAssert(urlStrings.count);
if (self = [super init]) {
_urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES];
_username = [username copy];
_credential = [credential copy];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@",
_urlStrings,
_username,
_credential];
}
#pragma mark - Private
- (webrtc::PeerConnectionInterface::IceServer)iceServer {
__block webrtc::PeerConnectionInterface::IceServer iceServer;
iceServer.username = [NSString stdStringForString:_username];
iceServer.password = [NSString stdStringForString:_credential];
[_urlStrings enumerateObjectsUsingBlock:^(NSString *url,
NSUInteger idx,
BOOL *stop) {
iceServer.urls.push_back(url.stdString);
}];
return iceServer;
}
@end

View file

@ -0,0 +1,53 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaConstraints.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "webrtc/base/scoped_ptr.h"
namespace webrtc {
class MediaConstraints : public MediaConstraintsInterface {
public:
virtual ~MediaConstraints();
MediaConstraints();
MediaConstraints(
const MediaConstraintsInterface::Constraints& mandatory,
const MediaConstraintsInterface::Constraints& optional);
virtual const Constraints& GetMandatory() const;
virtual const Constraints& GetOptional() const;
private:
MediaConstraintsInterface::Constraints mandatory_;
MediaConstraintsInterface::Constraints optional_;
};
} // namespace webrtc
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaConstraints ()
/**
* A MediaConstraints representation of this RTCMediaConstraints object. This is
* needed to pass to the underlying C++ APIs.
*/
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints;
/** Return a native Constraints object representing these constraints */
+ (webrtc::MediaConstraintsInterface::Constraints)
nativeConstraintsForConstraints:
(NSDictionary<NSString *, NSString *> *)constraints;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,28 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaConstraints : NSObject
- (instancetype)init NS_UNAVAILABLE;
/** Initialize with mandatory and/or optional constraints. */
- (instancetype)initWithMandatoryConstraints:
(nullable NSDictionary<NSString *, NSString *> *)mandatory
optionalConstraints:
(nullable NSDictionary<NSString *, NSString *> *)optional
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,92 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaConstraints.h"
#import "webrtc/api/objc/RTCMediaConstraints+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
namespace webrtc {
MediaConstraints::~MediaConstraints() {}
MediaConstraints::MediaConstraints() {}
MediaConstraints::MediaConstraints(
const MediaConstraintsInterface::Constraints& mandatory,
const MediaConstraintsInterface::Constraints& optional)
: mandatory_(mandatory), optional_(optional) {}
const MediaConstraintsInterface::Constraints&
MediaConstraints::GetMandatory() const {
return mandatory_;
}
const MediaConstraintsInterface::Constraints&
MediaConstraints::GetOptional() const {
return optional_;
}
} // namespace webrtc
@implementation RTCMediaConstraints {
NSDictionary<NSString *, NSString *> *_mandatory;
NSDictionary<NSString *, NSString *> *_optional;
}
- (instancetype)initWithMandatoryConstraints:
(NSDictionary<NSString *, NSString *> *)mandatory
optionalConstraints:
(NSDictionary<NSString *, NSString *> *)optional {
if (self = [super init]) {
_mandatory = [[NSDictionary alloc] initWithDictionary:mandatory
copyItems:YES];
_optional = [[NSDictionary alloc] initWithDictionary:optional
copyItems:YES];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCMediaConstraints:\n%@\n%@",
_mandatory,
_optional];
}
#pragma mark - Private
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints {
webrtc::MediaConstraintsInterface::Constraints mandatory =
[[self class] nativeConstraintsForConstraints:_mandatory];
webrtc::MediaConstraintsInterface::Constraints optional =
[[self class] nativeConstraintsForConstraints:_optional];
webrtc::MediaConstraints *nativeConstraints =
new webrtc::MediaConstraints(mandatory, optional);
return rtc::scoped_ptr<webrtc::MediaConstraints>(nativeConstraints);
}
+ (webrtc::MediaConstraintsInterface::Constraints)
nativeConstraintsForConstraints:
(NSDictionary<NSString *, NSString *> *)constraints {
webrtc::MediaConstraintsInterface::Constraints nativeConstraints;
for (NSString *key in constraints) {
NSAssert([key isKindOfClass:[NSString class]],
@"%@ is not an NSString.", key);
NSAssert([constraints[key] isKindOfClass:[NSString class]],
@"%@ is not an NSString.", constraints[key]);
nativeConstraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
key.stdString, constraints[key].stdString));
}
return nativeConstraints;
}
@end

View file

@ -0,0 +1,41 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaSource.h"
#include "talk/app/webrtc/mediastreaminterface.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaSource ()
/**
* The MediaSourceInterface object passed to this RTCMediaSource during
* construction.
*/
@property(nonatomic, readonly)
rtc::scoped_refptr<webrtc::MediaSourceInterface> nativeMediaSource;
/** Initialize an RTCMediaSource from a native MediaSourceInterface. */
- (instancetype)initWithNativeMediaSource:
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
NS_DESIGNATED_INITIALIZER;
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
(RTCSourceState)state;
+ (RTCSourceState)sourceStateForNativeState:
(webrtc::MediaSourceInterface::SourceState)nativeState;
+ (NSString *)stringForState:(RTCSourceState)state;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,31 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, RTCSourceState) {
RTCSourceStateInitializing,
RTCSourceStateLive,
RTCSourceStateEnded,
RTCSourceStateMuted,
};
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaSource : NSObject
/** The current state of the RTCMediaSource. */
@property(nonatomic, readonly) RTCSourceState state;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,84 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaSource.h"
#import "webrtc/api/objc/RTCMediaSource+Private.h"
@implementation RTCMediaSource {
rtc::scoped_refptr<webrtc::MediaSourceInterface> _nativeMediaSource;
}
- (RTCSourceState)state {
return [[self class] sourceStateForNativeState:_nativeMediaSource->state()];
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCMediaSource:\n%@",
[[self class] stringForState:self.state]];
}
#pragma mark - Private
- (rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
return _nativeMediaSource;
}
- (instancetype)initWithNativeMediaSource:
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
NSParameterAssert(nativeMediaSource);
if (self = [super init]) {
_nativeMediaSource = nativeMediaSource;
}
return self;
}
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
(RTCSourceState)state {
switch (state) {
case RTCSourceStateInitializing:
return webrtc::MediaSourceInterface::kInitializing;
case RTCSourceStateLive:
return webrtc::MediaSourceInterface::kLive;
case RTCSourceStateEnded:
return webrtc::MediaSourceInterface::kEnded;
case RTCSourceStateMuted:
return webrtc::MediaSourceInterface::kMuted;
}
}
+ (RTCSourceState)sourceStateForNativeState:
(webrtc::MediaSourceInterface::SourceState)nativeState {
switch (nativeState) {
case webrtc::MediaSourceInterface::kInitializing:
return RTCSourceStateInitializing;
case webrtc::MediaSourceInterface::kLive:
return RTCSourceStateLive;
case webrtc::MediaSourceInterface::kEnded:
return RTCSourceStateEnded;
case webrtc::MediaSourceInterface::kMuted:
return RTCSourceStateMuted;
}
}
+ (NSString *)stringForState:(RTCSourceState)state {
switch (state) {
case RTCSourceStateInitializing:
return @"Initializing";
case RTCSourceStateLive:
return @"Live";
case RTCSourceStateEnded:
return @"Ended";
case RTCSourceStateMuted:
return @"Muted";
}
}
@end

View file

@ -0,0 +1,45 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaStreamTrack.h"
#include "talk/app/webrtc/mediastreaminterface.h"
#include "webrtc/base/scoped_ptr.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaStreamTrack ()
/**
* The native MediaStreamTrackInterface representation of this
* RTCMediaStreamTrack object. This is needed to pass to the underlying C++
* APIs.
*/
@property(nonatomic, readonly)
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack;
/**
* Initialize an RTCMediaStreamTrack from a native MediaStreamTrackInterface.
*/
- (instancetype)initWithNativeTrack:
(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
NS_DESIGNATED_INITIALIZER;
+ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
(RTCMediaStreamTrackState)state;
+ (RTCMediaStreamTrackState)trackStateForNativeState:
(webrtc::MediaStreamTrackInterface::TrackState)nativeState;
+ (NSString *)stringForState:(RTCMediaStreamTrackState)state;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,47 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
/**
* Represents the state of the track. This exposes the same states in C++,
* which include two more states than are in the W3C spec.
*/
typedef NS_ENUM(NSInteger, RTCMediaStreamTrackState) {
RTCMediaStreamTrackStateInitializing,
RTCMediaStreamTrackStateLive,
RTCMediaStreamTrackStateEnded,
RTCMediaStreamTrackStateFailed,
};
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaStreamTrack : NSObject
/**
* The kind of track. For example, "audio" if this track represents an audio
* track and "video" if this track represents a video track.
*/
@property(nonatomic, readonly) NSString *kind;
/** An identifier string. */
@property(nonatomic, readonly) NSString *trackId;
/** The enabled state of the track. */
@property(nonatomic) BOOL isEnabled;
/** The state of the track. */
@property(nonatomic, readonly) RTCMediaStreamTrackState readyState;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,105 @@
/*
* Copyright 2015 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.
*/
#import "RTCMediaStreamTrack.h"
#import "webrtc/api/objc/RTCMediaStreamTrack+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@implementation RTCMediaStreamTrack {
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> _nativeTrack;
}
- (NSString *)kind {
return [NSString stringForStdString:_nativeTrack->kind()];
}
- (NSString *)trackId {
return [NSString stringForStdString:_nativeTrack->id()];
}
- (BOOL)isEnabled {
return _nativeTrack->enabled();
}
- (void)setIsEnabled:(BOOL)isEnabled {
_nativeTrack->set_enabled(isEnabled);
}
- (RTCMediaStreamTrackState)readyState {
return [[self class] trackStateForNativeState:_nativeTrack->state()];
}
- (NSString *)description {
NSString *readyState = [[self class] stringForState:self.readyState];
return [NSString stringWithFormat:@"RTCMediaStreamTrack:\n%@\n%@\n%@\n%@",
self.kind,
self.trackId,
self.isEnabled ? @"enabled" : @"disabled",
readyState];
}
#pragma mark - Private
- (rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
return _nativeTrack;
}
- (instancetype)initWithNativeTrack:
(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack {
NSParameterAssert(nativeTrack);
if (self = [super init]) {
_nativeTrack = nativeTrack;
}
return self;
}
+ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
(RTCMediaStreamTrackState)state {
switch (state) {
case RTCMediaStreamTrackStateInitializing:
return webrtc::MediaStreamTrackInterface::kInitializing;
case RTCMediaStreamTrackStateLive:
return webrtc::MediaStreamTrackInterface::kLive;
case RTCMediaStreamTrackStateEnded:
return webrtc::MediaStreamTrackInterface::kEnded;
case RTCMediaStreamTrackStateFailed:
return webrtc::MediaStreamTrackInterface::kFailed;
}
}
+ (RTCMediaStreamTrackState)trackStateForNativeState:
(webrtc::MediaStreamTrackInterface::TrackState)nativeState {
switch (nativeState) {
case webrtc::MediaStreamTrackInterface::kInitializing:
return RTCMediaStreamTrackStateInitializing;
case webrtc::MediaStreamTrackInterface::kLive:
return RTCMediaStreamTrackStateLive;
case webrtc::MediaStreamTrackInterface::kEnded:
return RTCMediaStreamTrackStateEnded;
case webrtc::MediaStreamTrackInterface::kFailed:
return RTCMediaStreamTrackStateFailed;
}
}
+ (NSString *)stringForState:(RTCMediaStreamTrackState)state {
switch (state) {
case RTCMediaStreamTrackStateInitializing:
return @"Initializing";
case RTCMediaStreamTrackStateLive:
return @"Live";
case RTCMediaStreamTrackStateEnded:
return @"Ended";
case RTCMediaStreamTrackStateFailed:
return @"Failed";
}
}
@end

View file

@ -0,0 +1,34 @@
/*
* Copyright 2015 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.
*/
#if TARGET_OS_IPHONE
#error "This file targets OSX."
#endif
#import <AppKit/NSOpenGLView.h>
#import "RTCVideoRenderer.h"
NS_ASSUME_NONNULL_BEGIN
@class RTCNSGLVideoView;
@protocol RTCNSGLVideoViewDelegate
- (void)videoView:(RTCNSGLVideoView *)videoView didChangeVideoSize:(CGSize)size;
@end
@interface RTCNSGLVideoView : NSOpenGLView <RTCVideoRenderer>
@property(nonatomic, weak) id<RTCNSGLVideoViewDelegate> delegate;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,141 @@
/*
* Copyright 2015 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.
*/
#import "RTCNSGLVideoView.h"
#import <CoreVideo/CVDisplayLink.h>
#import <OpenGL/gl3.h>
#import "RTCVideoFrame.h"
#import "RTCOpenGLVideoRenderer.h"
@interface RTCNSGLVideoView ()
// |videoFrame| is set when we receive a frame from a worker thread and is read
// from the display link callback so atomicity is required.
@property(atomic, strong) RTCVideoFrame *videoFrame;
@property(atomic, strong) RTCOpenGLVideoRenderer *glRenderer;
- (void)drawFrame;
@end
static CVReturn OnDisplayLinkFired(CVDisplayLinkRef displayLink,
const CVTimeStamp *now,
const CVTimeStamp *outputTime,
CVOptionFlags flagsIn,
CVOptionFlags *flagsOut,
void *displayLinkContext) {
RTCNSGLVideoView *view = (__bridge RTCNSGLVideoView *)displayLinkContext;
[view drawFrame];
return kCVReturnSuccess;
}
@implementation RTCNSGLVideoView {
CVDisplayLinkRef _displayLink;
}
@synthesize delegate = _delegate;
@synthesize videoFrame = _videoFrame;
@synthesize glRenderer = _glRenderer;
- (void)dealloc {
[self teardownDisplayLink];
}
- (void)drawRect:(NSRect)rect {
[self drawFrame];
}
- (void)reshape {
[super reshape];
NSRect frame = [self frame];
CGLLockContext([[self openGLContext] CGLContextObj]);
glViewport(0, 0, frame.size.width, frame.size.height);
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
- (void)lockFocus {
NSOpenGLContext *context = [self openGLContext];
[super lockFocus];
if ([context view] != self) {
[context setView:self];
}
[context makeCurrentContext];
}
- (void)prepareOpenGL {
[super prepareOpenGL];
if (!self.glRenderer) {
self.glRenderer =
[[RTCOpenGLVideoRenderer alloc] initWithContext:[self openGLContext]];
}
[self.glRenderer setupGL];
[self setupDisplayLink];
}
- (void)clearGLContext {
[self.glRenderer teardownGL];
self.glRenderer = nil;
[super clearGLContext];
}
#pragma mark - RTCVideoRenderer
// These methods may be called on non-main thread.
- (void)setSize:(CGSize)size {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate videoView:self didChangeVideoSize:size];
});
}
- (void)renderFrame:(RTCVideoFrame *)frame {
self.videoFrame = frame;
}
#pragma mark - Private
- (void)drawFrame {
RTCVideoFrame *videoFrame = self.videoFrame;
if (self.glRenderer.lastDrawnFrame != videoFrame) {
// This method may be called from CVDisplayLink callback which isn't on the
// main thread so we have to lock the GL context before drawing.
CGLLockContext([[self openGLContext] CGLContextObj]);
[self.glRenderer drawFrame:videoFrame];
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
}
- (void)setupDisplayLink {
if (_displayLink) {
return;
}
// Synchronize buffer swaps with vertical refresh rate.
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
// Create display link.
CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink);
CVDisplayLinkSetOutputCallback(_displayLink,
&OnDisplayLinkFired,
(__bridge void *)self);
// Set the display link for the current renderer.
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(
_displayLink, cglContext, cglPixelFormat);
CVDisplayLinkStart(_displayLink);
}
- (void)teardownDisplayLink {
if (!_displayLink) {
return;
}
CVDisplayLinkRelease(_displayLink);
_displayLink = NULL;
}
@end

View file

@ -0,0 +1,58 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <GLKit/GLKit.h>
#else
#import <AppKit/NSOpenGL.h>
#endif
NS_ASSUME_NONNULL_BEGIN
@class RTCVideoFrame;
// RTCOpenGLVideoRenderer issues appropriate OpenGL commands to draw a frame to
// the currently bound framebuffer. Supports OpenGL 3.2 and OpenGLES 2.0. OpenGL
// framebuffer creation and management should be handled elsewhere using the
// same context used to initialize this class.
@interface RTCOpenGLVideoRenderer : NSObject
// The last successfully drawn frame. Used to avoid drawing frames unnecessarily
// hence saving battery life by reducing load.
@property(nonatomic, readonly) RTCVideoFrame *lastDrawnFrame;
#if TARGET_OS_IPHONE
- (instancetype)initWithContext:(EAGLContext *)context
NS_DESIGNATED_INITIALIZER;
#else
- (instancetype)initWithContext:(NSOpenGLContext *)context
NS_DESIGNATED_INITIALIZER;
#endif
// Draws |frame| onto the currently bound OpenGL framebuffer. |setupGL| must be
// called before this function will succeed.
- (BOOL)drawFrame:(RTCVideoFrame *)frame;
// The following methods are used to manage OpenGL resources. On iOS
// applications should release resources when placed in background for use in
// the foreground application. In fact, attempting to call OpenGLES commands
// while in background will result in application termination.
// Sets up the OpenGL state needed for rendering.
- (void)setupGL;
// Tears down the OpenGL state created by |setupGL|.
- (void)teardownGL;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,485 @@
/*
* Copyright 2015 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.
*/
#import "RTCOpenGLVideoRenderer.h"
#include <string.h>
#include "webrtc/base/scoped_ptr.h"
#if TARGET_OS_IPHONE
#import <OpenGLES/ES3/gl.h>
#else
#import <OpenGL/gl3.h>
#endif
#import "RTCVideoFrame.h"
// TODO(tkchin): check and log openGL errors. Methods here return BOOLs in
// anticipation of that happening in the future.
#if TARGET_OS_IPHONE
#define RTC_PIXEL_FORMAT GL_LUMINANCE
#define SHADER_VERSION
#define VERTEX_SHADER_IN "attribute"
#define VERTEX_SHADER_OUT "varying"
#define FRAGMENT_SHADER_IN "varying"
#define FRAGMENT_SHADER_OUT
#define FRAGMENT_SHADER_COLOR "gl_FragColor"
#define FRAGMENT_SHADER_TEXTURE "texture2D"
#else
#define RTC_PIXEL_FORMAT GL_RED
#define SHADER_VERSION "#version 150\n"
#define VERTEX_SHADER_IN "in"
#define VERTEX_SHADER_OUT "out"
#define FRAGMENT_SHADER_IN "in"
#define FRAGMENT_SHADER_OUT "out vec4 fragColor;\n"
#define FRAGMENT_SHADER_COLOR "fragColor"
#define FRAGMENT_SHADER_TEXTURE "texture"
#endif
// Vertex shader doesn't do anything except pass coordinates through.
static const char kVertexShaderSource[] =
SHADER_VERSION
VERTEX_SHADER_IN " vec2 position;\n"
VERTEX_SHADER_IN " vec2 texcoord;\n"
VERTEX_SHADER_OUT " vec2 v_texcoord;\n"
"void main() {\n"
" gl_Position = vec4(position.x, position.y, 0.0, 1.0);\n"
" v_texcoord = texcoord;\n"
"}\n";
// Fragment shader converts YUV values from input textures into a final RGB
// pixel. The conversion formula is from http://www.fourcc.org/fccyvrgb.php.
static const char kFragmentShaderSource[] =
SHADER_VERSION
"precision highp float;"
FRAGMENT_SHADER_IN " vec2 v_texcoord;\n"
"uniform lowp sampler2D s_textureY;\n"
"uniform lowp sampler2D s_textureU;\n"
"uniform lowp sampler2D s_textureV;\n"
FRAGMENT_SHADER_OUT
"void main() {\n"
" float y, u, v, r, g, b;\n"
" y = " FRAGMENT_SHADER_TEXTURE "(s_textureY, v_texcoord).r;\n"
" u = " FRAGMENT_SHADER_TEXTURE "(s_textureU, v_texcoord).r;\n"
" v = " FRAGMENT_SHADER_TEXTURE "(s_textureV, v_texcoord).r;\n"
" u = u - 0.5;\n"
" v = v - 0.5;\n"
" r = y + 1.403 * v;\n"
" g = y - 0.344 * u - 0.714 * v;\n"
" b = y + 1.770 * u;\n"
" " FRAGMENT_SHADER_COLOR " = vec4(r, g, b, 1.0);\n"
" }\n";
// Compiles a shader of the given |type| with GLSL source |source| and returns
// the shader handle or 0 on error.
GLuint CreateShader(GLenum type, const GLchar *source) {
GLuint shader = glCreateShader(type);
if (!shader) {
return 0;
}
glShaderSource(shader, 1, &source, NULL);
glCompileShader(shader);
GLint compileStatus = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == GL_FALSE) {
glDeleteShader(shader);
shader = 0;
}
return shader;
}
// Links a shader program with the given vertex and fragment shaders and
// returns the program handle or 0 on error.
GLuint CreateProgram(GLuint vertexShader, GLuint fragmentShader) {
if (vertexShader == 0 || fragmentShader == 0) {
return 0;
}
GLuint program = glCreateProgram();
if (!program) {
return 0;
}
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
GLint linkStatus = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
glDeleteProgram(program);
program = 0;
}
return program;
}
// When modelview and projection matrices are identity (default) the world is
// contained in the square around origin with unit size 2. Drawing to these
// coordinates is equivalent to drawing to the entire screen. The texture is
// stretched over that square using texture coordinates (u, v) that range
// from (0, 0) to (1, 1) inclusive. Texture coordinates are flipped vertically
// here because the incoming frame has origin in upper left hand corner but
// OpenGL expects origin in bottom left corner.
const GLfloat gVertices[] = {
// X, Y, U, V.
-1, -1, 0, 1, // Bottom left.
1, -1, 1, 1, // Bottom right.
1, 1, 1, 0, // Top right.
-1, 1, 0, 0, // Top left.
};
// |kNumTextures| must not exceed 8, which is the limit in OpenGLES2. Two sets
// of 3 textures are used here, one for each of the Y, U and V planes. Having
// two sets alleviates CPU blockage in the event that the GPU is asked to render
// to a texture that is already in use.
static const GLsizei kNumTextureSets = 2;
static const GLsizei kNumTextures = 3 * kNumTextureSets;
@implementation RTCOpenGLVideoRenderer {
#if TARGET_OS_IPHONE
EAGLContext *_context;
#else
NSOpenGLContext *_context;
#endif
BOOL _isInitialized;
NSUInteger _currentTextureSet;
// Handles for OpenGL constructs.
GLuint _textures[kNumTextures];
GLuint _program;
#if !TARGET_OS_IPHONE
GLuint _vertexArray;
#endif
GLuint _vertexBuffer;
GLint _position;
GLint _texcoord;
GLint _ySampler;
GLint _uSampler;
GLint _vSampler;
// Used to create a non-padded plane for GPU upload when we receive padded
// frames.
rtc::scoped_ptr<uint8_t[]> _planeBuffer;
}
@synthesize lastDrawnFrame = _lastDrawnFrame;
+ (void)initialize {
// Disable dithering for performance.
glDisable(GL_DITHER);
}
#if TARGET_OS_IPHONE
- (instancetype)initWithContext:(EAGLContext *)context {
#else
- (instancetype)initWithContext:(NSOpenGLContext *)context {
#endif
NSAssert(context != nil, @"context cannot be nil");
if (self = [super init]) {
_context = context;
}
return self;
}
- (BOOL)drawFrame:(RTCVideoFrame *)frame {
if (!_isInitialized) {
return NO;
}
if (_lastDrawnFrame == frame) {
return NO;
}
[self ensureGLContext];
glClear(GL_COLOR_BUFFER_BIT);
if (frame) {
if (![self updateTextureSizesForFrame:frame] ||
![self updateTextureDataForFrame:frame]) {
return NO;
}
#if !TARGET_OS_IPHONE
glBindVertexArray(_vertexArray);
#endif
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
#if !TARGET_OS_IPHONE
[_context flushBuffer];
#endif
_lastDrawnFrame = frame;
return YES;
}
- (void)setupGL {
if (_isInitialized) {
return;
}
[self ensureGLContext];
if (![self setupProgram]) {
return;
}
if (![self setupTextures]) {
return;
}
if (![self setupVertices]) {
return;
}
glUseProgram(_program);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
_isInitialized = YES;
}
- (void)teardownGL {
if (!_isInitialized) {
return;
}
[self ensureGLContext];
glDeleteProgram(_program);
_program = 0;
glDeleteTextures(kNumTextures, _textures);
glDeleteBuffers(1, &_vertexBuffer);
_vertexBuffer = 0;
#if !TARGET_OS_IPHONE
glDeleteVertexArrays(1, &_vertexArray);
#endif
_isInitialized = NO;
}
#pragma mark - Private
- (void)ensureGLContext {
NSAssert(_context, @"context shouldn't be nil");
#if TARGET_OS_IPHONE
if ([EAGLContext currentContext] != _context) {
[EAGLContext setCurrentContext:_context];
}
#else
if ([NSOpenGLContext currentContext] != _context) {
[_context makeCurrentContext];
}
#endif
}
- (BOOL)setupProgram {
NSAssert(!_program, @"program already set up");
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, kVertexShaderSource);
NSAssert(vertexShader, @"failed to create vertex shader");
GLuint fragmentShader =
CreateShader(GL_FRAGMENT_SHADER, kFragmentShaderSource);
NSAssert(fragmentShader, @"failed to create fragment shader");
_program = CreateProgram(vertexShader, fragmentShader);
// Shaders are created only to generate program.
if (vertexShader) {
glDeleteShader(vertexShader);
}
if (fragmentShader) {
glDeleteShader(fragmentShader);
}
if (!_program) {
return NO;
}
_position = glGetAttribLocation(_program, "position");
_texcoord = glGetAttribLocation(_program, "texcoord");
_ySampler = glGetUniformLocation(_program, "s_textureY");
_uSampler = glGetUniformLocation(_program, "s_textureU");
_vSampler = glGetUniformLocation(_program, "s_textureV");
if (_position < 0 || _texcoord < 0 || _ySampler < 0 || _uSampler < 0 ||
_vSampler < 0) {
return NO;
}
return YES;
}
- (BOOL)setupTextures {
glGenTextures(kNumTextures, _textures);
// Set parameters for each of the textures we created.
for (GLsizei i = 0; i < kNumTextures; i++) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, _textures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
return YES;
}
- (BOOL)updateTextureSizesForFrame:(RTCVideoFrame *)frame {
if (frame.height == _lastDrawnFrame.height &&
frame.width == _lastDrawnFrame.width &&
frame.chromaWidth == _lastDrawnFrame.chromaWidth &&
frame.chromaHeight == _lastDrawnFrame.chromaHeight) {
return YES;
}
GLsizei lumaWidth = frame.width;
GLsizei lumaHeight = frame.height;
GLsizei chromaWidth = frame.chromaWidth;
GLsizei chromaHeight = frame.chromaHeight;
for (GLint i = 0; i < kNumTextureSets; i++) {
glActiveTexture(GL_TEXTURE0 + i * 3);
glTexImage2D(GL_TEXTURE_2D,
0,
RTC_PIXEL_FORMAT,
lumaWidth,
lumaHeight,
0,
RTC_PIXEL_FORMAT,
GL_UNSIGNED_BYTE,
0);
glActiveTexture(GL_TEXTURE0 + i * 3 + 1);
glTexImage2D(GL_TEXTURE_2D,
0,
RTC_PIXEL_FORMAT,
chromaWidth,
chromaHeight,
0,
RTC_PIXEL_FORMAT,
GL_UNSIGNED_BYTE,
0);
glActiveTexture(GL_TEXTURE0 + i * 3 + 2);
glTexImage2D(GL_TEXTURE_2D,
0,
RTC_PIXEL_FORMAT,
chromaWidth,
chromaHeight,
0,
RTC_PIXEL_FORMAT,
GL_UNSIGNED_BYTE,
0);
}
if ((NSUInteger)frame.yPitch != frame.width ||
(NSUInteger)frame.uPitch != frame.chromaWidth ||
(NSUInteger)frame.vPitch != frame.chromaWidth) {
_planeBuffer.reset(new uint8_t[frame.width * frame.height]);
} else {
_planeBuffer.reset();
}
return YES;
}
- (void)uploadPlane:(const uint8_t *)plane
sampler:(GLint)sampler
offset:(NSUInteger)offset
width:(size_t)width
height:(size_t)height
stride:(int32_t)stride {
glActiveTexture(GL_TEXTURE0 + offset);
// When setting texture sampler uniforms, the texture index is used not
// the texture handle.
glUniform1i(sampler, offset);
#if TARGET_OS_IPHONE
BOOL hasUnpackRowLength = _context.API == kEAGLRenderingAPIOpenGLES3;
#else
BOOL hasUnpackRowLength = YES;
#endif
const uint8_t *uploadPlane = plane;
if ((size_t)stride != width) {
if (hasUnpackRowLength) {
// GLES3 allows us to specify stride.
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
glTexImage2D(GL_TEXTURE_2D,
0,
RTC_PIXEL_FORMAT,
width,
height,
0,
RTC_PIXEL_FORMAT,
GL_UNSIGNED_BYTE,
uploadPlane);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
return;
} else {
// Make an unpadded copy and upload that instead. Quick profiling showed
// that this is faster than uploading row by row using glTexSubImage2D.
uint8_t *unpaddedPlane = _planeBuffer.get();
for (size_t y = 0; y < height; ++y) {
memcpy(unpaddedPlane + y * width, plane + y * stride, width);
}
uploadPlane = unpaddedPlane;
}
}
glTexImage2D(GL_TEXTURE_2D,
0,
RTC_PIXEL_FORMAT,
width,
height,
0,
RTC_PIXEL_FORMAT,
GL_UNSIGNED_BYTE,
uploadPlane);
}
- (BOOL)updateTextureDataForFrame:(RTCVideoFrame *)frame {
NSUInteger textureOffset = _currentTextureSet * 3;
NSAssert(textureOffset + 3 <= kNumTextures, @"invalid offset");
[self uploadPlane:frame.yPlane
sampler:_ySampler
offset:textureOffset
width:frame.width
height:frame.height
stride:frame.yPitch];
[self uploadPlane:frame.uPlane
sampler:_uSampler
offset:textureOffset + 1
width:frame.chromaWidth
height:frame.chromaHeight
stride:frame.uPitch];
[self uploadPlane:frame.vPlane
sampler:_vSampler
offset:textureOffset + 2
width:frame.chromaWidth
height:frame.chromaHeight
stride:frame.vPitch];
_currentTextureSet = (_currentTextureSet + 1) % kNumTextureSets;
return YES;
}
- (BOOL)setupVertices {
#if !TARGET_OS_IPHONE
NSAssert(!_vertexArray, @"vertex array already set up");
glGenVertexArrays(1, &_vertexArray);
if (!_vertexArray) {
return NO;
}
glBindVertexArray(_vertexArray);
#endif
NSAssert(!_vertexBuffer, @"vertex buffer already set up");
glGenBuffers(1, &_vertexBuffer);
if (!_vertexBuffer) {
#if !TARGET_OS_IPHONE
glDeleteVertexArrays(1, &_vertexArray);
_vertexArray = 0;
#endif
return NO;
}
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(gVertices), gVertices, GL_DYNAMIC_DRAW);
// Read position attribute from |gVertices| with size of 2 and stride of 4
// beginning at the start of the array. The last argument indicates offset
// of data within |gVertices| as supplied to the vertex buffer.
glVertexAttribPointer(
_position, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void *)0);
glEnableVertexAttribArray(_position);
// Read texcoord attribute from |gVertices| with size of 2 and stride of 4
// beginning at the first texcoord in the array. The last argument indicates
// offset of data within |gVertices| as supplied to the vertex buffer.
glVertexAttribPointer(_texcoord,
2,
GL_FLOAT,
GL_FALSE,
4 * sizeof(GLfloat),
(void *)(2 * sizeof(GLfloat)));
glEnableVertexAttribArray(_texcoord);
return YES;
}
@end

View file

@ -0,0 +1,41 @@
/*
* Copyright 2015 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.
*/
#import "RTCSessionDescription.h"
#include "talk/app/webrtc/jsep.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCSessionDescription ()
/**
* The native SessionDescriptionInterface representation of this
* RTCSessionDescription object. This is needed to pass to the underlying C++
* APIs.
*/
@property(nonatomic, readonly)
webrtc::SessionDescriptionInterface *nativeDescription;
/**
* Initialize an RTCSessionDescription from a native
* SessionDescriptionInterface. No ownership is taken of the native session
* description.
*/
- (instancetype)initWithNativeDescription:
(webrtc::SessionDescriptionInterface *)nativeDescription;
+ (std::string)stringForType:(RTCSdpType)type;
+ (RTCSdpType)typeForString:(const std::string &)string;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,41 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
/**
* Represents the session description type. This exposes the same types that are
* in C++, which doesn't include the rollback type that is in the W3C spec.
*/
typedef NS_ENUM(NSInteger, RTCSdpType) {
RTCSdpTypeOffer,
RTCSdpTypePrAnswer,
RTCSdpTypeAnswer,
};
NS_ASSUME_NONNULL_BEGIN
@interface RTCSessionDescription : NSObject
/** The type of session description. */
@property(nonatomic, readonly) RTCSdpType type;
/** The SDP string representation of this session description. */
@property(nonatomic, readonly) NSString *sdp;
- (instancetype)init NS_UNAVAILABLE;
/** Initialize a session description with a type and SDP string. */
- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,92 @@
/*
* Copyright 2015 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.
*/
#import "RTCSessionDescription.h"
#include "webrtc/base/checks.h"
#import "webrtc/api/objc/RTCSessionDescription+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
#import "webrtc/base/objc/RTCLogging.h"
@implementation RTCSessionDescription
@synthesize type = _type;
@synthesize sdp = _sdp;
- (instancetype)initWithType:(RTCSdpType)type sdp:(NSString *)sdp {
NSParameterAssert(sdp.length);
if (self = [super init]) {
_type = type;
_sdp = [sdp copy];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCSessionDescription:\n%s\n%@",
[[self class] stringForType:_type].c_str(),
_sdp];
}
#pragma mark - Private
- (webrtc::SessionDescriptionInterface *)nativeDescription {
webrtc::SdpParseError error;
webrtc::SessionDescriptionInterface *description =
webrtc::CreateSessionDescription([[self class] stringForType:_type],
_sdp.stdString,
&error);
if (!description) {
RTCLogError(@"Failed to create session description: %s\nline: %s",
error.description.c_str(),
error.line.c_str());
}
return description;
}
- (instancetype)initWithNativeDescription:
(webrtc::SessionDescriptionInterface *)nativeDescription {
NSParameterAssert(nativeDescription);
std::string sdp;
nativeDescription->ToString(&sdp);
RTCSdpType type = [[self class] typeForString:nativeDescription->type()];
return [self initWithType:type
sdp:[NSString stringForStdString:sdp]];
}
+ (std::string)stringForType:(RTCSdpType)type {
switch (type) {
case RTCSdpTypeOffer:
return webrtc::SessionDescriptionInterface::kOffer;
case RTCSdpTypePrAnswer:
return webrtc::SessionDescriptionInterface::kPrAnswer;
case RTCSdpTypeAnswer:
return webrtc::SessionDescriptionInterface::kAnswer;
}
}
+ (RTCSdpType)typeForString:(const std::string &)string {
if (string == webrtc::SessionDescriptionInterface::kOffer) {
return RTCSdpTypeOffer;
} else if (string == webrtc::SessionDescriptionInterface::kPrAnswer) {
return RTCSdpTypePrAnswer;
} else if (string == webrtc::SessionDescriptionInterface::kAnswer) {
return RTCSdpTypeAnswer;
} else {
RTC_NOTREACHED();
}
}
@end

View file

@ -0,0 +1,24 @@
/*
* Copyright 2015 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.
*/
#import "RTCStatsReport.h"
#include "talk/app/webrtc/statstypes.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCStatsReport ()
/** Initialize an RTCStatsReport object from a native StatsReport. */
- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,34 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/** This does not currently conform to the spec. */
@interface RTCStatsReport : NSObject
/** Time since 1970-01-01T00:00:00Z in milliseconds. */
@property(nonatomic, readonly) CFTimeInterval timestamp;
/** The type of stats held by this object. */
@property(nonatomic, readonly) NSString *type;
/** The identifier for this object. */
@property(nonatomic, readonly) NSString *statsId;
/** A dictionary holding the actual stats. */
@property(nonatomic, readonly) NSDictionary<NSString *, NSString *> *values;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,62 @@
/*
* Copyright 2015 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.
*/
#import "RTCStatsReport.h"
#include "webrtc/base/checks.h"
#import "webrtc/api/objc/RTCStatsReport+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
#import "webrtc/base/objc/RTCLogging.h"
@implementation RTCStatsReport
@synthesize timestamp = _timestamp;
@synthesize type = _type;
@synthesize statsId = _statsId;
@synthesize values = _values;
- (NSString *)description {
return [NSString stringWithFormat:@"RTCStatsReport:\n%@\n%@\n%f\n%@",
_statsId,
_type,
_timestamp,
_values];
}
#pragma mark - Private
- (instancetype)initWithNativeReport:(const webrtc::StatsReport &)nativeReport {
if (self = [super init]) {
_timestamp = nativeReport.timestamp();
_type = [NSString stringForStdString:nativeReport.TypeToString()];
_statsId = [NSString stringForStdString:
nativeReport.id()->ToString()];
NSUInteger capacity = nativeReport.values().size();
NSMutableDictionary *values =
[NSMutableDictionary dictionaryWithCapacity:capacity];
for (auto const &valuePair : nativeReport.values()) {
NSString *key = [NSString stringForStdString:
valuePair.second->display_name()];
NSString *value = [NSString stringForStdString:
valuePair.second->ToString()];
// Not expecting duplicate keys.
RTC_DCHECK(values[key]);
values[key] = value;
}
_values = values;
}
return self;
}
@end

View file

@ -1,5 +1,5 @@
/*
* Copyright 2004 The WebRTC Project Authors. All rights reserved.
* Copyright 2015 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
@ -8,13 +8,17 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_BASE_BASICDEFS_H_
#define WEBRTC_BASE_BASICDEFS_H_
#import "RTCVideoFrame.h"
#if HAVE_CONFIG_H
#include "config.h" // NOLINT
#endif
#include "talk/media/base/videoframe.h"
#define ARRAY_SIZE(x) (static_cast<int>(sizeof(x) / sizeof(x[0])))
NS_ASSUME_NONNULL_BEGIN
#endif // WEBRTC_BASE_BASICDEFS_H_
@interface RTCVideoFrame ()
- (instancetype)initWithNativeFrame:(const cricket::VideoFrame *)nativeFrame
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,37 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCVideoFrame : NSObject
/** Width without rotation applied. */
@property(nonatomic, readonly) size_t width;
/** Height without rotation applied. */
@property(nonatomic, readonly) size_t height;
@property(nonatomic, readonly) size_t chromaWidth;
@property(nonatomic, readonly) size_t chromaHeight;
@property(nonatomic, readonly) size_t chromaSize;
// These can return NULL if the object is not backed by a buffer.
@property(nonatomic, readonly, nullable) const uint8_t *yPlane;
@property(nonatomic, readonly, nullable) const uint8_t *uPlane;
@property(nonatomic, readonly, nullable) const uint8_t *vPlane;
@property(nonatomic, readonly) int32_t yPitch;
@property(nonatomic, readonly) int32_t uPitch;
@property(nonatomic, readonly) int32_t vPitch;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,79 @@
/*
* Copyright 2015 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.
*/
#import "RTCVideoFrame.h"
#include "webrtc/base/scoped_ptr.h"
#import "webrtc/api/objc/RTCVideoFrame+Private.h"
@implementation RTCVideoFrame {
rtc::scoped_ptr<cricket::VideoFrame> _videoFrame;
}
- (size_t)width {
return _videoFrame->GetWidth();
}
- (size_t)height {
return _videoFrame->GetHeight();
}
- (size_t)chromaWidth {
return _videoFrame->GetChromaWidth();
}
- (size_t)chromaHeight {
return _videoFrame->GetChromaHeight();
}
- (size_t)chromaSize {
return _videoFrame->GetChromaSize();
}
- (const uint8_t *)yPlane {
const cricket::VideoFrame *const_frame = _videoFrame.get();
return const_frame->GetYPlane();
}
- (const uint8_t *)uPlane {
const cricket::VideoFrame *const_frame = _videoFrame.get();
return const_frame->GetUPlane();
}
- (const uint8_t *)vPlane {
const cricket::VideoFrame *const_frame = _videoFrame.get();
return const_frame->GetVPlane();
}
- (int32_t)yPitch {
return _videoFrame->GetYPitch();
}
- (int32_t)uPitch {
return _videoFrame->GetUPitch();
}
- (int32_t)vPitch {
return _videoFrame->GetVPitch();
}
#pragma mark - Private
- (instancetype)initWithNativeFrame:(const cricket::VideoFrame *)nativeFrame {
if (self = [super init]) {
// Keep a shallow copy of the video frame. The underlying frame buffer is
// not copied.
_videoFrame.reset(nativeFrame->Copy());
}
return self;
}
@end

View file

@ -0,0 +1,30 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#endif
NS_ASSUME_NONNULL_BEGIN
@class RTCVideoFrame;
@protocol RTCVideoRenderer <NSObject>
/** The size of the frame. */
- (void)setSize:(CGSize)size;
/** The frame to be displayed. */
- (void)renderFrame:(RTCVideoFrame *)frame;
@end
NS_ASSUME_NONNULL_END

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
* Copyright 2015 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
@ -8,5 +8,6 @@
* be found in the AUTHORS file in the root of the source tree.
*/
// This file has moved.
// TODO(tommi): Delete after removing dependencies and updating Chromium.
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif

View file

@ -0,0 +1,74 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#include "webrtc/base/gunit.h"
#import "webrtc/api/objc/RTCIceCandidate.h"
#import "webrtc/api/objc/RTCIceCandidate+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@interface RTCIceCandidateTest : NSObject
- (void)testCandidate;
- (void)testInitFromNativeCandidate;
@end
@implementation RTCIceCandidateTest
- (void)testCandidate {
NSString *sdp = @"candidate:4025901590 1 udp 2122265343 "
"fdff:2642:12a6:fe38:c001:beda:fcf9:51aa "
"59052 typ host generation 0";
RTCIceCandidate *candidate = [[RTCIceCandidate alloc] initWithSdp:sdp
sdpMLineIndex:0
sdpMid:@"audio"];
rtc::scoped_ptr<webrtc::IceCandidateInterface> nativeCandidate =
candidate.nativeCandidate;
EXPECT_EQ("audio", nativeCandidate->sdp_mid());
EXPECT_EQ(0, nativeCandidate->sdp_mline_index());
std::string sdpString;
nativeCandidate->ToString(&sdpString);
EXPECT_EQ(sdp.stdString, sdpString);
}
- (void)testInitFromNativeCandidate {
std::string sdp("candidate:4025901590 1 udp 2122265343 "
"fdff:2642:12a6:fe38:c001:beda:fcf9:51aa "
"59052 typ host generation 0");
webrtc::IceCandidateInterface *nativeCandidate =
webrtc::CreateIceCandidate("audio", 0, sdp, nullptr);
RTCIceCandidate *iceCandidate =
[[RTCIceCandidate alloc] initWithNativeCandidate:nativeCandidate];
EXPECT_TRUE([@"audio" isEqualToString:iceCandidate.sdpMid]);
EXPECT_EQ(0, iceCandidate.sdpMLineIndex);
EXPECT_EQ(sdp, iceCandidate.sdp.stdString);
}
@end
TEST(RTCIceCandidateTest, CandidateTest) {
@autoreleasepool {
RTCIceCandidateTest *test = [[RTCIceCandidateTest alloc] init];
[test testCandidate];
}
}
TEST(RTCIceCandidateTest, InitFromCandidateTest) {
@autoreleasepool {
RTCIceCandidateTest *test = [[RTCIceCandidateTest alloc] init];
[test testInitFromNativeCandidate];
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#include <vector>
#include "webrtc/base/gunit.h"
#import "webrtc/api/objc/RTCIceServer.h"
#import "webrtc/api/objc/RTCIceServer+Private.h"
@interface RTCIceServerTest : NSObject
- (void)testOneURLServer;
- (void)testTwoURLServer;
- (void)testPasswordCredential;
@end
@implementation RTCIceServerTest
- (void)testOneURLServer {
RTCIceServer *server = [[RTCIceServer alloc] initWithURLStrings:@[
@"stun:stun1.example.net" ]];
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
EXPECT_EQ((size_t)1, iceStruct.urls.size());
EXPECT_EQ("stun:stun1.example.net", iceStruct.urls.front());
EXPECT_EQ("", iceStruct.username);
EXPECT_EQ("", iceStruct.password);
}
- (void)testTwoURLServer {
RTCIceServer *server = [[RTCIceServer alloc] initWithURLStrings:@[
@"turn1:turn1.example.net", @"turn2:turn2.example.net" ]];
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
EXPECT_EQ((size_t)2, iceStruct.urls.size());
EXPECT_EQ("turn1:turn1.example.net", iceStruct.urls.front());
EXPECT_EQ("turn2:turn2.example.net", iceStruct.urls.back());
EXPECT_EQ("", iceStruct.username);
EXPECT_EQ("", iceStruct.password);
}
- (void)testPasswordCredential {
RTCIceServer *server = [[RTCIceServer alloc]
initWithURLStrings:@[ @"turn1:turn1.example.net" ]
username:@"username"
credential:@"credential"];
webrtc::PeerConnectionInterface::IceServer iceStruct = server.iceServer;
EXPECT_EQ((size_t)1, iceStruct.urls.size());
EXPECT_EQ("turn1:turn1.example.net", iceStruct.urls.front());
EXPECT_EQ("username", iceStruct.username);
EXPECT_EQ("credential", iceStruct.password);
}
@end
TEST(RTCIceServerTest, OneURLTest) {
@autoreleasepool {
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
[test testOneURLServer];
}
}
TEST(RTCIceServerTest, TwoURLTest) {
@autoreleasepool {
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
[test testTwoURLServer];
}
}
TEST(RTCIceServerTest, PasswordCredentialTest) {
@autoreleasepool {
RTCIceServerTest *test = [[RTCIceServerTest alloc] init];
[test testPasswordCredential];
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#include "webrtc/base/gunit.h"
#import "webrtc/api/objc/RTCMediaConstraints.h"
#import "webrtc/api/objc/RTCMediaConstraints+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@interface RTCMediaConstraintsTest : NSObject
- (void)testMediaConstraints;
@end
@implementation RTCMediaConstraintsTest
- (void)testMediaConstraints {
NSDictionary *mandatory = @{@"key1": @"value1", @"key2": @"value2"};
NSDictionary *optional = @{@"key3": @"value3", @"key4": @"value4"};
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc]
initWithMandatoryConstraints:mandatory
optionalConstraints:optional];
rtc::scoped_ptr<webrtc::MediaConstraints> nativeConstraints =
[constraints nativeConstraints];
webrtc::MediaConstraintsInterface::Constraints nativeMandatory =
nativeConstraints->GetMandatory();
[self expectConstraints:mandatory inNativeConstraints:nativeMandatory];
webrtc::MediaConstraintsInterface::Constraints nativeOptional =
nativeConstraints->GetOptional();
[self expectConstraints:optional inNativeConstraints:nativeOptional];
}
- (void)expectConstraints:(NSDictionary *)constraints
inNativeConstraints:
(webrtc::MediaConstraintsInterface::Constraints)nativeConstraints {
EXPECT_EQ(constraints.count, nativeConstraints.size());
for (NSString *key in constraints) {
NSString *value = constraints[key];
std::string nativeValue;
bool found = nativeConstraints.FindFirst(key.stdString, &nativeValue);
EXPECT_TRUE(found);
EXPECT_EQ(value.stdString, nativeValue);
}
}
@end
TEST(RTCMediaConstraintsTest, MediaConstraintsTest) {
@autoreleasepool {
RTCMediaConstraintsTest *test = [[RTCMediaConstraintsTest alloc] init];
[test testMediaConstraints];
}
}

View file

@ -0,0 +1,144 @@
/*
* Copyright 2015 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.
*/
#import <Foundation/Foundation.h>
#include "webrtc/base/gunit.h"
#import "webrtc/api/objc/RTCSessionDescription.h"
#import "webrtc/api/objc/RTCSessionDescription+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@interface RTCSessionDescriptionTest : NSObject
- (void)testSessionDescriptionConversion;
- (void)testInitFromNativeSessionDescription;
@end
@implementation RTCSessionDescriptionTest
/**
* Test conversion of an Objective-C RTCSessionDescription to a native
* SessionDescriptionInterface (based on the types and SDP strings being equal).
*/
- (void)testSessionDescriptionConversion {
RTCSessionDescription *description =
[[RTCSessionDescription alloc] initWithType:RTCSdpTypeAnswer
sdp:[self sdp]];
webrtc::SessionDescriptionInterface *nativeDescription =
description.nativeDescription;
EXPECT_EQ(RTCSdpTypeAnswer,
[RTCSessionDescription typeForString:nativeDescription->type()]);
std::string sdp;
nativeDescription->ToString(&sdp);
EXPECT_EQ([self sdp].stdString, sdp);
}
- (void)testInitFromNativeSessionDescription {
webrtc::SessionDescriptionInterface *nativeDescription;
nativeDescription = webrtc::CreateSessionDescription(
webrtc::SessionDescriptionInterface::kAnswer,
[self sdp].stdString,
nullptr);
RTCSessionDescription *description =
[[RTCSessionDescription alloc] initWithNativeDescription:
nativeDescription];
EXPECT_EQ(webrtc::SessionDescriptionInterface::kAnswer,
[RTCSessionDescription stringForType:description.type]);
EXPECT_TRUE([[self sdp] isEqualToString:description.sdp]);
}
- (NSString *)sdp {
return @"v=0\r\n"
"o=- 5319989746393411314 2 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"t=0 0\r\n"
"a=group:BUNDLE audio video\r\n"
"a=msid-semantic: WMS ARDAMS\r\n"
"m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 0 8 126\r\n"
"c=IN IP4 0.0.0.0\r\n"
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
"a=ice-ufrag:f3o+0HG7l9nwIWFY\r\n"
"a=ice-pwd:VDctmJNCptR2TB7+meDpw7w5\r\n"
"a=fingerprint:sha-256 A9:D5:8D:A8:69:22:39:60:92:AD:94:1A:22:2D:5E:"
"A5:4A:A9:18:C2:35:5D:46:5E:59:BD:1C:AF:38:9F:E6:E1\r\n"
"a=setup:active\r\n"
"a=mid:audio\r\n"
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"
"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/"
"abs-send-time\r\n"
"a=sendrecv\r\n"
"a=rtcp-mux\r\n"
"a=rtpmap:111 opus/48000/2\r\n"
"a=fmtp:111 minptime=10; useinbandfec=1\r\n"
"a=rtpmap:103 ISAC/16000\r\n"
"a=rtpmap:9 G722/8000\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=rtpmap:126 telephone-event/8000\r\n"
"a=maxptime:60\r\n"
"a=ssrc:1504474588 cname:V+FdIC5AJpxLhdYQ\r\n"
"a=ssrc:1504474588 msid:ARDAMS ARDAMSa0\r\n"
"a=ssrc:1504474588 mslabel:ARDAMS\r\n"
"a=ssrc:1504474588 label:ARDAMSa0\r\n"
"m=video 9 UDP/TLS/RTP/SAVPF 100 116 117 96\r\n"
"c=IN IP4 0.0.0.0\r\n"
"a=rtcp:9 IN IP4 0.0.0.0\r\n"
"a=ice-ufrag:f3o+0HG7l9nwIWFY\r\n"
"a=ice-pwd:VDctmJNCptR2TB7+meDpw7w5\r\n"
"a=fingerprint:sha-256 A9:D5:8D:A8:69:22:39:60:92:AD:94:1A:22:2D:5E:"
"A5:4A:A9:18:C2:35:5D:46:5E:59:BD:1C:AF:38:9F:E6:E1\r\n"
"a=setup:active\r\n"
"a=mid:video\r\n"
"a=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\n"
"a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/"
"abs-send-time\r\n"
"a=extmap:4 urn:3gpp:video-orientation\r\n"
"a=sendrecv\r\n"
"a=rtcp-mux\r\n"
"a=rtpmap:100 VP8/90000\r\n"
"a=rtcp-fb:100 ccm fir\r\n"
"a=rtcp-fb:100 nack\r\n"
"a=rtcp-fb:100 nack pli\r\n"
"a=rtcp-fb:100 goog-remb\r\n"
"a=rtpmap:116 red/90000\r\n"
"a=rtpmap:117 ulpfec/90000\r\n"
"a=rtpmap:96 rtx/90000\r\n"
"a=fmtp:96 apt=100\r\n"
"a=ssrc-group:FID 498297514 1644357692\r\n"
"a=ssrc:498297514 cname:V+FdIC5AJpxLhdYQ\r\n"
"a=ssrc:498297514 msid:ARDAMS ARDAMSv0\r\n"
"a=ssrc:498297514 mslabel:ARDAMS\r\n"
"a=ssrc:498297514 label:ARDAMSv0\r\n"
"a=ssrc:1644357692 cname:V+FdIC5AJpxLhdYQ\r\n"
"a=ssrc:1644357692 msid:ARDAMS ARDAMSv0\r\n"
"a=ssrc:1644357692 mslabel:ARDAMS\r\n"
"a=ssrc:1644357692 label:ARDAMSv0\r\n";
}
@end
TEST(RTCSessionDescriptionTest, SessionDescriptionConversionTest) {
@autoreleasepool {
RTCSessionDescriptionTest *test = [[RTCSessionDescriptionTest alloc] init];
[test testSessionDescriptionConversion];
}
}
TEST(RTCSessionDescriptionTest, InitFromSessionDescriptionTest) {
@autoreleasepool {
RTCSessionDescriptionTest *test = [[RTCSessionDescriptionTest alloc] init];
[test testInitFromNativeSessionDescription];
}
}

View file

@ -0,0 +1,38 @@
# Copyright (c) 2015 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.
import("../build/webrtc.gni")
source_set("audio") {
sources = [
"audio_receive_stream.cc",
"audio_receive_stream.h",
"audio_send_stream.cc",
"audio_send_stream.h",
"audio_sink.h",
"audio_state.cc",
"audio_state.h",
"conversion.h",
"scoped_voe_interface.h",
]
configs += [ "..:common_config" ]
public_configs = [ "..:common_inherited_config" ]
if (is_clang) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
deps = [
"..:webrtc_common",
"../system_wrappers",
"../voice_engine",
]
}

View file

@ -1,5 +1,9 @@
solenberg@webrtc.org
tina.legrand@webrtc.org
# These are for the common case of adding or renaming files. If you're doing
# structural changes, please get a review from a reviewer in this file.
per-file *.gyp=*
per-file *.gypi=*
per-file BUILD.gn=kjellander@webrtc.org

View file

@ -0,0 +1,256 @@
/*
* Copyright (c) 2015 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 "webrtc/audio/audio_receive_stream.h"
#include <string>
#include <utility>
#include "webrtc/audio/audio_sink.h"
#include "webrtc/audio/audio_state.h"
#include "webrtc/audio/conversion.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/call/congestion_controller.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/system_wrappers/include/tick_util.h"
#include "webrtc/voice_engine/channel_proxy.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_codec.h"
#include "webrtc/voice_engine/include/voe_neteq_stats.h"
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
#include "webrtc/voice_engine/include/voe_video_sync.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
#include "webrtc/voice_engine/voice_engine_impl.h"
namespace webrtc {
namespace {
bool UseSendSideBwe(const webrtc::AudioReceiveStream::Config& config) {
if (!config.rtp.transport_cc) {
return false;
}
for (const auto& extension : config.rtp.extensions) {
if (extension.name == RtpExtension::kTransportSequenceNumber) {
return true;
}
}
return false;
}
} // namespace
std::string AudioReceiveStream::Config::Rtp::ToString() const {
std::stringstream ss;
ss << "{remote_ssrc: " << remote_ssrc;
ss << ", local_ssrc: " << local_ssrc;
ss << ", extensions: [";
for (size_t i = 0; i < extensions.size(); ++i) {
ss << extensions[i].ToString();
if (i != extensions.size() - 1) {
ss << ", ";
}
}
ss << ']';
ss << '}';
return ss.str();
}
std::string AudioReceiveStream::Config::ToString() const {
std::stringstream ss;
ss << "{rtp: " << rtp.ToString();
ss << ", receive_transport: "
<< (receive_transport ? "(Transport)" : "nullptr");
ss << ", rtcp_send_transport: "
<< (rtcp_send_transport ? "(Transport)" : "nullptr");
ss << ", voe_channel_id: " << voe_channel_id;
if (!sync_group.empty()) {
ss << ", sync_group: " << sync_group;
}
ss << ", combined_audio_video_bwe: "
<< (combined_audio_video_bwe ? "true" : "false");
ss << '}';
return ss.str();
}
namespace internal {
AudioReceiveStream::AudioReceiveStream(
CongestionController* congestion_controller,
const webrtc::AudioReceiveStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state)
: config_(config),
audio_state_(audio_state),
rtp_header_parser_(RtpHeaderParser::Create()) {
LOG(LS_INFO) << "AudioReceiveStream: " << config_.ToString();
RTC_DCHECK_NE(config_.voe_channel_id, -1);
RTC_DCHECK(audio_state_.get());
RTC_DCHECK(congestion_controller);
RTC_DCHECK(rtp_header_parser_);
VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine());
channel_proxy_ = voe_impl->GetChannelProxy(config_.voe_channel_id);
channel_proxy_->SetLocalSSRC(config.rtp.local_ssrc);
for (const auto& extension : config.rtp.extensions) {
if (extension.name == RtpExtension::kAudioLevel) {
channel_proxy_->SetReceiveAudioLevelIndicationStatus(true, extension.id);
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAudioLevel, extension.id);
RTC_DCHECK(registered);
} else if (extension.name == RtpExtension::kAbsSendTime) {
channel_proxy_->SetReceiveAbsoluteSenderTimeStatus(true, extension.id);
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime, extension.id);
RTC_DCHECK(registered);
} else if (extension.name == RtpExtension::kTransportSequenceNumber) {
bool registered = rtp_header_parser_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber, extension.id);
RTC_DCHECK(registered);
} else {
RTC_NOTREACHED() << "Unsupported RTP extension.";
}
}
// Configure bandwidth estimation.
channel_proxy_->SetCongestionControlObjects(
nullptr, nullptr, congestion_controller->packet_router());
if (config.combined_audio_video_bwe) {
if (UseSendSideBwe(config)) {
remote_bitrate_estimator_ =
congestion_controller->GetRemoteBitrateEstimator(true);
} else {
remote_bitrate_estimator_ =
congestion_controller->GetRemoteBitrateEstimator(false);
}
RTC_DCHECK(remote_bitrate_estimator_);
}
}
AudioReceiveStream::~AudioReceiveStream() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "~AudioReceiveStream: " << config_.ToString();
channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr);
if (remote_bitrate_estimator_) {
remote_bitrate_estimator_->RemoveStream(config_.rtp.remote_ssrc);
}
}
void AudioReceiveStream::Start() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::Stop() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioReceiveStream::SignalNetworkState(NetworkState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
bool AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
return false;
}
bool AudioReceiveStream::DeliverRtp(const uint8_t* packet,
size_t length,
const PacketTime& packet_time) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
RTPHeader header;
if (!rtp_header_parser_->Parse(packet, length, &header)) {
return false;
}
// Only forward if the parsed header has one of the headers necessary for
// bandwidth estimation. RTP timestamps has different rates for audio and
// video and shouldn't be mixed.
if (remote_bitrate_estimator_ &&
(header.extension.hasAbsoluteSendTime ||
header.extension.hasTransportSequenceNumber)) {
int64_t arrival_time_ms = TickTime::MillisecondTimestamp();
if (packet_time.timestamp >= 0)
arrival_time_ms = (packet_time.timestamp + 500) / 1000;
size_t payload_size = length - header.headerLength;
remote_bitrate_estimator_->IncomingPacket(arrival_time_ms, payload_size,
header, false);
}
return true;
}
webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
webrtc::AudioReceiveStream::Stats stats;
stats.remote_ssrc = config_.rtp.remote_ssrc;
ScopedVoEInterface<VoECodec> codec(voice_engine());
webrtc::CallStatistics call_stats = channel_proxy_->GetRTCPStatistics();
webrtc::CodecInst codec_inst = {0};
if (codec->GetRecCodec(config_.voe_channel_id, codec_inst) == -1) {
return stats;
}
stats.bytes_rcvd = call_stats.bytesReceived;
stats.packets_rcvd = call_stats.packetsReceived;
stats.packets_lost = call_stats.cumulativeLost;
stats.fraction_lost = Q8ToFloat(call_stats.fractionLost);
stats.capture_start_ntp_time_ms = call_stats.capture_start_ntp_time_ms_;
if (codec_inst.pltype != -1) {
stats.codec_name = codec_inst.plname;
}
stats.ext_seqnum = call_stats.extendedMax;
if (codec_inst.plfreq / 1000 > 0) {
stats.jitter_ms = call_stats.jitterSamples / (codec_inst.plfreq / 1000);
}
stats.delay_estimate_ms = channel_proxy_->GetDelayEstimate();
stats.audio_level = channel_proxy_->GetSpeechOutputLevelFullRange();
// Get jitter buffer and total delay (alg + jitter + playout) stats.
auto ns = channel_proxy_->GetNetworkStatistics();
stats.jitter_buffer_ms = ns.currentBufferSize;
stats.jitter_buffer_preferred_ms = ns.preferredBufferSize;
stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
stats.accelerate_rate = Q14ToFloat(ns.currentAccelerateRate);
stats.preemptive_expand_rate = Q14ToFloat(ns.currentPreemptiveRate);
auto ds = channel_proxy_->GetDecodingCallStatistics();
stats.decoding_calls_to_silence_generator = ds.calls_to_silence_generator;
stats.decoding_calls_to_neteq = ds.calls_to_neteq;
stats.decoding_normal = ds.decoded_normal;
stats.decoding_plc = ds.decoded_plc;
stats.decoding_cng = ds.decoded_cng;
stats.decoding_plc_cng = ds.decoded_plc_cng;
return stats;
}
void AudioReceiveStream::SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
channel_proxy_->SetSink(std::move(sink));
}
const webrtc::AudioReceiveStream::Config& AudioReceiveStream::config() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return config_;
}
VoiceEngine* AudioReceiveStream::voice_engine() const {
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
VoiceEngine* voice_engine = audio_state->voice_engine();
RTC_DCHECK(voice_engine);
return voice_engine;
}
} // namespace internal
} // namespace webrtc

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015 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.
*/
#ifndef WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
#define WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_
#include "webrtc/audio_receive_stream.h"
#include "webrtc/audio_state.h"
#include "webrtc/base/thread_checker.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
namespace webrtc {
class CongestionController;
class RemoteBitrateEstimator;
namespace voe {
class ChannelProxy;
} // namespace voe
namespace internal {
class AudioReceiveStream final : public webrtc::AudioReceiveStream {
public:
AudioReceiveStream(CongestionController* congestion_controller,
const webrtc::AudioReceiveStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state);
~AudioReceiveStream() override;
// webrtc::ReceiveStream implementation.
void Start() override;
void Stop() override;
void SignalNetworkState(NetworkState state) override;
bool DeliverRtcp(const uint8_t* packet, size_t length) override;
bool DeliverRtp(const uint8_t* packet,
size_t length,
const PacketTime& packet_time) override;
// webrtc::AudioReceiveStream implementation.
webrtc::AudioReceiveStream::Stats GetStats() const override;
void SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) override;
const webrtc::AudioReceiveStream::Config& config() const;
private:
VoiceEngine* voice_engine() const;
rtc::ThreadChecker thread_checker_;
RemoteBitrateEstimator* remote_bitrate_estimator_ = nullptr;
const webrtc::AudioReceiveStream::Config config_;
rtc::scoped_refptr<webrtc::AudioState> audio_state_;
rtc::scoped_ptr<RtpHeaderParser> rtp_header_parser_;
rtc::scoped_ptr<voe::ChannelProxy> channel_proxy_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioReceiveStream);
};
} // namespace internal
} // namespace webrtc
#endif // WEBRTC_AUDIO_AUDIO_RECEIVE_STREAM_H_

View file

@ -0,0 +1,328 @@
/*
* Copyright (c) 2015 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 <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/audio/audio_receive_stream.h"
#include "webrtc/audio/conversion.h"
#include "webrtc/call/mock/mock_congestion_controller.h"
#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
#include "webrtc/modules/pacing/packet_router.h"
#include "webrtc/modules/remote_bitrate_estimator/include/mock/mock_remote_bitrate_estimator.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/utility/include/mock/mock_process_thread.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/mock_voe_channel_proxy.h"
#include "webrtc/test/mock_voice_engine.h"
#include "webrtc/video/call_stats.h"
namespace webrtc {
namespace test {
namespace {
using testing::_;
using testing::Return;
AudioDecodingCallStats MakeAudioDecodeStatsForTest() {
AudioDecodingCallStats audio_decode_stats;
audio_decode_stats.calls_to_silence_generator = 234;
audio_decode_stats.calls_to_neteq = 567;
audio_decode_stats.decoded_normal = 890;
audio_decode_stats.decoded_plc = 123;
audio_decode_stats.decoded_cng = 456;
audio_decode_stats.decoded_plc_cng = 789;
return audio_decode_stats;
}
const int kChannelId = 2;
const uint32_t kRemoteSsrc = 1234;
const uint32_t kLocalSsrc = 5678;
const size_t kOneByteExtensionHeaderLength = 4;
const size_t kOneByteExtensionLength = 4;
const int kAbsSendTimeId = 2;
const int kAudioLevelId = 3;
const int kTransportSequenceNumberId = 4;
const int kJitterBufferDelay = -7;
const int kPlayoutBufferDelay = 302;
const unsigned int kSpeechOutputLevel = 99;
const CallStatistics kCallStats = {
345, 678, 901, 234, -12, 3456, 7890, 567, 890, 123};
const CodecInst kCodecInst = {
123, "codec_name_recv", 96000, -187, 0, -103};
const NetworkStatistics kNetworkStats = {
123, 456, false, 0, 0, 789, 12, 345, 678, 901, -1, -1, -1, -1, -1, 0};
const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
struct ConfigHelper {
ConfigHelper()
: simulated_clock_(123456),
call_stats_(&simulated_clock_),
congestion_controller_(&process_thread_,
&call_stats_,
&bitrate_observer_) {
using testing::Invoke;
EXPECT_CALL(voice_engine_,
RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
EXPECT_CALL(voice_engine_,
DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
AudioState::Config config;
config.voice_engine = &voice_engine_;
audio_state_ = AudioState::Create(config);
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId))
.WillOnce(Invoke([this](int channel_id) {
EXPECT_FALSE(channel_proxy_);
channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kLocalSsrc)).Times(1);
EXPECT_CALL(*channel_proxy_,
SetReceiveAbsoluteSenderTimeStatus(true, kAbsSendTimeId))
.Times(1);
EXPECT_CALL(*channel_proxy_,
SetReceiveAudioLevelIndicationStatus(true, kAudioLevelId))
.Times(1);
EXPECT_CALL(*channel_proxy_, SetCongestionControlObjects(
nullptr, nullptr, &packet_router_))
.Times(1);
EXPECT_CALL(congestion_controller_, packet_router())
.WillOnce(Return(&packet_router_));
EXPECT_CALL(*channel_proxy_,
SetCongestionControlObjects(nullptr, nullptr, nullptr))
.Times(1);
return channel_proxy_;
}));
stream_config_.voe_channel_id = kChannelId;
stream_config_.rtp.local_ssrc = kLocalSsrc;
stream_config_.rtp.remote_ssrc = kRemoteSsrc;
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
}
MockCongestionController* congestion_controller() {
return &congestion_controller_;
}
MockRemoteBitrateEstimator* remote_bitrate_estimator() {
return &remote_bitrate_estimator_;
}
AudioReceiveStream::Config& config() { return stream_config_; }
rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
MockVoiceEngine& voice_engine() { return voice_engine_; }
void SetupMockForBweFeedback(bool send_side_bwe) {
EXPECT_CALL(congestion_controller_,
GetRemoteBitrateEstimator(send_side_bwe))
.WillOnce(Return(&remote_bitrate_estimator_));
EXPECT_CALL(remote_bitrate_estimator_,
RemoveStream(stream_config_.rtp.remote_ssrc));
}
void SetupMockForGetStats() {
using testing::DoAll;
using testing::SetArgReferee;
ASSERT_TRUE(channel_proxy_);
EXPECT_CALL(*channel_proxy_, GetRTCPStatistics())
.WillOnce(Return(kCallStats));
EXPECT_CALL(*channel_proxy_, GetDelayEstimate())
.WillOnce(Return(kJitterBufferDelay + kPlayoutBufferDelay));
EXPECT_CALL(*channel_proxy_, GetSpeechOutputLevelFullRange())
.WillOnce(Return(kSpeechOutputLevel));
EXPECT_CALL(*channel_proxy_, GetNetworkStatistics())
.WillOnce(Return(kNetworkStats));
EXPECT_CALL(*channel_proxy_, GetDecodingCallStatistics())
.WillOnce(Return(kAudioDecodeStats));
EXPECT_CALL(voice_engine_, GetRecCodec(kChannelId, _))
.WillOnce(DoAll(SetArgReferee<1>(kCodecInst), Return(0)));
}
private:
SimulatedClock simulated_clock_;
CallStats call_stats_;
PacketRouter packet_router_;
testing::NiceMock<MockBitrateObserver> bitrate_observer_;
testing::NiceMock<MockProcessThread> process_thread_;
MockCongestionController congestion_controller_;
MockRemoteBitrateEstimator remote_bitrate_estimator_;
testing::StrictMock<MockVoiceEngine> voice_engine_;
rtc::scoped_refptr<AudioState> audio_state_;
AudioReceiveStream::Config stream_config_;
testing::StrictMock<MockVoEChannelProxy>* channel_proxy_ = nullptr;
};
void BuildOneByteExtension(std::vector<uint8_t>::iterator it,
int id,
uint32_t extension_value,
size_t value_length) {
const uint16_t kRtpOneByteHeaderExtensionId = 0xBEDE;
ByteWriter<uint16_t>::WriteBigEndian(&(*it), kRtpOneByteHeaderExtensionId);
it += 2;
ByteWriter<uint16_t>::WriteBigEndian(&(*it), kOneByteExtensionLength / 4);
it += 2;
const size_t kExtensionDataLength = kOneByteExtensionLength - 1;
uint32_t shifted_value = extension_value
<< (8 * (kExtensionDataLength - value_length));
*it = (id << 4) + (value_length - 1);
++it;
ByteWriter<uint32_t, kExtensionDataLength>::WriteBigEndian(&(*it),
shifted_value);
}
std::vector<uint8_t> CreateRtpHeaderWithOneByteExtension(
int extension_id,
uint32_t extension_value,
size_t value_length) {
std::vector<uint8_t> header;
header.resize(webrtc::kRtpHeaderSize + kOneByteExtensionHeaderLength +
kOneByteExtensionLength);
header[0] = 0x80; // Version 2.
header[0] |= 0x10; // Set extension bit.
header[1] = 100; // Payload type.
header[1] |= 0x80; // Marker bit is set.
ByteWriter<uint16_t>::WriteBigEndian(&header[2], 0x1234); // Sequence number.
ByteWriter<uint32_t>::WriteBigEndian(&header[4], 0x5678); // Timestamp.
ByteWriter<uint32_t>::WriteBigEndian(&header[8], 0x4321); // SSRC.
BuildOneByteExtension(header.begin() + webrtc::kRtpHeaderSize, extension_id,
extension_value, value_length);
return header;
}
} // namespace
TEST(AudioReceiveStreamTest, ConfigToString) {
AudioReceiveStream::Config config;
config.rtp.remote_ssrc = kRemoteSsrc;
config.rtp.local_ssrc = kLocalSsrc;
config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
config.voe_channel_id = kChannelId;
config.combined_audio_video_bwe = true;
EXPECT_EQ(
"{rtp: {remote_ssrc: 1234, local_ssrc: 5678, extensions: [{name: "
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 2}]}, "
"receive_transport: nullptr, rtcp_send_transport: nullptr, "
"voe_channel_id: 2, combined_audio_video_bwe: true}",
config.ToString());
}
TEST(AudioReceiveStreamTest, ConstructDestruct) {
ConfigHelper helper;
internal::AudioReceiveStream recv_stream(
helper.congestion_controller(), helper.config(), helper.audio_state());
}
MATCHER_P(VerifyHeaderExtension, expected_extension, "") {
return arg.extension.hasAbsoluteSendTime ==
expected_extension.hasAbsoluteSendTime &&
arg.extension.absoluteSendTime ==
expected_extension.absoluteSendTime &&
arg.extension.hasTransportSequenceNumber ==
expected_extension.hasTransportSequenceNumber &&
arg.extension.transportSequenceNumber ==
expected_extension.transportSequenceNumber;
}
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweWithTimestamp) {
ConfigHelper helper;
helper.config().combined_audio_video_bwe = true;
helper.SetupMockForBweFeedback(false);
internal::AudioReceiveStream recv_stream(
helper.congestion_controller(), helper.config(), helper.audio_state());
const int kAbsSendTimeValue = 1234;
std::vector<uint8_t> rtp_packet =
CreateRtpHeaderWithOneByteExtension(kAbsSendTimeId, kAbsSendTimeValue, 3);
PacketTime packet_time(5678000, 0);
const size_t kExpectedHeaderLength = 20;
RTPHeaderExtension expected_extension;
expected_extension.hasAbsoluteSendTime = true;
expected_extension.absoluteSendTime = kAbsSendTimeValue;
EXPECT_CALL(*helper.remote_bitrate_estimator(),
IncomingPacket(packet_time.timestamp / 1000,
rtp_packet.size() - kExpectedHeaderLength,
VerifyHeaderExtension(expected_extension), false))
.Times(1);
EXPECT_TRUE(
recv_stream.DeliverRtp(&rtp_packet[0], rtp_packet.size(), packet_time));
}
TEST(AudioReceiveStreamTest, AudioPacketUpdatesBweFeedback) {
ConfigHelper helper;
helper.config().combined_audio_video_bwe = true;
helper.config().rtp.transport_cc = true;
helper.config().rtp.extensions.push_back(RtpExtension(
RtpExtension::kTransportSequenceNumber, kTransportSequenceNumberId));
helper.SetupMockForBweFeedback(true);
internal::AudioReceiveStream recv_stream(
helper.congestion_controller(), helper.config(), helper.audio_state());
const int kTransportSequenceNumberValue = 1234;
std::vector<uint8_t> rtp_packet = CreateRtpHeaderWithOneByteExtension(
kTransportSequenceNumberId, kTransportSequenceNumberValue, 2);
PacketTime packet_time(5678000, 0);
const size_t kExpectedHeaderLength = 20;
RTPHeaderExtension expected_extension;
expected_extension.hasTransportSequenceNumber = true;
expected_extension.transportSequenceNumber = kTransportSequenceNumberValue;
EXPECT_CALL(*helper.remote_bitrate_estimator(),
IncomingPacket(packet_time.timestamp / 1000,
rtp_packet.size() - kExpectedHeaderLength,
VerifyHeaderExtension(expected_extension), false))
.Times(1);
EXPECT_TRUE(
recv_stream.DeliverRtp(&rtp_packet[0], rtp_packet.size(), packet_time));
}
TEST(AudioReceiveStreamTest, GetStats) {
ConfigHelper helper;
internal::AudioReceiveStream recv_stream(
helper.congestion_controller(), helper.config(), helper.audio_state());
helper.SetupMockForGetStats();
AudioReceiveStream::Stats stats = recv_stream.GetStats();
EXPECT_EQ(kRemoteSsrc, stats.remote_ssrc);
EXPECT_EQ(static_cast<int64_t>(kCallStats.bytesReceived), stats.bytes_rcvd);
EXPECT_EQ(static_cast<uint32_t>(kCallStats.packetsReceived),
stats.packets_rcvd);
EXPECT_EQ(kCallStats.cumulativeLost, stats.packets_lost);
EXPECT_EQ(Q8ToFloat(kCallStats.fractionLost), stats.fraction_lost);
EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name);
EXPECT_EQ(kCallStats.extendedMax, stats.ext_seqnum);
EXPECT_EQ(kCallStats.jitterSamples / (kCodecInst.plfreq / 1000),
stats.jitter_ms);
EXPECT_EQ(kNetworkStats.currentBufferSize, stats.jitter_buffer_ms);
EXPECT_EQ(kNetworkStats.preferredBufferSize,
stats.jitter_buffer_preferred_ms);
EXPECT_EQ(static_cast<uint32_t>(kJitterBufferDelay + kPlayoutBufferDelay),
stats.delay_estimate_ms);
EXPECT_EQ(static_cast<int32_t>(kSpeechOutputLevel), stats.audio_level);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
stats.speech_expand_rate);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSecondaryDecodedRate),
stats.secondary_decoded_rate);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentAccelerateRate),
stats.accelerate_rate);
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentPreemptiveRate),
stats.preemptive_expand_rate);
EXPECT_EQ(kAudioDecodeStats.calls_to_silence_generator,
stats.decoding_calls_to_silence_generator);
EXPECT_EQ(kAudioDecodeStats.calls_to_neteq, stats.decoding_calls_to_neteq);
EXPECT_EQ(kAudioDecodeStats.decoded_normal, stats.decoding_normal);
EXPECT_EQ(kAudioDecodeStats.decoded_plc, stats.decoding_plc);
EXPECT_EQ(kAudioDecodeStats.decoded_cng, stats.decoding_cng);
EXPECT_EQ(kAudioDecodeStats.decoded_plc_cng, stats.decoding_plc_cng);
EXPECT_EQ(kCallStats.capture_start_ntp_time_ms_,
stats.capture_start_ntp_time_ms);
}
} // namespace test
} // namespace webrtc

View file

@ -0,0 +1,221 @@
/*
* Copyright (c) 2015 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 "webrtc/audio/audio_send_stream.h"
#include <string>
#include "webrtc/audio/audio_state.h"
#include "webrtc/audio/conversion.h"
#include "webrtc/audio/scoped_voe_interface.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/call/congestion_controller.h"
#include "webrtc/modules/pacing/paced_sender.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "webrtc/voice_engine/channel_proxy.h"
#include "webrtc/voice_engine/include/voe_audio_processing.h"
#include "webrtc/voice_engine/include/voe_codec.h"
#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
#include "webrtc/voice_engine/include/voe_volume_control.h"
#include "webrtc/voice_engine/voice_engine_impl.h"
namespace webrtc {
std::string AudioSendStream::Config::Rtp::ToString() const {
std::stringstream ss;
ss << "{ssrc: " << ssrc;
ss << ", extensions: [";
for (size_t i = 0; i < extensions.size(); ++i) {
ss << extensions[i].ToString();
if (i != extensions.size() - 1) {
ss << ", ";
}
}
ss << ']';
ss << ", c_name: " << c_name;
ss << '}';
return ss.str();
}
std::string AudioSendStream::Config::ToString() const {
std::stringstream ss;
ss << "{rtp: " << rtp.ToString();
ss << ", voe_channel_id: " << voe_channel_id;
// TODO(solenberg): Encoder config.
ss << ", cng_payload_type: " << cng_payload_type;
ss << ", red_payload_type: " << red_payload_type;
ss << '}';
return ss.str();
}
namespace internal {
AudioSendStream::AudioSendStream(
const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
CongestionController* congestion_controller)
: config_(config), audio_state_(audio_state) {
LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
RTC_DCHECK_NE(config_.voe_channel_id, -1);
RTC_DCHECK(audio_state_.get());
RTC_DCHECK(congestion_controller);
VoiceEngineImpl* voe_impl = static_cast<VoiceEngineImpl*>(voice_engine());
channel_proxy_ = voe_impl->GetChannelProxy(config_.voe_channel_id);
channel_proxy_->SetCongestionControlObjects(
congestion_controller->pacer(),
congestion_controller->GetTransportFeedbackObserver(),
congestion_controller->packet_router());
channel_proxy_->SetRTCPStatus(true);
channel_proxy_->SetLocalSSRC(config.rtp.ssrc);
channel_proxy_->SetRTCP_CNAME(config.rtp.c_name);
for (const auto& extension : config.rtp.extensions) {
if (extension.name == RtpExtension::kAbsSendTime) {
channel_proxy_->SetSendAbsoluteSenderTimeStatus(true, extension.id);
} else if (extension.name == RtpExtension::kAudioLevel) {
channel_proxy_->SetSendAudioLevelIndicationStatus(true, extension.id);
} else if (extension.name == RtpExtension::kTransportSequenceNumber) {
channel_proxy_->EnableSendTransportSequenceNumber(extension.id);
} else {
RTC_NOTREACHED() << "Registering unsupported RTP extension.";
}
}
}
AudioSendStream::~AudioSendStream() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
channel_proxy_->SetCongestionControlObjects(nullptr, nullptr, nullptr);
}
void AudioSendStream::Start() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioSendStream::Stop() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
void AudioSendStream::SignalNetworkState(NetworkState state) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
}
bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
// TODO(solenberg): Tests call this function on a network thread, libjingle
// calls on the worker thread. We should move towards always using a network
// thread. Then this check can be enabled.
// RTC_DCHECK(!thread_checker_.CalledOnValidThread());
return false;
}
bool AudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event,
uint32_t duration_ms) {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type) &&
channel_proxy_->SendTelephoneEventOutband(event, duration_ms);
}
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
webrtc::AudioSendStream::Stats stats;
stats.local_ssrc = config_.rtp.ssrc;
ScopedVoEInterface<VoEAudioProcessing> processing(voice_engine());
ScopedVoEInterface<VoECodec> codec(voice_engine());
ScopedVoEInterface<VoEVolumeControl> volume(voice_engine());
webrtc::CallStatistics call_stats = channel_proxy_->GetRTCPStatistics();
stats.bytes_sent = call_stats.bytesSent;
stats.packets_sent = call_stats.packetsSent;
// RTT isn't known until a RTCP report is received. Until then, VoiceEngine
// returns 0 to indicate an error value.
if (call_stats.rttMs > 0) {
stats.rtt_ms = call_stats.rttMs;
}
// TODO(solenberg): [was ajm]: Re-enable this metric once we have a reliable
// implementation.
stats.aec_quality_min = -1;
webrtc::CodecInst codec_inst = {0};
if (codec->GetSendCodec(config_.voe_channel_id, codec_inst) != -1) {
RTC_DCHECK_NE(codec_inst.pltype, -1);
stats.codec_name = codec_inst.plname;
// Get data from the last remote RTCP report.
for (const auto& block : channel_proxy_->GetRemoteRTCPReportBlocks()) {
// Lookup report for send ssrc only.
if (block.source_SSRC == stats.local_ssrc) {
stats.packets_lost = block.cumulative_num_packets_lost;
stats.fraction_lost = Q8ToFloat(block.fraction_lost);
stats.ext_seqnum = block.extended_highest_sequence_number;
// Convert samples to milliseconds.
if (codec_inst.plfreq / 1000 > 0) {
stats.jitter_ms =
block.interarrival_jitter / (codec_inst.plfreq / 1000);
}
break;
}
}
}
// Local speech level.
{
unsigned int level = 0;
int error = volume->GetSpeechInputLevelFullRange(level);
RTC_DCHECK_EQ(0, error);
stats.audio_level = static_cast<int32_t>(level);
}
bool echo_metrics_on = false;
int error = processing->GetEcMetricsStatus(echo_metrics_on);
RTC_DCHECK_EQ(0, error);
if (echo_metrics_on) {
// These can also be negative, but in practice -1 is only used to signal
// insufficient data, since the resolution is limited to multiples of 4 ms.
int median = -1;
int std = -1;
float dummy = 0.0f;
error = processing->GetEcDelayMetrics(median, std, dummy);
RTC_DCHECK_EQ(0, error);
stats.echo_delay_median_ms = median;
stats.echo_delay_std_ms = std;
// These can take on valid negative values, so use the lowest possible level
// as default rather than -1.
int erl = -100;
int erle = -100;
int dummy1 = 0;
int dummy2 = 0;
error = processing->GetEchoMetrics(erl, erle, dummy1, dummy2);
RTC_DCHECK_EQ(0, error);
stats.echo_return_loss = erl;
stats.echo_return_loss_enhancement = erle;
}
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
stats.typing_noise_detected = audio_state->typing_noise_detected();
return stats;
}
const webrtc::AudioSendStream::Config& AudioSendStream::config() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return config_;
}
VoiceEngine* AudioSendStream::voice_engine() const {
internal::AudioState* audio_state =
static_cast<internal::AudioState*>(audio_state_.get());
VoiceEngine* voice_engine = audio_state->voice_engine();
RTC_DCHECK(voice_engine);
return voice_engine;
}
} // namespace internal
} // namespace webrtc

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2015 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.
*/
#ifndef WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
#define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
#include "webrtc/audio_send_stream.h"
#include "webrtc/audio_state.h"
#include "webrtc/base/thread_checker.h"
#include "webrtc/base/scoped_ptr.h"
namespace webrtc {
class CongestionController;
class VoiceEngine;
namespace voe {
class ChannelProxy;
} // namespace voe
namespace internal {
class AudioSendStream final : public webrtc::AudioSendStream {
public:
AudioSendStream(const webrtc::AudioSendStream::Config& config,
const rtc::scoped_refptr<webrtc::AudioState>& audio_state,
CongestionController* congestion_controller);
~AudioSendStream() override;
// webrtc::SendStream implementation.
void Start() override;
void Stop() override;
void SignalNetworkState(NetworkState state) override;
bool DeliverRtcp(const uint8_t* packet, size_t length) override;
// webrtc::AudioSendStream implementation.
bool SendTelephoneEvent(int payload_type, uint8_t event,
uint32_t duration_ms) override;
webrtc::AudioSendStream::Stats GetStats() const override;
const webrtc::AudioSendStream::Config& config() const;
private:
VoiceEngine* voice_engine() const;
rtc::ThreadChecker thread_checker_;
const webrtc::AudioSendStream::Config config_;
rtc::scoped_refptr<webrtc::AudioState> audio_state_;
rtc::scoped_ptr<voe::ChannelProxy> channel_proxy_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AudioSendStream);
};
} // namespace internal
} // namespace webrtc
#endif // WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_

View file

@ -0,0 +1,245 @@
/*
* Copyright (c) 2015 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 <string>
#include <vector>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/audio/audio_send_stream.h"
#include "webrtc/audio/audio_state.h"
#include "webrtc/audio/conversion.h"
#include "webrtc/call/congestion_controller.h"
#include "webrtc/modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
#include "webrtc/modules/pacing/paced_sender.h"
#include "webrtc/test/mock_voe_channel_proxy.h"
#include "webrtc/test/mock_voice_engine.h"
#include "webrtc/video/call_stats.h"
namespace webrtc {
namespace test {
namespace {
using testing::_;
using testing::Return;
const int kChannelId = 1;
const uint32_t kSsrc = 1234;
const char* kCName = "foo_name";
const int kAudioLevelId = 2;
const int kAbsSendTimeId = 3;
const int kTransportSequenceNumberId = 4;
const int kEchoDelayMedian = 254;
const int kEchoDelayStdDev = -3;
const int kEchoReturnLoss = -65;
const int kEchoReturnLossEnhancement = 101;
const unsigned int kSpeechInputLevel = 96;
const CallStatistics kCallStats = {
1345, 1678, 1901, 1234, 112, 13456, 17890, 1567, -1890, -1123};
const CodecInst kCodecInst = {-121, "codec_name_send", 48000, -231, 0, -671};
const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354};
const int kTelephoneEventPayloadType = 123;
const uint8_t kTelephoneEventCode = 45;
const uint32_t kTelephoneEventDuration = 6789;
struct ConfigHelper {
ConfigHelper()
: stream_config_(nullptr),
call_stats_(Clock::GetRealTimeClock()),
process_thread_(ProcessThread::Create("AudioTestThread")),
congestion_controller_(process_thread_.get(),
&call_stats_,
&bitrate_observer_) {
using testing::Invoke;
using testing::StrEq;
EXPECT_CALL(voice_engine_,
RegisterVoiceEngineObserver(_)).WillOnce(Return(0));
EXPECT_CALL(voice_engine_,
DeRegisterVoiceEngineObserver()).WillOnce(Return(0));
AudioState::Config config;
config.voice_engine = &voice_engine_;
audio_state_ = AudioState::Create(config);
EXPECT_CALL(voice_engine_, ChannelProxyFactory(kChannelId))
.WillOnce(Invoke([this](int channel_id) {
EXPECT_FALSE(channel_proxy_);
channel_proxy_ = new testing::StrictMock<MockVoEChannelProxy>();
EXPECT_CALL(*channel_proxy_, SetRTCPStatus(true)).Times(1);
EXPECT_CALL(*channel_proxy_, SetLocalSSRC(kSsrc)).Times(1);
EXPECT_CALL(*channel_proxy_, SetRTCP_CNAME(StrEq(kCName))).Times(1);
EXPECT_CALL(*channel_proxy_,
SetSendAbsoluteSenderTimeStatus(true, kAbsSendTimeId)).Times(1);
EXPECT_CALL(*channel_proxy_,
SetSendAudioLevelIndicationStatus(true, kAudioLevelId)).Times(1);
EXPECT_CALL(*channel_proxy_, EnableSendTransportSequenceNumber(
kTransportSequenceNumberId))
.Times(1);
EXPECT_CALL(*channel_proxy_,
SetCongestionControlObjects(
congestion_controller_.pacer(),
congestion_controller_.GetTransportFeedbackObserver(),
congestion_controller_.packet_router()))
.Times(1);
EXPECT_CALL(*channel_proxy_,
SetCongestionControlObjects(nullptr, nullptr, nullptr))
.Times(1);
return channel_proxy_;
}));
stream_config_.voe_channel_id = kChannelId;
stream_config_.rtp.ssrc = kSsrc;
stream_config_.rtp.c_name = kCName;
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAudioLevel, kAudioLevelId));
stream_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
stream_config_.rtp.extensions.push_back(RtpExtension(
RtpExtension::kTransportSequenceNumber, kTransportSequenceNumberId));
}
AudioSendStream::Config& config() { return stream_config_; }
rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
CongestionController* congestion_controller() {
return &congestion_controller_;
}
void SetupMockForSendTelephoneEvent() {
EXPECT_TRUE(channel_proxy_);
EXPECT_CALL(*channel_proxy_,
SetSendTelephoneEventPayloadType(kTelephoneEventPayloadType))
.WillOnce(Return(true));
EXPECT_CALL(*channel_proxy_,
SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration))
.WillOnce(Return(true));
}
void SetupMockForGetStats() {
using testing::DoAll;
using testing::SetArgReferee;
std::vector<ReportBlock> report_blocks;
webrtc::ReportBlock block = kReportBlock;
report_blocks.push_back(block); // Has wrong SSRC.
block.source_SSRC = kSsrc;
report_blocks.push_back(block); // Correct block.
block.fraction_lost = 0;
report_blocks.push_back(block); // Duplicate SSRC, bad fraction_lost.
EXPECT_TRUE(channel_proxy_);
EXPECT_CALL(*channel_proxy_, GetRTCPStatistics())
.WillRepeatedly(Return(kCallStats));
EXPECT_CALL(*channel_proxy_, GetRemoteRTCPReportBlocks())
.WillRepeatedly(Return(report_blocks));
EXPECT_CALL(voice_engine_, GetSendCodec(kChannelId, _))
.WillRepeatedly(DoAll(SetArgReferee<1>(kCodecInst), Return(0)));
EXPECT_CALL(voice_engine_, GetSpeechInputLevelFullRange(_))
.WillRepeatedly(DoAll(SetArgReferee<0>(kSpeechInputLevel), Return(0)));
EXPECT_CALL(voice_engine_, GetEcMetricsStatus(_))
.WillRepeatedly(DoAll(SetArgReferee<0>(true), Return(0)));
EXPECT_CALL(voice_engine_, GetEchoMetrics(_, _, _, _))
.WillRepeatedly(DoAll(SetArgReferee<0>(kEchoReturnLoss),
SetArgReferee<1>(kEchoReturnLossEnhancement),
Return(0)));
EXPECT_CALL(voice_engine_, GetEcDelayMetrics(_, _, _))
.WillRepeatedly(DoAll(SetArgReferee<0>(kEchoDelayMedian),
SetArgReferee<1>(kEchoDelayStdDev), Return(0)));
}
private:
testing::StrictMock<MockVoiceEngine> voice_engine_;
rtc::scoped_refptr<AudioState> audio_state_;
AudioSendStream::Config stream_config_;
testing::StrictMock<MockVoEChannelProxy>* channel_proxy_ = nullptr;
CallStats call_stats_;
testing::NiceMock<MockBitrateObserver> bitrate_observer_;
rtc::scoped_ptr<ProcessThread> process_thread_;
CongestionController congestion_controller_;
};
} // namespace
TEST(AudioSendStreamTest, ConfigToString) {
AudioSendStream::Config config(nullptr);
config.rtp.ssrc = kSsrc;
config.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
config.rtp.c_name = kCName;
config.voe_channel_id = kChannelId;
config.cng_payload_type = 42;
config.red_payload_type = 17;
EXPECT_EQ(
"{rtp: {ssrc: 1234, extensions: [{name: "
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time, id: 3}], "
"c_name: foo_name}, voe_channel_id: 1, cng_payload_type: 42, "
"red_payload_type: 17}",
config.ToString());
}
TEST(AudioSendStreamTest, ConstructDestruct) {
ConfigHelper helper;
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
helper.congestion_controller());
}
TEST(AudioSendStreamTest, SendTelephoneEvent) {
ConfigHelper helper;
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
helper.congestion_controller());
helper.SetupMockForSendTelephoneEvent();
EXPECT_TRUE(send_stream.SendTelephoneEvent(kTelephoneEventPayloadType,
kTelephoneEventCode, kTelephoneEventDuration));
}
TEST(AudioSendStreamTest, GetStats) {
ConfigHelper helper;
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
helper.congestion_controller());
helper.SetupMockForGetStats();
AudioSendStream::Stats stats = send_stream.GetStats();
EXPECT_EQ(kSsrc, stats.local_ssrc);
EXPECT_EQ(static_cast<int64_t>(kCallStats.bytesSent), stats.bytes_sent);
EXPECT_EQ(kCallStats.packetsSent, stats.packets_sent);
EXPECT_EQ(static_cast<int32_t>(kReportBlock.cumulative_num_packets_lost),
stats.packets_lost);
EXPECT_EQ(Q8ToFloat(kReportBlock.fraction_lost), stats.fraction_lost);
EXPECT_EQ(std::string(kCodecInst.plname), stats.codec_name);
EXPECT_EQ(static_cast<int32_t>(kReportBlock.extended_highest_sequence_number),
stats.ext_seqnum);
EXPECT_EQ(static_cast<int32_t>(kReportBlock.interarrival_jitter /
(kCodecInst.plfreq / 1000)),
stats.jitter_ms);
EXPECT_EQ(kCallStats.rttMs, stats.rtt_ms);
EXPECT_EQ(static_cast<int32_t>(kSpeechInputLevel), stats.audio_level);
EXPECT_EQ(-1, stats.aec_quality_min);
EXPECT_EQ(kEchoDelayMedian, stats.echo_delay_median_ms);
EXPECT_EQ(kEchoDelayStdDev, stats.echo_delay_std_ms);
EXPECT_EQ(kEchoReturnLoss, stats.echo_return_loss);
EXPECT_EQ(kEchoReturnLossEnhancement, stats.echo_return_loss_enhancement);
EXPECT_FALSE(stats.typing_noise_detected);
}
TEST(AudioSendStreamTest, GetStatsTypingNoiseDetected) {
ConfigHelper helper;
internal::AudioSendStream send_stream(helper.config(), helper.audio_state(),
helper.congestion_controller());
helper.SetupMockForGetStats();
EXPECT_FALSE(send_stream.GetStats().typing_noise_detected);
internal::AudioState* internal_audio_state =
static_cast<internal::AudioState*>(helper.audio_state().get());
VoiceEngineObserver* voe_observer =
static_cast<VoiceEngineObserver*>(internal_audio_state);
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_WARNING);
EXPECT_TRUE(send_stream.GetStats().typing_noise_detected);
voe_observer->CallbackOnError(-1, VE_TYPING_NOISE_OFF_WARNING);
EXPECT_FALSE(send_stream.GetStats().typing_noise_detected);
}
} // namespace test
} // namespace webrtc

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015 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.
*/
#ifndef WEBRTC_AUDIO_AUDIO_SINK_H_
#define WEBRTC_AUDIO_AUDIO_SINK_H_
#if defined(WEBRTC_POSIX) && !defined(__STDC_FORMAT_MACROS)
// Avoid conflict with format_macros.h.
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#include <stddef.h>
namespace webrtc {
// Represents a simple push audio sink.
class AudioSinkInterface {
public:
virtual ~AudioSinkInterface() {}
struct Data {
Data(int16_t* data,
size_t samples_per_channel,
int sample_rate,
size_t channels,
uint32_t timestamp)
: data(data),
samples_per_channel(samples_per_channel),
sample_rate(sample_rate),
channels(channels),
timestamp(timestamp) {}
int16_t* data; // The actual 16bit audio data.
size_t samples_per_channel; // Number of frames in the buffer.
int sample_rate; // Sample rate in Hz.
size_t channels; // Number of channels in the audio data.
uint32_t timestamp; // The RTP timestamp of the first sample.
};
virtual void OnData(const Data& audio) = 0;
};
} // namespace webrtc
#endif // WEBRTC_AUDIO_AUDIO_SINK_H_

View file

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015 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 "webrtc/audio/audio_state.h"
#include "webrtc/base/atomicops.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/voice_engine/include/voe_errors.h"
namespace webrtc {
namespace internal {
AudioState::AudioState(const AudioState::Config& config)
: config_(config), voe_base_(config.voice_engine) {
process_thread_checker_.DetachFromThread();
// Only one AudioState should be created per VoiceEngine.
RTC_CHECK(voe_base_->RegisterVoiceEngineObserver(*this) != -1);
}
AudioState::~AudioState() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
voe_base_->DeRegisterVoiceEngineObserver();
}
VoiceEngine* AudioState::voice_engine() {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
return config_.voice_engine;
}
bool AudioState::typing_noise_detected() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
rtc::CritScope lock(&crit_sect_);
return typing_noise_detected_;
}
// Reference count; implementation copied from rtc::RefCountedObject.
int AudioState::AddRef() const {
return rtc::AtomicOps::Increment(&ref_count_);
}
// Reference count; implementation copied from rtc::RefCountedObject.
int AudioState::Release() const {
int count = rtc::AtomicOps::Decrement(&ref_count_);
if (!count) {
delete this;
}
return count;
}
void AudioState::CallbackOnError(int channel_id, int err_code) {
RTC_DCHECK(process_thread_checker_.CalledOnValidThread());
// All call sites in VoE, as of this writing, specify -1 as channel_id.
RTC_DCHECK(channel_id == -1);
LOG(LS_INFO) << "VoiceEngine error " << err_code << " reported on channel "
<< channel_id << ".";
if (err_code == VE_TYPING_NOISE_WARNING) {
rtc::CritScope lock(&crit_sect_);
typing_noise_detected_ = true;
} else if (err_code == VE_TYPING_NOISE_OFF_WARNING) {
rtc::CritScope lock(&crit_sect_);
typing_noise_detected_ = false;
}
}
} // namespace internal
rtc::scoped_refptr<AudioState> AudioState::Create(
const AudioState::Config& config) {
return rtc::scoped_refptr<AudioState>(new internal::AudioState(config));
}
} // namespace webrtc

Some files were not shown because too many files have changed in this diff Show more