mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-23 00:47:31 +09:00
[WebRTC] updated to upstream branch 49 and related.
this patch is based on 38d7a7883...226f2f0bd
This commit is contained in:
parent
e79847e7b9
commit
a3239eaa4d
2838 changed files with 151221 additions and 159688 deletions
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
namespace mozilla {
|
||||
class GmpVideoCodec {
|
||||
public:
|
||||
static VideoEncoder* CreateEncoder();
|
||||
static VideoDecoder* CreateDecoder();
|
||||
static WebrtcVideoEncoder* CreateEncoder();
|
||||
static WebrtcVideoDecoder* CreateDecoder();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "MediaPipelineFilter.h"
|
||||
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/common_types.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
23
media/webrtc/trunk/README.md
Normal file
23
media/webrtc/trunk/README.md
Normal 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
|
||||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
31
media/webrtc/trunk/webrtc/.gitignore
vendored
31
media/webrtc/trunk/webrtc/.gitignore
vendored
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
76
media/webrtc/trunk/webrtc/api/BUILD.gn
Normal file
76
media/webrtc/trunk/webrtc/api/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
1
media/webrtc/trunk/webrtc/api/OWNERS
Normal file
1
media/webrtc/trunk/webrtc/api/OWNERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
tkchin@webrtc.org
|
||||
83
media/webrtc/trunk/webrtc/api/api.gyp
Normal file
83
media/webrtc/trunk/webrtc/api/api.gyp
Normal 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"
|
||||
],
|
||||
}
|
||||
40
media/webrtc/trunk/webrtc/api/api_tests.gyp
Normal file
40
media/webrtc/trunk/webrtc/api/api_tests.gyp
Normal 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"
|
||||
],
|
||||
}
|
||||
1
media/webrtc/trunk/webrtc/api/objc/OWNERS
Normal file
1
media/webrtc/trunk/webrtc/api/objc/OWNERS
Normal file
|
|
@ -0,0 +1 @@
|
|||
tkchin@webrtc.org
|
||||
3
media/webrtc/trunk/webrtc/api/objc/README
Normal file
3
media/webrtc/trunk/webrtc/api/objc/README
Normal 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.
|
||||
35
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.h
Normal file
35
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.h
Normal 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
|
||||
259
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.m
Normal file
259
media/webrtc/trunk/webrtc/api/objc/RTCEAGLVideoView.m
Normal 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
|
||||
36
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate+Private.h
Normal file
36
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate+Private.h
Normal 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
|
||||
44
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.h
Normal file
44
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.h
Normal 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
|
||||
70
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.mm
Normal file
70
media/webrtc/trunk/webrtc/api/objc/RTCIceCandidate.mm
Normal 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
|
||||
28
media/webrtc/trunk/webrtc/api/objc/RTCIceServer+Private.h
Normal file
28
media/webrtc/trunk/webrtc/api/objc/RTCIceServer+Private.h
Normal 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
|
||||
42
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.h
Normal file
42
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.h
Normal 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
|
||||
64
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.mm
Normal file
64
media/webrtc/trunk/webrtc/api/objc/RTCIceServer.mm
Normal 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
|
||||
|
|
@ -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
|
||||
28
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.h
Normal file
28
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.h
Normal 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
|
||||
92
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.mm
Normal file
92
media/webrtc/trunk/webrtc/api/objc/RTCMediaConstraints.mm
Normal 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
|
||||
41
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource+Private.h
Normal file
41
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource+Private.h
Normal 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
|
||||
31
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.h
Normal file
31
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.h
Normal 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
|
||||
84
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.mm
Normal file
84
media/webrtc/trunk/webrtc/api/objc/RTCMediaSource.mm
Normal 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
|
||||
|
|
@ -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
|
||||
47
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.h
Normal file
47
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.h
Normal 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
|
||||
105
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.mm
Normal file
105
media/webrtc/trunk/webrtc/api/objc/RTCMediaStreamTrack.mm
Normal 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
|
||||
34
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.h
Normal file
34
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.h
Normal 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
|
||||
141
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.m
Normal file
141
media/webrtc/trunk/webrtc/api/objc/RTCNSGLVideoView.m
Normal 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
|
||||
58
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.h
Normal file
58
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.h
Normal 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
|
||||
485
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.mm
Normal file
485
media/webrtc/trunk/webrtc/api/objc/RTCOpenGLVideoRenderer.mm
Normal 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
|
||||
|
|
@ -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
|
||||
41
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.h
Normal file
41
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.h
Normal 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
|
||||
92
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.mm
Normal file
92
media/webrtc/trunk/webrtc/api/objc/RTCSessionDescription.mm
Normal 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
|
||||
24
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport+Private.h
Normal file
24
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport+Private.h
Normal 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
|
||||
34
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.h
Normal file
34
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.h
Normal 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
|
||||
62
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.mm
Normal file
62
media/webrtc/trunk/webrtc/api/objc/RTCStatsReport.mm
Normal 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
|
||||
|
|
@ -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
|
||||
37
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.h
Normal file
37
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.h
Normal 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
|
||||
79
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.mm
Normal file
79
media/webrtc/trunk/webrtc/api/objc/RTCVideoFrame.mm
Normal 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
|
||||
30
media/webrtc/trunk/webrtc/api/objc/RTCVideoRenderer.h
Normal file
30
media/webrtc/trunk/webrtc/api/objc/RTCVideoRenderer.h
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
84
media/webrtc/trunk/webrtc/api/objctests/RTCIceServerTest.mm
Normal file
84
media/webrtc/trunk/webrtc/api/objctests/RTCIceServerTest.mm
Normal 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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
38
media/webrtc/trunk/webrtc/audio/BUILD.gn
Normal file
38
media/webrtc/trunk/webrtc/audio/BUILD.gn
Normal 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",
|
||||
]
|
||||
}
|
||||
|
|
@ -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
|
||||
256
media/webrtc/trunk/webrtc/audio/audio_receive_stream.cc
Normal file
256
media/webrtc/trunk/webrtc/audio/audio_receive_stream.cc
Normal 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
|
||||
67
media/webrtc/trunk/webrtc/audio/audio_receive_stream.h
Normal file
67
media/webrtc/trunk/webrtc/audio/audio_receive_stream.h
Normal 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_
|
||||
328
media/webrtc/trunk/webrtc/audio/audio_receive_stream_unittest.cc
Normal file
328
media/webrtc/trunk/webrtc/audio/audio_receive_stream_unittest.cc
Normal 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
|
||||
221
media/webrtc/trunk/webrtc/audio/audio_send_stream.cc
Normal file
221
media/webrtc/trunk/webrtc/audio/audio_send_stream.cc
Normal 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
|
||||
61
media/webrtc/trunk/webrtc/audio/audio_send_stream.h
Normal file
61
media/webrtc/trunk/webrtc/audio/audio_send_stream.h
Normal 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_
|
||||
245
media/webrtc/trunk/webrtc/audio/audio_send_stream_unittest.cc
Normal file
245
media/webrtc/trunk/webrtc/audio/audio_send_stream_unittest.cc
Normal 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
|
||||
53
media/webrtc/trunk/webrtc/audio/audio_sink.h
Normal file
53
media/webrtc/trunk/webrtc/audio/audio_sink.h
Normal 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_
|
||||
79
media/webrtc/trunk/webrtc/audio/audio_state.cc
Normal file
79
media/webrtc/trunk/webrtc/audio/audio_state.cc
Normal 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
Loading…
Add table
Add a link
Reference in a new issue