[WebRTC] updated to upstream branch 49 and related.

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

View file

@ -36,6 +36,8 @@ gyp_vars = {
# don't use openssl
'use_openssl': 0,
'debug': 1 if CONFIG['DEBUG'] else 0,
'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
'use_glib': 1 if CONFIG['GLIB_LIBS'] else 0,

View file

@ -146,8 +146,16 @@ CaptureStreamTestHelper.prototype = {
info("Waiting for video " + video.id + " to match [" +
refColor.data.join(',') + "] - " + refColor.name +
" (" + infoString + ")");
var paintedFrames = video.mozPaintedFrames-1;
return this.waitForPixel(video, 0, 0,
px => this.isPixel(px, refColor, threshold))
px => { if (paintedFrames != video.mozPaintedFrames) {
info("Frame: " + video.mozPaintedFrames +
" IsPixel ref=" + refColor.data +
" threshold=" + threshold +
" value=" + px);
paintedFrames = video.mozPaintedFrames;
}
return this.isPixel(px, refColor, threshold); })
.then(() => ok(true, video.id + " " + infoString));
},

View file

@ -5,7 +5,6 @@
#include "CamerasChild.h"
#include "webrtc/video_engine/include/vie_capture.h"
#undef FF
#include "mozilla/Assertions.h"
@ -336,7 +335,7 @@ int
CamerasChild::GetCaptureCapability(CaptureEngine aCapEngine,
const char* unique_idUTF8,
const unsigned int capability_number,
webrtc::CaptureCapability& capability)
webrtc::VideoCaptureCapability& capability)
{
LOG(("GetCaptureCapability: %s %d", unique_idUTF8, capability_number));
RefPtr<CamerasChild> deathGrip = this;
@ -352,7 +351,7 @@ CamerasChild::GetCaptureCapability(CaptureEngine aCapEngine,
}
bool
CamerasChild::RecvReplyGetCaptureCapability(const CaptureCapability& ipcCapability)
CamerasChild::RecvReplyGetCaptureCapability(const VideoCaptureCapability& ipcCapability)
{
LOG((__PRETTY_FUNCTION__));
MonitorAutoLock monitor(mReplyMonitor);
@ -414,7 +413,7 @@ int
CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
const char* unique_idUTF8,
const unsigned int unique_idUTF8Length,
int& capture_id,
int& aStreamId,
const nsACString& aOrigin)
{
LOG((__PRETTY_FUNCTION__));
@ -427,7 +426,7 @@ CamerasChild::AllocateCaptureDevice(CaptureEngine aCapEngine,
LockAndDispatch<> dispatcher(this, __func__, runnable);
if (dispatcher.Success()) {
LOG(("Capture Device allocated: %d", mReplyInteger));
capture_id = mReplyInteger;
aStreamId = mReplyInteger;
}
return dispatcher.ReturnValue();
}
@ -460,7 +459,7 @@ CamerasChild::ReleaseCaptureDevice(CaptureEngine aCapEngine,
void
CamerasChild::AddCallback(const CaptureEngine aCapEngine, const int capture_id,
webrtc::ExternalRenderer* render)
FrameRelay* render)
{
MutexAutoLock lock(mCallbackMutex);
CapturerElement ce;
@ -486,12 +485,12 @@ CamerasChild::RemoveCallback(const CaptureEngine aCapEngine, const int capture_i
int
CamerasChild::StartCapture(CaptureEngine aCapEngine,
const int capture_id,
webrtc::CaptureCapability& webrtcCaps,
webrtc::ExternalRenderer* cb)
webrtc::VideoCaptureCapability& webrtcCaps,
FrameRelay* cb)
{
LOG((__PRETTY_FUNCTION__));
AddCallback(aCapEngine, capture_id, cb);
CaptureCapability capCap(webrtcCaps.width,
VideoCaptureCapability capCap(webrtcCaps.width,
webrtcCaps.height,
webrtcCaps.maxFPS,
webrtcCaps.expectedCaptureDelay,
@ -500,7 +499,7 @@ CamerasChild::StartCapture(CaptureEngine aCapEngine,
webrtcCaps.interlaced);
RefPtr<CamerasChild> deathGrip = this;
nsCOMPtr<nsIRunnable> runnable =
mozilla::NewNonOwningRunnableMethod<CaptureEngine, int, CaptureCapability>
mozilla::NewNonOwningRunnableMethod<CaptureEngine, int, VideoCaptureCapability>
(this, &CamerasChild::SendStartCapture, aCapEngine, capture_id, capCap);
LockAndDispatch<> dispatcher(this, __func__, runnable);
return dispatcher.ReturnValue();
@ -617,18 +616,12 @@ bool
CamerasChild::RecvDeliverFrame(const CaptureEngine& capEngine,
const int& capId,
mozilla::ipc::Shmem&& shmem,
const size_t& size,
const uint32_t& time_stamp,
const int64_t& ntp_time,
const int64_t& render_time)
const VideoFrameProperties & prop)
{
MutexAutoLock lock(mCallbackMutex);
if (Callback(capEngine, capId)) {
unsigned char* image = shmem.get<unsigned char>();
Callback(capEngine, capId)->DeliverFrame(image, size,
time_stamp,
ntp_time, render_time,
nullptr);
Callback(capEngine, capId)->DeliverFrame(image, prop);
} else {
LOG(("DeliverFrame called with dead callback"));
}
@ -673,7 +666,7 @@ CamerasChild::RecvFrameSizeChange(const CaptureEngine& capEngine,
LOG((__PRETTY_FUNCTION__));
MutexAutoLock lock(mCallbackMutex);
if (Callback(capEngine, capId)) {
Callback(capEngine, capId)->FrameSizeChange(w, h, 0);
Callback(capEngine, capId)->FrameSizeChange(w, h);
} else {
LOG(("Frame size change with dead callback"));
}
@ -717,7 +710,7 @@ CamerasChild::~CamerasChild()
MOZ_COUNT_DTOR(CamerasChild);
}
webrtc::ExternalRenderer* CamerasChild::Callback(CaptureEngine aCapEngine,
FrameRelay* CamerasChild::Callback(CaptureEngine aCapEngine,
int capture_id)
{
for (unsigned int i = 0; i < mCallbacks.Length(); i++) {

View file

@ -19,10 +19,10 @@
// conflicts with #include of scoped_ptr.h
#undef FF
#include "webrtc/common.h"
// Video Engine
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_renderer.h"
#include "webrtc/modules/video_capture/video_capture_defines.h"
namespace mozilla {
@ -32,10 +32,17 @@ class BackgroundChildImpl;
namespace camera {
class FrameRelay {
public:
virtual int DeliverFrame(uint8_t* buffer,
const mozilla::camera::VideoFrameProperties& props) = 0;
virtual void FrameSizeChange(unsigned int w, unsigned int h) = 0;
};
struct CapturerElement {
CaptureEngine engine;
int id;
webrtc::ExternalRenderer* callback;
FrameRelay* callback;
};
// Forward declaration so we can work with pointers to it.
@ -157,9 +164,9 @@ public:
// IPC messages recevied, received on the PBackground thread
// these are the actual callbacks with data
virtual bool RecvDeliverFrame(const CaptureEngine&, const int&, mozilla::ipc::Shmem&&,
const size_t&, const uint32_t&, const int64_t&,
const int64_t&) override;
virtual bool RecvDeliverFrame(const CaptureEngine&, const int&,
mozilla::ipc::Shmem&&,
const VideoFrameProperties & prop) override;
virtual bool RecvFrameSizeChange(const CaptureEngine&, const int&,
const int& w, const int& h) override;
@ -171,7 +178,7 @@ public:
virtual bool RecvReplyNumberOfCaptureDevices(const int&) override;
virtual bool RecvReplyNumberOfCapabilities(const int&) override;
virtual bool RecvReplyAllocateCaptureDevice(const int&) override;
virtual bool RecvReplyGetCaptureCapability(const CaptureCapability& capability) override;
virtual bool RecvReplyGetCaptureCapability(const VideoCaptureCapability& capability) override;
virtual bool RecvReplyGetCaptureDevice(const nsCString& device_name,
const nsCString& device_id,
const bool& scary) override;
@ -188,8 +195,8 @@ public:
int ReleaseCaptureDevice(CaptureEngine aCapEngine,
const int capture_id);
int StartCapture(CaptureEngine aCapEngine,
const int capture_id, webrtc::CaptureCapability& capability,
webrtc::ExternalRenderer* func);
const int capture_id, webrtc::VideoCaptureCapability& capability,
FrameRelay* func);
int StopCapture(CaptureEngine aCapEngine, const int capture_id);
int AllocateCaptureDevice(CaptureEngine aCapEngine,
const char* unique_idUTF8,
@ -199,7 +206,7 @@ public:
int GetCaptureCapability(CaptureEngine aCapEngine,
const char* unique_idUTF8,
const unsigned int capability_number,
webrtc::CaptureCapability& capability);
webrtc::VideoCaptureCapability& capability);
int GetCaptureDevice(CaptureEngine aCapEngine,
unsigned int list_number, char* device_nameUTF8,
const unsigned int device_nameUTF8Length,
@ -209,7 +216,7 @@ public:
void ShutdownAll();
int EnsureInitialized(CaptureEngine aCapEngine);
webrtc::ExternalRenderer* Callback(CaptureEngine aCapEngine, int capture_id);
FrameRelay* Callback(CaptureEngine aCapEngine, int capture_id);
private:
CamerasChild();
@ -219,7 +226,7 @@ private:
bool DispatchToParent(nsIRunnable* aRunnable,
MonitorAutoLock& aMonitor);
void AddCallback(const CaptureEngine aCapEngine, const int capture_id,
webrtc::ExternalRenderer* render);
FrameRelay* render);
void RemoveCallback(const CaptureEngine aCapEngine, const int capture_id);
void ShutdownParent();
void ShutdownChild();
@ -246,7 +253,7 @@ private:
// Async responses data contents;
bool mReplySuccess;
int mReplyInteger;
webrtc::CaptureCapability mReplyCapability;
webrtc::VideoCaptureCapability mReplyCapability;
nsCString mReplyDeviceName;
nsCString mReplyDeviceID;
bool mReplyScary;

View file

@ -6,6 +6,7 @@
#include "CamerasParent.h"
#include "MediaEngine.h"
#include "MediaUtils.h"
#include "VideoFrameUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Unused.h"
@ -26,9 +27,11 @@
#endif
#undef LOG
#undef LOG_VERBOSE
#undef LOG_ENABLED
mozilla::LazyLogModule gCamerasParentLog("CamerasParent");
#define LOG(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Debug, args)
#define LOG_VERBOSE(args) MOZ_LOG(gCamerasParentLog, mozilla::LogLevel::Verbose, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gCamerasParentLog, mozilla::LogLevel::Debug)
namespace mozilla {
@ -44,7 +47,7 @@ namespace camera {
// suitable for UI access.
// InputObserver is owned by CamerasParent, and it has a ref to CamerasParent
void InputObserver::DeviceChange() {
void InputObserver::OnDeviceChange() {
LOG((__PRETTY_FUNCTION__));
MOZ_ASSERT(mParent);
@ -63,80 +66,30 @@ void InputObserver::DeviceChange() {
thread->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
};
class FrameSizeChangeRunnable : public Runnable {
class DeliverFrameRunnable : public ::mozilla::Runnable {
public:
FrameSizeChangeRunnable(CamerasParent *aParent, CaptureEngine capEngine,
int cap_id, unsigned int aWidth, unsigned int aHeight)
: mParent(aParent), mCapEngine(capEngine), mCapId(cap_id),
mWidth(aWidth), mHeight(aHeight) {}
NS_IMETHOD Run() override {
if (mParent->IsShuttingDown()) {
// Communication channel is being torn down
LOG(("FrameSizeChangeRunnable is active without active Child"));
mResult = 0;
return NS_OK;
}
if (!mParent->SendFrameSizeChange(mCapEngine, mCapId, mWidth, mHeight)) {
mResult = -1;
} else {
mResult = 0;
}
return NS_OK;
}
int GetResult() {
return mResult;
}
private:
RefPtr<CamerasParent> mParent;
CaptureEngine mCapEngine;
int mCapId;
unsigned int mWidth;
unsigned int mHeight;
int mResult;
};
int
CallbackHelper::FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams)
{
LOG(("CallbackHelper Video FrameSizeChange: %ux%u", w, h));
RefPtr<FrameSizeChangeRunnable> runnable =
new FrameSizeChangeRunnable(mParent, mCapEngine, mCapturerId, w, h);
MOZ_ASSERT(mParent);
nsIThread * thread = mParent->GetBackgroundThread();
MOZ_ASSERT(thread != nullptr);
thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return 0;
}
class DeliverFrameRunnable : public Runnable {
public:
DeliverFrameRunnable(CamerasParent *aParent,
CaptureEngine engine,
int cap_id,
ShmemBuffer buffer,
unsigned char* altbuffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time)
: mParent(aParent), mCapEngine(engine), mCapId(cap_id), mBuffer(Move(buffer)),
mSize(size), mTimeStamp(time_stamp), mNtpTime(ntp_time),
mRenderTime(render_time) {
DeliverFrameRunnable(CamerasParent *aParent, CaptureEngine aEngine,
uint32_t aStreamId, const webrtc::VideoFrame& aFrame,
const VideoFrameProperties& aProperties)
: mParent(aParent), mCapEngine(aEngine), mStreamId(aStreamId),
mProperties(aProperties)
{
// No ShmemBuffer (of the right size) was available, so make an
// extra buffer here. We have no idea when we are going to run and
// it will be potentially long after the webrtc frame callback has
// returned, so the copy needs to be no later than here.
// We will need to copy this back into a Shmem later on so we prefer
// using ShmemBuffers to avoid the extra copy.
if (altbuffer != nullptr) {
mAlternateBuffer.reset(new unsigned char[size]);
memcpy(mAlternateBuffer.get(), altbuffer, size);
}
};
mAlternateBuffer.reset(new unsigned char[aProperties.bufferSize()]);
VideoFrameUtils::CopyVideoFrameBuffers(mAlternateBuffer.get(),
aProperties.bufferSize(), aFrame);
}
DeliverFrameRunnable(CamerasParent* aParent, CaptureEngine aEngine,
uint32_t aStreamId, ShmemBuffer aBuffer, VideoFrameProperties& aProperties)
: mParent(aParent), mCapEngine(aEngine), mStreamId(aStreamId),
mBuffer(Move(aBuffer)), mProperties(aProperties)
{};
NS_IMETHOD Run() override {
if (mParent->IsShuttingDown()) {
@ -144,10 +97,8 @@ public:
mResult = 0;
return NS_OK;
}
if (!mParent->DeliverFrameOverIPC(mCapEngine, mCapId,
Move(mBuffer), mAlternateBuffer.get(),
mSize, mTimeStamp,
mNtpTime, mRenderTime)) {
if (!mParent->DeliverFrameOverIPC(mCapEngine, mStreamId, Move(mBuffer),
mAlternateBuffer.get(), mProperties)) {
mResult = -1;
} else {
mResult = 0;
@ -162,13 +113,10 @@ public:
private:
RefPtr<CamerasParent> mParent;
CaptureEngine mCapEngine;
int mCapId;
uint32_t mStreamId;
ShmemBuffer mBuffer;
mozilla::UniquePtr<unsigned char[]> mAlternateBuffer;
size_t mSize;
uint32_t mTimeStamp;
int64_t mNtpTime;
int64_t mRenderTime;
VideoFrameProperties mProperties;
int mResult;
};
@ -258,14 +206,11 @@ CamerasParent::StopVideoCapture()
}
int
CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
int cap_id,
ShmemBuffer buffer,
unsigned char* altbuffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time)
CamerasParent::DeliverFrameOverIPC(CaptureEngine capEng,
uint32_t aStreamId,
ShmemBuffer buffer,
unsigned char* altbuffer,
VideoFrameProperties& aProps)
{
// No ShmemBuffers were available, so construct one now of the right size
// and copy into it. That is an extra copy, but we expect this to be
@ -273,7 +218,7 @@ CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
// buffer of the right size.
if (altbuffer != nullptr) {
// Get a shared memory buffer from the pool, at least size big
ShmemBuffer shMemBuff = mShmemPool.Get(this, size);
ShmemBuffer shMemBuff = mShmemPool.Get(this, aProps.bufferSize());
if (!shMemBuff.Valid()) {
LOG(("No usable Video shmem in DeliverFrame (out of buffers?)"));
@ -282,20 +227,18 @@ CamerasParent::DeliverFrameOverIPC(CaptureEngine cap_engine,
}
// get() and Size() check for proper alignment of the segment
memcpy(shMemBuff.GetBytes(), altbuffer, size);
memcpy(shMemBuff.GetBytes(), altbuffer, aProps.bufferSize());
if (!SendDeliverFrame(cap_engine, cap_id,
shMemBuff.Get(), size,
time_stamp, ntp_time, render_time)) {
if (!SendDeliverFrame(capEng, aStreamId,
shMemBuff.Get(), aProps)) {
return -1;
}
} else {
MOZ_ASSERT(buffer.Valid());
// ShmemBuffer was available, we're all good. A single copy happened
// in the original webrtc callback.
if (!SendDeliverFrame(cap_engine, cap_id,
buffer.Get(), size,
time_stamp, ntp_time, render_time)) {
if (!SendDeliverFrame(capEng, aStreamId,
buffer.Get(), aProps)) {
return -1;
}
}
@ -309,16 +252,16 @@ CamerasParent::GetBuffer(size_t aSize)
return mShmemPool.GetIfAvailable(aSize);
}
int
CallbackHelper::DeliverFrame(unsigned char* buffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle)
int32_t
CallbackHelper::RenderFrame(uint32_t aStreamId, const webrtc::VideoFrame& aVideoFrame)
{
LOG_VERBOSE((__PRETTY_FUNCTION__));
RefPtr<DeliverFrameRunnable> runnable = nullptr;
// Get frame properties
camera::VideoFrameProperties properties;
VideoFrameUtils::InitFrameBufferProperties(aVideoFrame, properties);
// Get a shared memory buffer to copy the frame data into
ShmemBuffer shMemBuffer = mParent->GetBuffer(size);
ShmemBuffer shMemBuffer = mParent->GetBuffer(properties.bufferSize());
if (!shMemBuffer.Valid()) {
// Either we ran out of buffers or they're not the right size yet
LOG(("Correctly sized Video shmem not available in DeliverFrame"));
@ -326,30 +269,33 @@ CallbackHelper::DeliverFrame(unsigned char* buffer,
// the DeliverFrameRunnable constructor.
} else {
// Shared memory buffers of the right size are available, do the copy here.
memcpy(shMemBuffer.GetBytes(), buffer, size);
// Mark the original buffer as cleared.
buffer = nullptr;
VideoFrameUtils::CopyVideoFrameBuffers(shMemBuffer.GetBytes(),
properties.bufferSize(), aVideoFrame);
runnable = new DeliverFrameRunnable(mParent, mCapEngine, mStreamId,
Move(shMemBuffer), properties);
}
if (!runnable.get()) {
runnable = new DeliverFrameRunnable(mParent, mCapEngine, mStreamId,
aVideoFrame, properties);
}
RefPtr<DeliverFrameRunnable> runnable =
new DeliverFrameRunnable(mParent, mCapEngine, mCapturerId,
Move(shMemBuffer), buffer, size, time_stamp,
ntp_time, render_time);
MOZ_ASSERT(mParent);
nsIThread* thread = mParent->GetBackgroundThread();
MOZ_ASSERT(thread != nullptr);
thread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return 0;
}
// XXX!!! FIX THIS -- we should move to pure DeliverI420Frame
int
CallbackHelper::DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame)
void
CallbackHelper::OnIncomingCapturedFrame(const int32_t id, const webrtc::VideoFrame& aVideoFrame)
{
return DeliverFrame(const_cast<uint8_t*>(webrtc_frame.buffer(webrtc::kYPlane)),
CalcBufferSize(webrtc::kI420, webrtc_frame.width(), webrtc_frame.height()),
webrtc_frame.timestamp(),
webrtc_frame.ntp_time_ms(),
webrtc_frame.render_time_ms(),
(void*) webrtc_frame.native_handle());
LOG_VERBOSE((__PRETTY_FUNCTION__));
RenderFrame(id,aVideoFrame);
}
void
CallbackHelper::OnCaptureDelayChanged(const int32_t id, const int32_t delay)
{
LOG((__PRETTY_FUNCTION__));
}
bool
@ -361,15 +307,17 @@ CamerasParent::RecvReleaseFrame(mozilla::ipc::Shmem&& s) {
bool
CamerasParent::SetupEngine(CaptureEngine aCapEngine)
{
LOG((__PRETTY_FUNCTION__));
MOZ_ASSERT(mVideoCaptureThread->thread_id() == PlatformThread::CurrentId());
EngineHelper *helper = &mEngines[aCapEngine];
RefPtr<mozilla::camera::VideoEngine>* engine = &mEngines[aCapEngine];
// Already initialized
if (helper->mEngine) {
if (engine->get()) {
return true;
}
webrtc::CaptureDeviceInfo *captureDeviceInfo = nullptr;
UniquePtr<webrtc::Config> config(new webrtc::Config);
switch (aCapEngine) {
case ScreenEngine:
@ -398,43 +346,19 @@ CamerasParent::SetupEngine(CaptureEngine aCapEngine)
break;
}
helper->mConfig.Set<webrtc::CaptureDeviceInfo>(captureDeviceInfo);
helper->mEngine = webrtc::VideoEngine::Create(helper->mConfig);
config->Set<webrtc::CaptureDeviceInfo>(captureDeviceInfo);
*engine = mozilla::camera::VideoEngine::Create(UniquePtr<const webrtc::Config>(config.release()));
if (!helper->mEngine) {
if (!engine->get()) {
LOG(("VideoEngine::Create failed"));
return false;
}
helper->mPtrViEBase = webrtc::ViEBase::GetInterface(helper->mEngine);
if (!helper->mPtrViEBase) {
LOG(("ViEBase::GetInterface failed"));
return false;
}
if (helper->mPtrViEBase->Init() < 0) {
LOG(("ViEBase::Init failed"));
return false;
}
helper->mPtrViECapture = webrtc::ViECapture::GetInterface(helper->mEngine);
if (!helper->mPtrViECapture) {
LOG(("ViECapture::GetInterface failed"));
return false;
}
RefPtr<InputObserver>* observer = mObservers.AppendElement(new InputObserver(this));
#ifdef DEBUG
MOZ_ASSERT(0 == helper->mPtrViECapture->RegisterInputObserver(observer->get()));
#else
helper->mPtrViECapture->RegisterInputObserver(observer->get());
#endif
helper->mPtrViERender = webrtc::ViERender::GetInterface(helper->mEngine);
if (!helper->mPtrViERender) {
LOG(("ViERender::GetInterface failed"));
return false;
auto device_info = engine->get()->GetOrCreateVideoCaptureDeviceInfo();
MOZ_ASSERT(device_info);
if (device_info) {
device_info->RegisterVideoInputFeedBack(**observer);
}
return true;
@ -452,38 +376,25 @@ CamerasParent::CloseEngines()
// Stop the callers
while (mCallbacks.Length()) {
auto capEngine = mCallbacks[0]->mCapEngine;
auto capNum = mCallbacks[0]->mCapturerId;
LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, capNum));
StopCapture(capEngine, capNum);
Unused << ReleaseCaptureDevice(capEngine, capNum);
auto streamNum = mCallbacks[0]->mStreamId;
LOG(("Forcing shutdown of engine %d, capturer %d", capEngine, streamNum));
StopCapture(capEngine, streamNum);
Unused << ReleaseCaptureDevice(capEngine, streamNum);
}
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
if (mEngines[i].mEngineIsRunning) {
LOG(("Being closed down while engine %d is running!", i));
}
if (mEngines[i].mPtrViERender) {
mEngines[i].mPtrViERender->Release();
mEngines[i].mPtrViERender = nullptr;
}
if (mEngines[i].mPtrViECapture) {
#ifdef DEBUG
MOZ_ASSERT(0 == mEngines[i].mPtrViECapture->DeregisterInputObserver());
#else
mEngines[i].mPtrViECapture->DeregisterInputObserver();
#endif
if (auto engine = mEngines[i].get() ){
if (engine->IsRunning()) {
LOG(("Being closed down while engine %d is running!", i));
}
mEngines[i].mPtrViECapture->Release();
mEngines[i].mPtrViECapture = nullptr;
}
if(mEngines[i].mPtrViEBase) {
mEngines[i].mPtrViEBase->Release();
mEngines[i].mPtrViEBase = nullptr;
}
if (mEngines[i].mEngine) {
mEngines[i].mEngine->SetTraceCallback(nullptr);
webrtc::VideoEngine::Delete(mEngines[i].mEngine);
mEngines[i].mEngine = nullptr;
auto device_info = engine->GetOrCreateVideoCaptureDeviceInfo();
MOZ_ASSERT(device_info);
if (device_info) {
device_info->DeRegisterVideoInputFeedBack();
}
mozilla::camera::VideoEngine::Delete(engine);
mEngines[i] = nullptr;
}
}
@ -492,21 +403,21 @@ CamerasParent::CloseEngines()
mWebRTCAlive = false;
}
bool
VideoEngine *
CamerasParent::EnsureInitialized(int aEngine)
{
LOG((__PRETTY_FUNCTION__));
LOG_VERBOSE((__PRETTY_FUNCTION__));
// We're shutting down, don't try to do new WebRTC ops.
if (!mWebRTCAlive) {
return false;
return nullptr;
}
CaptureEngine capEngine = static_cast<CaptureEngine>(aEngine);
if (!SetupEngine(capEngine)) {
LOG(("CamerasParent failed to initialize engine"));
return false;
return nullptr;
}
return true;
return mEngines[aEngine];
}
// Dispatch the runnable to do the camera operation on the
@ -518,13 +429,15 @@ bool
CamerasParent::RecvNumberOfCaptureDevices(const CaptureEngine& aCapEngine)
{
LOG((__PRETTY_FUNCTION__));
LOG(("CaptureEngine=%d", aCapEngine));
RefPtr<CamerasParent> self(this);
RefPtr<Runnable> webrtc_runnable =
media::NewRunnableFrom([self, aCapEngine]() -> nsresult {
int num = -1;
if (self->EnsureInitialized(aCapEngine)) {
num = self->mEngines[aCapEngine].mPtrViECapture->NumberOfCaptureDevices();
if (auto engine = self->EnsureInitialized(aCapEngine)) {
if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
num = devInfo->NumberOfDevices();
}
}
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, num]() -> nsresult {
@ -591,11 +504,10 @@ CamerasParent::RecvNumberOfCapabilities(const CaptureEngine& aCapEngine,
RefPtr<Runnable> webrtc_runnable =
media::NewRunnableFrom([self, unique_id, aCapEngine]() -> nsresult {
int num = -1;
if (self->EnsureInitialized(aCapEngine)) {
num =
self->mEngines[aCapEngine].mPtrViECapture->NumberOfCapabilities(
unique_id.get(),
MediaEngineSource::kMaxUniqueIdLength);
if (auto engine = self->EnsureInitialized(aCapEngine)) {
if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
num = devInfo->NumberOfCapabilities(unique_id.get());
}
}
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, num]() -> nsresult {
@ -630,18 +542,19 @@ CamerasParent::RecvGetCaptureCapability(const CaptureEngine& aCapEngine,
RefPtr<CamerasParent> self(this);
RefPtr<Runnable> webrtc_runnable =
media::NewRunnableFrom([self, unique_id, aCapEngine, num]() -> nsresult {
webrtc::CaptureCapability webrtcCaps;
webrtc::VideoCaptureCapability webrtcCaps;
int error = -1;
if (self->EnsureInitialized(aCapEngine)) {
error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureCapability(
unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, num, webrtcCaps);
if (auto engine = self->EnsureInitialized(aCapEngine)) {
if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()){
error = devInfo->GetCapability(unique_id.get(), num, webrtcCaps);
}
}
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, webrtcCaps, error]() -> nsresult {
if (self->IsShuttingDown()) {
return NS_ERROR_FAILURE;
}
CaptureCapability capCap(webrtcCaps.width,
VideoCaptureCapability capCap(webrtcCaps.width,
webrtcCaps.height,
webrtcCaps.maxFPS,
webrtcCaps.expectedCaptureDelay,
@ -682,15 +595,15 @@ CamerasParent::RecvGetCaptureDevice(const CaptureEngine& aCapEngine,
char deviceUniqueId[MediaEngineSource::kMaxUniqueIdLength];
nsCString name;
nsCString uniqueId;
int devicePid = 0;
pid_t devicePid = 0;
int error = -1;
if (self->EnsureInitialized(aCapEngine)) {
error = self->mEngines[aCapEngine].mPtrViECapture->GetCaptureDevice(aListNumber,
deviceName,
sizeof(deviceName),
deviceUniqueId,
sizeof(deviceUniqueId),
&devicePid);
if (auto engine = self->EnsureInitialized(aCapEngine)) {
if (auto devInfo = engine->GetOrCreateVideoCaptureDeviceInfo()) {
error = devInfo->GetDeviceName(aListNumber, deviceName, sizeof(deviceName),
deviceUniqueId, sizeof(deviceUniqueId),
nullptr, 0,
&devicePid);
}
}
if (!error) {
name.Assign(deviceName);
@ -806,8 +719,17 @@ CamerasParent::RecvAllocateCaptureDevice(const CaptureEngine& aCapEngine,
int numdev = -1;
int error = -1;
if (allowed && self->EnsureInitialized(aCapEngine)) {
error = self->mEngines[aCapEngine].mPtrViECapture->AllocateCaptureDevice(
unique_id.get(), MediaEngineSource::kMaxUniqueIdLength, numdev);
auto engine = self->mEngines[aCapEngine].get();
engine->CreateVideoCapture(numdev, unique_id.get());
engine->WithEntry(numdev, [&error](VideoEngine::CaptureEntry& cap) {
if (cap.VideoCapture()) {
if (!cap.VideoRenderer()) {
LOG(("VideoEngine::VideoRenderer() failed"));
} else {
error = 0;
}
}
});
}
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, numdev, error]() -> nsresult {
@ -838,8 +760,8 @@ CamerasParent::ReleaseCaptureDevice(const CaptureEngine& aCapEngine,
const int& capnum)
{
int error = -1;
if (EnsureInitialized(aCapEngine)) {
error = mEngines[aCapEngine].mPtrViECapture->ReleaseCaptureDevice(capnum);
if (auto engine = EnsureInitialized(aCapEngine)) {
error = engine->ReleaseVideoCapture(capnum);
}
return error;
}
@ -881,44 +803,48 @@ CamerasParent::RecvReleaseCaptureDevice(const CaptureEngine& aCapEngine,
bool
CamerasParent::RecvStartCapture(const CaptureEngine& aCapEngine,
const int& capnum,
const CaptureCapability& ipcCaps)
const VideoCaptureCapability& ipcCaps)
{
LOG((__PRETTY_FUNCTION__));
RefPtr<CamerasParent> self(this);
RefPtr<Runnable> webrtc_runnable =
media::NewRunnableFrom([self, aCapEngine, capnum, ipcCaps]() -> nsresult {
LOG((__PRETTY_FUNCTION__));
CallbackHelper** cbh;
webrtc::ExternalRenderer* render;
EngineHelper* helper = nullptr;
webrtc::VideoRenderCallback* render;
VideoEngine* engine = nullptr;
int error = -1;
if (self->EnsureInitialized(aCapEngine)) {
cbh = self->mCallbacks.AppendElement(
new CallbackHelper(static_cast<CaptureEngine>(aCapEngine), capnum, self));
render = static_cast<webrtc::ExternalRenderer*>(*cbh);
render = static_cast<webrtc::VideoRenderCallback*>(*cbh);
helper = &self->mEngines[aCapEngine];
error =
helper->mPtrViERender->AddRenderer(capnum, webrtc::kVideoI420, render);
if (!error) {
error = helper->mPtrViERender->StartRender(capnum);
}
engine = self->mEngines[aCapEngine];
engine->WithEntry(capnum, [capnum, &render, &engine, &error, &ipcCaps, &cbh](VideoEngine::CaptureEntry& cap) {
cap.VideoRenderer()->AddIncomingRenderStream(capnum,0, 0., 0., 1., 1.);
error = cap.VideoRenderer()->AddExternalRenderCallback(capnum, render);
if (!error) {
error = cap.VideoRenderer()->StartRender(capnum);
}
webrtc::CaptureCapability capability;
capability.width = ipcCaps.width();
capability.height = ipcCaps.height();
capability.maxFPS = ipcCaps.maxFPS();
capability.expectedCaptureDelay = ipcCaps.expectedCaptureDelay();
capability.rawType = static_cast<webrtc::RawVideoType>(ipcCaps.rawType());
capability.codecType = static_cast<webrtc::VideoCodecType>(ipcCaps.codecType());
capability.interlaced = ipcCaps.interlaced();
webrtc::VideoCaptureCapability capability;
capability.width = ipcCaps.width();
capability.height = ipcCaps.height();
capability.maxFPS = ipcCaps.maxFPS();
capability.expectedCaptureDelay = ipcCaps.expectedCaptureDelay();
capability.rawType = static_cast<webrtc::RawVideoType>(ipcCaps.rawType());
capability.codecType = static_cast<webrtc::VideoCodecType>(ipcCaps.codecType());
capability.interlaced = ipcCaps.interlaced();
if (!error) {
error = helper->mPtrViECapture->StartCapture(capnum, capability);
}
if (!error) {
helper->mEngineIsRunning = true;
}
if (!error) {
error = cap.VideoCapture()->StartCapture(capability);
}
if (!error) {
engine->Startup();
cap.VideoCapture()->RegisterCaptureDataCallback(*static_cast<webrtc::VideoCaptureDataCallback*>(*cbh));
}
});
}
RefPtr<nsIRunnable> ipc_runnable =
media::NewRunnableFrom([self, error]() -> nsresult {
@ -944,20 +870,27 @@ void
CamerasParent::StopCapture(const CaptureEngine& aCapEngine,
const int& capnum)
{
if (EnsureInitialized(aCapEngine)) {
mEngines[aCapEngine].mPtrViECapture->StopCapture(capnum);
mEngines[aCapEngine].mPtrViERender->StopRender(capnum);
mEngines[aCapEngine].mPtrViERender->RemoveRenderer(capnum);
mEngines[aCapEngine].mEngineIsRunning = false;
for (size_t i = 0; i < mCallbacks.Length(); i++) {
if (mCallbacks[i]->mCapEngine == aCapEngine
&& mCallbacks[i]->mCapturerId == capnum) {
delete mCallbacks[i];
mCallbacks.RemoveElementAt(i);
if (auto engine = EnsureInitialized(aCapEngine)) {
engine->WithEntry(capnum,[capnum](VideoEngine::CaptureEntry& cap){
if (cap.VideoCapture()) {
cap.VideoCapture()->StopCapture();
cap.VideoCapture()->DeRegisterCaptureDataCallback();
}
if (cap.VideoRenderer()) {
cap.VideoRenderer()->StopRender(capnum);
}
});
// we're removing elements, iterate backwards
for (size_t i = mCallbacks.Length(); i > 0; i--) {
if (mCallbacks[i-1]->mCapEngine == aCapEngine
&& mCallbacks[i-1]->mStreamId == (uint32_t) capnum) {
delete mCallbacks[i-1];
mCallbacks.RemoveElementAt(i-1);
break;
}
}
engine->RemoveRenderer(capnum);
engine->Shutdown();
}
}
@ -1077,7 +1010,7 @@ CamerasParent::~CamerasParent()
// That runnable takes a ref to us, so it must have finished
// by the time we get here.
for (int i = 0; i < CaptureEngine::MaxEngine; i++) {
MOZ_ASSERT(!mEngines[i].mEngine);
MOZ_ASSERT(!mEngines[i]);
}
#endif
}

View file

@ -7,19 +7,21 @@
#define mozilla_CamerasParent_h
#include "nsIObserver.h"
#include "VideoEngine.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/camera/PCamerasParent.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/ShmemPool.h"
#include "mozilla/Atomics.h"
#include "webrtc/modules/video_capture/video_capture.h"
#include "webrtc/modules/video_render/video_render_impl.h"
#include "webrtc/modules/video_capture/video_capture_defines.h"
#include "webrtc/common_video/include/incoming_video_stream.h"
// conflicts with #include of scoped_ptr.h
#undef FF
#include "webrtc/common.h"
// Video Engine
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "CamerasChild.h"
#include "base/thread.h"
@ -29,60 +31,43 @@ namespace camera {
class CamerasParent;
class CallbackHelper : public webrtc::ExternalRenderer
class CallbackHelper :
public webrtc::VideoRenderCallback,
public webrtc::VideoCaptureDataCallback
{
public:
CallbackHelper(CaptureEngine aCapEng, int aCapId, CamerasParent *aParent)
: mCapEngine(aCapEng), mCapturerId(aCapId), mParent(aParent) {};
CallbackHelper(CaptureEngine aCapEng, uint32_t aStreamId, CamerasParent *aParent)
: mCapEngine(aCapEng), mStreamId(aStreamId), mParent(aParent) {};
// ViEExternalRenderer implementation. These callbacks end up
// running on the VideoCapture thread.
virtual int FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams) override;
virtual int DeliverFrame(unsigned char* buffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle) override;
virtual int DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame) override;
virtual bool IsTextureSupported() override { return false; };
virtual int32_t RenderFrame(const uint32_t aStreamId, const webrtc::VideoFrame& video_frame) override;
// From VideoCaptureCallback
virtual void OnIncomingCapturedFrame(const int32_t id, const webrtc::VideoFrame& videoFrame) override;
virtual void OnCaptureDelayChanged(const int32_t id, const int32_t delay) override;
// TODO(@@NG) This is now part of webrtc::VideoRenderer, not in the webrtc::VideoRenderCallback
// virtual bool IsTextureSupported() const override { return false; };
//
// virtual bool SmoothsRenderedFrames() const override { return false; }
friend CamerasParent;
private:
CaptureEngine mCapEngine;
int mCapturerId;
uint32_t mStreamId;
CamerasParent *mParent;
};
class EngineHelper
{
public:
EngineHelper() :
mEngine(nullptr), mPtrViEBase(nullptr), mPtrViECapture(nullptr),
mPtrViERender(nullptr), mEngineIsRunning(false) {};
webrtc::VideoEngine *mEngine;
webrtc::ViEBase *mPtrViEBase;
webrtc::ViECapture *mPtrViECapture;
webrtc::ViERender *mPtrViERender;
// The webrtc code keeps a reference to this one.
webrtc::Config mConfig;
// Engine alive
bool mEngineIsRunning;
};
class InputObserver : public webrtc::ViEInputObserver
class InputObserver : public webrtc::VideoInputFeedBack
{
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InputObserver)
explicit InputObserver(CamerasParent* aParent)
: mParent(aParent) {};
virtual void DeviceChange();
virtual void OnDeviceChange();
friend CamerasParent;
@ -113,7 +98,7 @@ public:
const int&) override;
virtual bool RecvGetCaptureDevice(const CaptureEngine&, const int&) override;
virtual bool RecvStartCapture(const CaptureEngine&, const int&,
const CaptureCapability&) override;
const VideoCaptureCapability&) override;
virtual bool RecvStopCapture(const CaptureEngine&, const int&) override;
virtual bool RecvReleaseFrame(mozilla::ipc::Shmem&&) override;
virtual bool RecvAllDone() override;
@ -128,13 +113,10 @@ public:
// helper to forward to the PBackground thread
int DeliverFrameOverIPC(CaptureEngine capEng,
int cap_id,
uint32_t aStreamId,
ShmemBuffer buffer,
unsigned char* altbuffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time);
VideoFrameProperties& aProps);
CamerasParent();
@ -147,14 +129,14 @@ protected:
int ReleaseCaptureDevice(const CaptureEngine& aCapEngine, const int& capnum);
bool SetupEngine(CaptureEngine aCapEngine);
bool EnsureInitialized(int aEngine);
VideoEngine* EnsureInitialized(int aEngine);
void CloseEngines();
void StopIPC();
void StopVideoCapture();
// Can't take already_AddRefed because it can fail in stupid ways.
nsresult DispatchToVideoCaptureThread(Runnable* event);
EngineHelper mEngines[CaptureEngine::MaxEngine];
RefPtr<VideoEngine> mEngines[CaptureEngine::MaxEngine];
nsTArray<CallbackHelper*> mCallbacks;
// image buffers

View file

@ -14,8 +14,8 @@
#include "nsIObserver.h"
#include "webrtc/common_types.h"
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/call.h"
#include "webrtc/video/overuse_frame_detector.h"
extern mozilla::LazyLogModule gLoadManagerLog;
namespace mozilla {
@ -77,7 +77,7 @@ private:
};
class LoadManager final : public webrtc::CPULoadStateCallbackInvoker,
public webrtc::CpuOveruseObserver
public webrtc::LoadObserver
{
public:
explicit LoadManager(LoadManagerSingleton* aManager)
@ -93,13 +93,14 @@ public:
{
mManager->RemoveObserver(aObserver);
}
void OveruseDetected() override
void OnLoadUpdate(webrtc::LoadObserver::Load load_state) override
{
mManager->OveruseDetected();
}
void NormalUsage() override
{
mManager->NormalUsage();
if (load_state == webrtc::LoadObserver::kOveruse) {
mManager->OveruseDetected();
} else if (load_state == webrtc::LoadObserver::kUnderuse) {
mManager->NormalUsage();
}
}
private:

View file

@ -10,7 +10,8 @@ using mozilla::camera::CaptureEngine from "mozilla/media/CamerasTypes.h";
namespace mozilla {
namespace camera {
struct CaptureCapability
// IPC analog for webrtc::VideoCaptureCapability
struct VideoCaptureCapability
{
int width;
int height;
@ -21,6 +22,32 @@ struct CaptureCapability
bool interlaced;
};
// IPC analog for webrtc::VideoFrame
// the described buffer is transported seperately in a Shmem
// See VideoFrameUtils.h
struct VideoFrameProperties
{
// Size of image data within the ShMem,
// the ShMem is at least this large
uint32_t bufferSize;
// From webrtc::VideoFrame
uint32_t timeStamp;
int64_t ntpTimeMs;
int64_t renderTimeMs;
// See webrtc/**/rotation.h
int rotation;
int yAllocatedSize;
int uAllocatedSize;
int vAllocatedSize;
// From webrtc::VideoFrameBuffer
int width;
int height;
int yStride;
int uStride;
int vStride;
};
async protocol PCameras
{
manager PBackground;
@ -28,14 +55,13 @@ async protocol PCameras
child:
async FrameSizeChange(CaptureEngine capEngine, int cap_id, int w, int h);
// transfers ownership of |buffer| from parent to child
async DeliverFrame(CaptureEngine capEngine, int cap_id,
Shmem buffer, size_t size, uint32_t time_stamp,
int64_t ntp_time, int64_t render_time);
async DeliverFrame(CaptureEngine capEngine, int streamId,
Shmem buffer, VideoFrameProperties props);
async DeviceChange();
async ReplyNumberOfCaptureDevices(int numdev);
async ReplyNumberOfCapabilities(int numdev);
async ReplyAllocateCaptureDevice(int numdev);
async ReplyGetCaptureCapability(CaptureCapability cap);
async ReplyGetCaptureCapability(VideoCaptureCapability cap);
async ReplyGetCaptureDevice(nsCString device_name, nsCString device_id, bool scary);
async ReplyFailure();
async ReplySuccess();
@ -45,12 +71,13 @@ parent:
async NumberOfCaptureDevices(CaptureEngine engine);
async NumberOfCapabilities(CaptureEngine engine, nsCString deviceUniqueIdUTF8);
async GetCaptureCapability(CaptureEngine engine, nsCString unique_idUTF8, int capability_number);
async GetCaptureCapability(CaptureEngine engine, nsCString unique_idUTF8,
int capability_number);
async GetCaptureDevice(CaptureEngine engine, int num);
async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8, nsCString origin);
async ReleaseCaptureDevice(CaptureEngine engine, int numdev);
async StartCapture(CaptureEngine engine, int numdev, CaptureCapability capability);
async StartCapture(CaptureEngine engine, int numdev, VideoCaptureCapability capability);
async StopCapture(CaptureEngine engine, int numdev);
// transfers frame back
async ReleaseFrame(Shmem s);

View file

@ -39,7 +39,7 @@ mozilla::ShmemBuffer ShmemPool::GetIfAvailable(size_t aSize)
MOZ_ASSERT(res.mShmem.IsWritable(), "Pool in Shmem is not writable?");
if (res.mShmem.Size<char>() < aSize) {
if (res.mShmem.Size<uint8_t>() < aSize) {
LOG(("Free Shmem but not of the right size"));
return ShmemBuffer();
}
@ -64,7 +64,7 @@ void ShmemPool::Put(ShmemBuffer&& aShmem)
#ifdef DEBUG
size_t poolUse = mShmemPool.Length() - mPoolFree;
if (poolUse > 0) {
LOG(("ShmemPool usage reduced to %d buffers", poolUse));
LOG_VERBOSE(("ShmemPool usage reduced to %d buffers", poolUse));
}
#endif
}

View file

@ -47,8 +47,8 @@ public:
return mInitialized;
}
char* GetBytes() {
return mShmem.get<char>();
uint8_t * GetBytes() {
return mShmem.get<uint8_t>();
}
mozilla::ipc::Shmem& Get() {

View file

@ -0,0 +1,185 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VideoEngine.h"
#include "webrtc/video_engine/browser_capture_impl.h"
#ifdef WEBRTC_ANDROID
#include "webrtc/modules/video_capture/video_capture.h"
#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
#include "webrtc/modules/video_render/video_render.h"
#endif
#endif
namespace mozilla {
namespace camera {
#undef LOG
#undef LOG_ENABLED
mozilla::LazyLogModule gVideoEngineLog("VideoEngine");
#define LOG(args) MOZ_LOG(gVideoEngineLog, mozilla::LogLevel::Debug, args)
#define LOG_ENABLED() MOZ_LOG_TEST(gVideoEngineLog, mozilla::LogLevel::Debug)
int VideoEngine::sId = 0;
#if defined(ANDROID)
int VideoEngine::SetAndroidObjects(JavaVM* javaVM) {
LOG((__PRETTY_FUNCTION__));
if (webrtc::SetCaptureAndroidVM(javaVM) != 0) {
LOG(("Could not set capture Android VM"));
return -1;
}
#ifdef WEBRTC_INCLUDE_INTERNAL_VIDEO_RENDER
if (webrtc::SetRenderAndroidVM(javaVM) != 0) {
LOG(("Could not set render Android VM"));
return -1;
}
#endif
return 0;
}
#endif
void
VideoEngine::CreateVideoCapture(int32_t& id, const char* deviceUniqueIdUTF8) {
LOG((__PRETTY_FUNCTION__));
id = GenerateId();
LOG(("CaptureDeviceInfo.type=%s id=%d",mCaptureDevInfo.TypeName(),id));
CaptureEntry entry = {-1,nullptr,nullptr};
if (mCaptureDevInfo.type == webrtc::CaptureDeviceType::Camera) {
entry = CaptureEntry(id,
webrtc::VideoCaptureFactory::Create(id, deviceUniqueIdUTF8),
nullptr);
} else {
#ifndef WEBRTC_ANDROID
entry = CaptureEntry(
id,
webrtc::DesktopCaptureImpl::Create(id, deviceUniqueIdUTF8, mCaptureDevInfo.type),
nullptr);
#else
MOZ_ASSERT("CreateVideoCapture NO DESKTOP CAPTURE IMPL ON ANDROID" == nullptr);
#endif
}
mCaps.emplace(id,std::move(entry));
}
int
VideoEngine::ReleaseVideoCapture(const int32_t id) {
bool found = false;
WithEntry(id, [&found](CaptureEntry& cap) {
cap.mVideoCaptureModule = nullptr;
found = true;
});
return found ? 0 : (-1);
}
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo>
VideoEngine::GetOrCreateVideoCaptureDeviceInfo() {
if (mDeviceInfo) {
return mDeviceInfo;
}
switch (mCaptureDevInfo.type) {
case webrtc::CaptureDeviceType::Camera: {
mDeviceInfo.reset(webrtc::VideoCaptureFactory::CreateDeviceInfo(0));
break;
}
case webrtc::CaptureDeviceType::Browser: {
mDeviceInfo.reset(webrtc::BrowserDeviceInfoImpl::CreateDeviceInfo());
break;
}
// Window, Application, and Screen types are handled by DesktopCapture
case webrtc::CaptureDeviceType::Window:
case webrtc::CaptureDeviceType::Application:
case webrtc::CaptureDeviceType::Screen: {
#if !defined(WEBRTC_ANDROID) && !defined(WEBRTC_IOS)
mDeviceInfo.reset(webrtc::DesktopCaptureImpl::CreateDeviceInfo(mId,mCaptureDevInfo.type));
#else
MOZ_ASSERT("GetVideoCaptureDeviceInfo NO DESKTOP CAPTURE IMPL ON ANDROID" == nullptr);
mDeviceInfo.reset();
#endif
break;
}
}
return mDeviceInfo;
}
void
VideoEngine::RemoveRenderer(int capnum) {
WithEntry(capnum, [](CaptureEntry& cap) {
cap.mVideoRender = nullptr;
});
}
const UniquePtr<const webrtc::Config>&
VideoEngine::GetConfiguration() {
return mConfig;
}
RefPtr<VideoEngine> VideoEngine::Create(UniquePtr<const webrtc::Config>&& aConfig) {
LOG((__PRETTY_FUNCTION__));
LOG(("Creating new VideoEngine with CaptureDeviceType %s",
aConfig->Get<webrtc::CaptureDeviceInfo>().TypeName()));
RefPtr<VideoEngine> engine(new VideoEngine(std::move(aConfig)));
return engine;
}
VideoEngine::CaptureEntry::CaptureEntry(int32_t aCapnum,
rtc::scoped_refptr<webrtc::VideoCaptureModule> aCapture,
webrtc::VideoRender * aRenderer):
mCapnum(aCapnum),
mVideoCaptureModule(aCapture),
mVideoRender(aRenderer)
{}
rtc::scoped_refptr<webrtc::VideoCaptureModule>
VideoEngine::CaptureEntry::VideoCapture() {
return mVideoCaptureModule;
}
const UniquePtr<webrtc::VideoRender>&
VideoEngine::CaptureEntry::VideoRenderer() {
if (!mVideoRender) {
MOZ_ASSERT(mCapnum != -1);
// Create a VideoRender on demand
mVideoRender = UniquePtr<webrtc::VideoRender>(
webrtc::VideoRender::CreateVideoRender(mCapnum,nullptr,false,webrtc::kRenderExternal));
}
return mVideoRender;
}
int32_t
VideoEngine::CaptureEntry::Capnum() const {
return mCapnum;
}
bool VideoEngine::WithEntry(const int32_t entryCapnum,
const std::function<void(CaptureEntry &entry)>&& fn) {
auto it = mCaps.find(entryCapnum);
if (it == mCaps.end()) {
return false;
}
fn(it->second);
return true;
}
int32_t
VideoEngine::GenerateId() {
// XXX Something better than this (a map perhaps, or a simple boolean TArray, given
// the number in-use is O(1) normally!)
return mId = sId++;
}
VideoEngine::VideoEngine(UniquePtr<const webrtc::Config>&& aConfig):
mCaptureDevInfo(aConfig->Get<webrtc::CaptureDeviceInfo>()),
mDeviceInfo(nullptr),
mConfig(std::move(aConfig))
{
LOG((__PRETTY_FUNCTION__));
}
}
}

View file

@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_VideoEngine_h
#define mozilla_VideoEngine_h
#include "MediaEngine.h"
#include "VideoFrameUtils.h"
#include "mozilla/media/MediaUtils.h"
#include "webrtc/common.h"
#include "webrtc/modules/video_capture/video_capture_impl.h"
#include "webrtc/modules/video_render/video_render.h"
#include "webrtc/modules/video_capture/video_capture_defines.h"
#include "webrtc/modules/video_capture/video_capture_factory.h"
#include "webrtc/video_engine/desktop_capture_impl.h"
#include <memory>
#include <functional>
namespace mozilla {
namespace camera {
// Historically the video engine was part of webrtc
// it was removed (and reimplemented in Talk)
class VideoEngine
{
private:
virtual ~VideoEngine (){};
public:
VideoEngine (){};
NS_INLINE_DECL_REFCOUNTING(VideoEngine)
static RefPtr<VideoEngine> Create(UniquePtr<const webrtc::Config>&& aConfig);
#if defined(ANDROID)
static int SetAndroidObjects(JavaVM* javaVM);
#endif
void CreateVideoCapture(int32_t& id, const char* deviceUniqueIdUTF8);
int ReleaseVideoCapture(const int32_t id);
// VideoEngine is responsible for any cleanup in its modules
static void Delete(VideoEngine * engine) { }
/** Returns or creates a new new DeviceInfo.
* It is cached to prevent repeated lengthy polling for "realness"
* of the hardware devices. This could be handled in a more elegant
* way in the future.
* @return on failure the shared_ptr will be null, otherwise it will contain a DeviceInfo.
* @see bug 1305212 https://bugzilla.mozilla.org/show_bug.cgi?id=1305212
*/
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> GetOrCreateVideoCaptureDeviceInfo();
void RemoveRenderer(int capnum);
const UniquePtr<const webrtc::Config>& GetConfiguration();
void Startup() {
mIsRunning = true;
}
void Shutdown() {
mIsRunning = false;
}
bool IsRunning() const {
return mIsRunning;
}
class CaptureEntry {
public:
CaptureEntry(int32_t aCapnum,
rtc::scoped_refptr<webrtc::VideoCaptureModule> aCapture,
webrtc::VideoRender* aRenderer);
int32_t Capnum() const;
rtc::scoped_refptr<webrtc::VideoCaptureModule> VideoCapture();
const UniquePtr<webrtc::VideoRender> & VideoRenderer();
private:
int32_t mCapnum;
rtc::scoped_refptr<webrtc::VideoCaptureModule> mVideoCaptureModule;
UniquePtr<webrtc::VideoRender> mVideoRender;
friend class VideoEngine;
};
// Returns true iff an entry for capnum exists
bool WithEntry(const int32_t entryCapnum, const std::function<void(CaptureEntry &entry)>&& fn);
private:
explicit VideoEngine(UniquePtr<const webrtc::Config>&& aConfig);
bool mIsRunning;
int32_t mId;
webrtc::CaptureDeviceInfo mCaptureDevInfo;
std::shared_ptr<webrtc::VideoCaptureModule::DeviceInfo> mDeviceInfo;
UniquePtr<const webrtc::Config> mConfig;
std::map<int32_t, CaptureEntry> mCaps;
int32_t GenerateId();
static int32_t sId;
};
}
}
#endif

View file

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "VideoFrameUtils.h"
#include "webrtc/video_frame.h"
#include "mozilla/ShmemPool.h"
namespace mozilla {
size_t
VideoFrameUtils::TotalRequiredBufferSize(
const webrtc::VideoFrame& aVideoFrame)
{
static const webrtc::PlaneType kPlanes[] =
{webrtc::kYPlane, webrtc::kUPlane, webrtc::kVPlane};
if (aVideoFrame.IsZeroSize()) {
return 0;
}
size_t sum = 0;
for (auto plane : kPlanes) {
sum += aVideoFrame.allocated_size(plane);
}
return sum;
}
void VideoFrameUtils::InitFrameBufferProperties(
const webrtc::VideoFrame& aVideoFrame,
camera::VideoFrameProperties& aDestProps)
{
// The VideoFrameBuffer image data stored in the accompanying buffer
// the buffer is at least this size of larger.
aDestProps.bufferSize() = TotalRequiredBufferSize(aVideoFrame);
aDestProps.timeStamp() = aVideoFrame.timestamp();
aDestProps.ntpTimeMs() = aVideoFrame.ntp_time_ms();
aDestProps.renderTimeMs() = aVideoFrame.render_time_ms();
aDestProps.rotation() = aVideoFrame.rotation();
aDestProps.yAllocatedSize() = aVideoFrame.allocated_size(webrtc::kYPlane);
aDestProps.uAllocatedSize() = aVideoFrame.allocated_size(webrtc::kYPlane);
aDestProps.vAllocatedSize() = aVideoFrame.allocated_size(webrtc::kYPlane);
aDestProps.width() = aVideoFrame.width();
aDestProps.height() = aVideoFrame.height();
aDestProps.yStride() = aVideoFrame.stride(webrtc::kYPlane);
aDestProps.uStride() = aVideoFrame.stride(webrtc::kUPlane);
aDestProps.vStride() = aVideoFrame.stride(webrtc::kVPlane);
}
void VideoFrameUtils::CopyVideoFrameBuffers(uint8_t* aDestBuffer,
const size_t aDestBufferSize,
const webrtc::VideoFrame& aFrame)
{
static const webrtc::PlaneType planes[] = {webrtc::kYPlane, webrtc::kUPlane, webrtc::kVPlane};
size_t aggregateSize = TotalRequiredBufferSize(aFrame);
MOZ_ASSERT(aDestBufferSize >= aggregateSize);
// If planes are ordered YUV and contiguous then do a single copy
if ((aFrame.buffer(webrtc::kYPlane) != nullptr)
// Check that the three planes are ordered
&& (aFrame.buffer(webrtc::kYPlane) < aFrame.buffer(webrtc::kUPlane))
&& (aFrame.buffer(webrtc::kUPlane) < aFrame.buffer(webrtc::kVPlane))
// Check that the last plane ends at firstPlane[totalsize]
&& (&aFrame.buffer(webrtc::kYPlane)[aggregateSize] == &aFrame.buffer(webrtc::kVPlane)[aFrame.allocated_size(webrtc::kVPlane)]))
{
memcpy(aDestBuffer,aFrame.buffer(webrtc::kYPlane),aggregateSize);
return;
}
// Copy each plane
size_t offset = 0;
for (auto plane: planes) {
memcpy(&aDestBuffer[offset], aFrame.buffer(plane), aFrame.allocated_size(plane));
offset += aFrame.allocated_size(plane);
}
}
void VideoFrameUtils::CopyVideoFrameBuffers(ShmemBuffer& aDestShmem,
const webrtc::VideoFrame& aVideoFrame)
{
CopyVideoFrameBuffers(aDestShmem.Get().get<uint8_t>(), aDestShmem.Get().Size<uint8_t>(), aVideoFrame);
}
}

View file

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_VideoFrameUtil_h
#define mozilla_VideoFrameUtil_h
#include "mozilla/camera/PCameras.h"
namespace webrtc {
class VideoFrame;
}
namespace mozilla
{
class ShmemBuffer;
// Util methods for working with webrtc::VideoFrame(s) and
// the IPC classes that are used to deliver their contents to the
// MediaEnginge
class VideoFrameUtils {
public:
// Returns the total number of bytes necessary to copy a VideoFrame's buffer
// across all planes.
static size_t TotalRequiredBufferSize(const webrtc::VideoFrame & frame);
// Initializes a camera::VideoFrameProperties from a VideoFrameBuffer
static void InitFrameBufferProperties(const webrtc::VideoFrame& aVideoFrame,
camera::VideoFrameProperties & aDestProperties);
// Copies the buffers out of a VideoFrameBuffer into a buffer.
// Attempts to make as few memcopies as possible.
static void CopyVideoFrameBuffers(uint8_t * aDestBuffer,
const size_t aDestBufferSize,
const webrtc::VideoFrame & aVideoFrame);
// Copies the buffers in a VideoFrameBuffer into a Shmem
// returns the eno from the underlying memcpy.
static void CopyVideoFrameBuffers(ShmemBuffer & aDestShmem,
const webrtc::VideoFrame & aVideoFrame);
};
} /* namespace mozilla */
#endif

View file

@ -1,4 +1,4 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
@ -10,6 +10,8 @@ if CONFIG['MOZ_WEBRTC']:
'LoadManager.h',
'LoadManagerFactory.h',
'LoadMonitor.h',
'VideoEngine.h',
'VideoFrameUtils.h'
]
SOURCES += [
'CamerasChild.cpp',
@ -18,6 +20,8 @@ if CONFIG['MOZ_WEBRTC']:
'LoadManagerFactory.cpp',
'LoadMonitor.cpp',
'ShmemPool.cpp',
'VideoEngine.cpp',
'VideoFrameUtils.cpp'
]
LOCAL_INCLUDES += [
'/media/webrtc/signaling',
@ -29,6 +33,9 @@ if CONFIG['OS_TARGET'] == 'WINNT':
else:
DEFINES['WEBRTC_POSIX'] = True
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['WEBRTC_ANDROID'] = True
if CONFIG['OS_TARGET'] == 'Android':
EXPORTS += [

View file

@ -42,7 +42,6 @@ skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulato
skip-if = true # needed by test_enumerateDevices.html on builders
[test_ondevicechange.html]
skip-if = os == 'android'
[test_getUserMedia_active_autoplay.html]
[test_getUserMedia_audioCapture.html]
skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
[test_getUserMedia_addTrackRemoveTrack.html]
@ -99,7 +98,7 @@ skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTCP.html]
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioRequireEOC.html]
skip-if = (android_version == '18' && debug) # android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_basicAudioPcmaPcmuOnly.html]
skip-if = android_version == '18'
[test_peerConnection_basicAudioDynamicPtMissingRtpmap.html]
@ -127,7 +126,7 @@ skip-if = os == 'android' # bug 1043403
[test_peerConnection_bug822674.html]
[test_peerConnection_bug825703.html]
[test_peerConnection_bug827843.html]
skip-if = (android_version == '18' && debug) # android(Bug 1189784, timeouts on 4.3 emulator)
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
[test_peerConnection_bug834153.html]
[test_peerConnection_bug1013809.html]
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)

View file

@ -1415,13 +1415,17 @@ PeerConnectionWrapper.prototype = {
* A promise that resolves when media is flowing.
*/
waitForRtpFlow(track) {
var hasFlow = stats => {
var rtp = stats.get([...stats.keys()].find(key =>
var hasFlow = (stats, retries) => {
info("Checking for stats in " + JSON.stringify(stats) + " for " + track.kind
+ " track " + track.id + ", retry number " + retries);
var rtp = stats.get([...Object.keys(stats)].find(key =>
!stats.get(key).isRemote && stats.get(key).type.endsWith("boundrtp")));
ok(rtp, "Should have RTP stats for track " + track.id);
if (!rtp) {
return false;
}
info("Should have RTP stats for track " + track.id);
info("RTP stats: "+JSON.stringify(rtp));
var nrPackets = rtp[rtp.type == "outboundrtp" ? "packetsSent"
: "packetsReceived"];
info("Track " + track.id + " has " + nrPackets + " " +
@ -1429,12 +1433,44 @@ PeerConnectionWrapper.prototype = {
return nrPackets > 0;
};
info("Checking RTP packet flow for track " + track.id);
// Time between stats checks
var retryInterval = 500;
// Timeout in ms
var timeoutInterval = 30000;
// Check hasFlow at a reasonable interval
var checkStats = new Promise((resolve, reject)=>{
var retries = 0;
var timer = setInterval(()=>{
this._pc.getStats(track).then(stats=>{
if (hasFlow(stats, retries)) {
clearInterval(timer);
ok(true, "RTP flowing for " + track.kind + " track " + track.id);
resolve();
}
retries = retries + 1;
// This is not accurate but it will tear down
// the timer eventually and probably not
// before timeoutInterval has elapsed.
if ((retries * retryInterval) > timeoutInterval) {
clearInterval(timer);
}
});
}, retryInterval);
});
var retry = (delay) => this._pc.getStats(track)
.then(stats => hasFlow(stats)? ok(true, "RTP flowing for track " + track.id) :
wait(delay).then(retry(1000)));
return retry(200);
info("Checking RTP packet flow for track " + track.id);
var retry = Promise.race([checkStats.then(new Promise((resolve, reject)=>{
info("checkStats completed for " + track.kind + " track " + track.id);
resolve();
})),
new Promise((accept,reject)=>wait(timeoutInterval).then(()=>{
info("Timeout checking for stats for track " + track.id + " after " + timeoutInterval + "ms");
reject("Timeout checking for stats for " + track.kind
+ " track " + track.id + " after " + timeoutInterval + "ms");
})
)]);
return retry;
},
/**
@ -1536,7 +1572,9 @@ PeerConnectionWrapper.prototype = {
var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
if (isWinXP) {
todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)");
} else if (!twoMachines) {
} else if (false) { // Bug 1325430 - timestamps aren't working properly in update 49
// else if (!twoMachines) {
// Bug 1225729: On android, sometimes the first RTCP of the first
// test run gets this value, likely because no RTP has been sent yet.
if (res.timestamp != 2085978496000) {
@ -1584,8 +1622,17 @@ PeerConnectionWrapper.prototype = {
ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived");
ok(rem.packetsLost !== undefined, "Rtcp packetsLost");
ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived");
if (!this.disableRtpCountChecking) {
ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets");
if (false) { // Bug 1325430 if (!this.disableRtpCountChecking) {
// no guarantee which one is newer!
// Note: this must change when we add a timestamp field to remote RTCP reports
// and make rem.timestamp be the reception time
if (res.timestamp >= rem.timestamp) {
ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets");
} else {
info("REVERSED timestamps: rec:" +
rem.packetsReceived + " time:" + rem.timestamp + " sent:" + res.packetsSent + " time:" + res.timestamp);
}
// Else we may have received more than outdated Rtcp packetsSent
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
}
ok(rem.jitter !== undefined, "Rtcp jitter");

View file

@ -46,6 +46,18 @@ runNetworkTest(() => {
// i.e., this order of `requestFrame(); draw();` should work.
stream.requestFrame();
h.drawColor(canvas, h.red);
var i = 0;
return setInterval(function() {
try {
info("draw " + i ? "green" : "red");
h.drawColor(canvas, i ? h.green : h.red);
i = 1 - i;
stream.requestFrame();
} catch (e) {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 500);
},
function PC_REMOTE_WAIT_FOR_REMOTE_RED() {
return h.waitForPixelColor(mediaElement, h.red, 128,

View file

@ -52,7 +52,7 @@ runNetworkTest(() => {
if (!program) {
ok(false, "Program should link");
return Promise.reject();
return Promise.reject("Program should link");
}
gl.useProgram(program);
@ -100,6 +100,16 @@ runNetworkTest(() => {
},
function DRAW_LOCAL_RED() {
h.drawColor(canvas, h.red);
return setInterval(function() {
try {
info("draw");
h.drawColor(canvas, h.red);
test.pcLocal.canvasStream.requestFrame();
} catch (e) {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 500);
},
function WAIT_FOR_REMOTE_RED() {
return h.waitForPixelColor(vremote, h.red, 128,

View file

@ -72,15 +72,38 @@ runNetworkTest(() => {
// After requesting a frame it will be captured at the time of next render.
// Next render will happen at next stable state, at the earliest,
// i.e., this order of `requestFrame(); draw();` should work.
stream1.requestFrame();
h.drawColor(canvas1, h.red);
stream1.requestFrame();
var i = 0;
return setInterval(function() {
try {
info("draw " + i ? "green" : "red");
h.drawColor(canvas1, i ? h.green : h.red);
i = 1 - i;
stream1.requestFrame();
} catch (e) {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 500);
},
function DRAW_LOCAL2_RED() {
// After requesting a frame it will be captured at the time of next render.
// Next render will happen at next stable state, at the earliest,
// i.e., this order of `requestFrame(); draw();` should work.
stream2.requestFrame();
h.drawColor(canvas2, h.red);
stream2.requestFrame();
return setInterval(function() {
try {
info("draw");
h.drawColor(canvas2, i ? h.green : h.red);
i = 1 - i;
stream2.requestFrame();
} catch (e) {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 500);
},
function WAIT_FOR_REMOTE1_RED() {
return h.waitForPixelColor(vremote1, h.red, 128,

View file

@ -63,7 +63,8 @@
test.originalOffer.sdp, test._remote_answer.sdp);
info("Answer with RIDs: " + JSON.stringify(test._remote_answer));
ok(test._remote_answer.sdp.match(/a=simulcast:/), "Modified answer has simulcast");
ok(test._remote_answer.sdp.match(/a=rid:/), "Modified answer has rid");
ok(test._remote_answer.sdp.match(/a=rid:foo/), "Modified answer has rid foo");
ok(test._remote_answer.sdp.match(/a=rid:bar/), "Modified answer has rid bar");
}
]);
@ -118,18 +119,8 @@
ok(vremote, "Should have remote video element for pcRemote");
ok(vlocal.videoWidth > 0, "source width is positive");
ok(vlocal.videoHeight > 0, "source height is positive");
is(vremote.videoWidth, vlocal.videoWidth / 2, "sink is 1/2 width of source");
is(vremote.videoHeight, vlocal.videoHeight / 2, "sink is 1/2 height of source");
},
function PC_REMOTE_SET_RTP_NONEXISTENT_RID(test) {
// Now, cause pcRemote to filter out everything, just to make sure
// selectRecvSsrc is working.
selectRecvSsrc(test.pcRemote, 2);
},
function PC_REMOTE_ENSURE_NO_FRAMES() {
var vremote = test.pcRemote.remoteMediaElements[0];
ok(vremote, "Should have remote video element for pcRemote");
return helper.verifyNoFrames(vremote);
is(vremote.videoWidth, vlocal.videoWidth, "sink is same width as source");
is(vremote.videoHeight, vlocal.videoHeight, "sink is same height as source");
},
]);

View file

@ -51,6 +51,18 @@ runNetworkTest(() => {
// i.e., this order of `requestFrame(); draw();` should work.
stream1.requestFrame();
h1.drawColor(canvas1, h1.red);
var i = 0;
return setInterval(function() {
try {
info("draw " + i ? "green" : "red");
h1.drawColor(canvas1, i ? h1.green : h1.red);
i = 1 - i;
stream1.requestFrame();
} catch (e) {
// ignore; stream might have shut down, and we don't bother clearing
// the setInterval.
}
}, 500);
},
function WAIT_FOR_REMOTE_RED() {
return h1.waitForPixelColor(vremote1, h1.red, 128,

View file

@ -390,22 +390,4 @@ MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners)
mHasDirectListeners = aHasDirectListeners;
}
bool operator == (const webrtc::CaptureCapability& a,
const webrtc::CaptureCapability& b)
{
return a.width == b.width &&
a.height == b.height &&
a.maxFPS == b.maxFPS &&
a.rawType == b.rawType &&
a.codecType == b.codecType &&
a.expectedCaptureDelay == b.expectedCaptureDelay &&
a.interlaced == b.interlaced;
};
bool operator != (const webrtc::CaptureCapability& a,
const webrtc::CaptureCapability& b)
{
return !(a == b);
}
} // namespace mozilla

View file

@ -11,15 +11,18 @@
// conflicts with #include of scoped_ptr.h
#undef FF
#include "webrtc/video_engine/include/vie_capture.h"
// Avoid warnings about redefinition of WARN_UNUSED_RESULT
#include "ipc/IPCMessageUtils.h"
// WebRTC includes
#include "webrtc/modules/video_capture/video_capture_defines.h"
namespace webrtc {
using CaptureCapability = VideoCaptureCapability;
}
namespace mozilla {
bool operator == (const webrtc::CaptureCapability& a,
const webrtc::CaptureCapability& b);
bool operator != (const webrtc::CaptureCapability& a,
const webrtc::CaptureCapability& b);
class MediaEngineCameraVideoSource : public MediaEngineVideoSource
{
public:

View file

@ -350,23 +350,23 @@ MediaEngineRemoteVideoSource::NotifyPull(MediaStreamGraph* aGraph,
}
}
int
MediaEngineRemoteVideoSource::FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams)
void
MediaEngineRemoteVideoSource::FrameSizeChange(unsigned int w, unsigned int h)
{
mWidth = w;
mHeight = h;
LOG(("MediaEngineRemoteVideoSource Video FrameSizeChange: %ux%u", w, h));
return 0;
#if defined(MOZ_WIDGET_GONK)
mMonitor.AssertCurrentThreadOwns(); // mWidth and mHeight are protected...
#endif
if ((mWidth < 0) || (mHeight < 0) ||
(w != (unsigned int) mWidth) || (h != (unsigned int) mHeight)) {
LOG(("MediaEngineRemoteVideoSource Video FrameSizeChange: %ux%u was %ux%u", w, h, mWidth, mHeight));
mWidth = w;
mHeight = h;
}
}
int
MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle)
MediaEngineRemoteVideoSource::DeliverFrame(uint8_t* aBuffer ,
const camera::VideoFrameProperties& aProps)
{
// Check for proper state.
if (mState != kStarted) {
@ -374,15 +374,13 @@ MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
return 0;
}
if ((size_t) (mWidth*mHeight + 2*(((mWidth+1)/2)*((mHeight+1)/2))) != size) {
MOZ_ASSERT(false, "Wrong size frame in DeliverFrame!");
return 0;
}
// Update the dimensions
FrameSizeChange(aProps.width(), aProps.height());
// Create a video frame and append it to the track.
RefPtr<layers::PlanarYCbCrImage> image = mImageContainer->CreatePlanarYCbCrImage();
uint8_t* frame = static_cast<uint8_t*> (buffer);
uint8_t* frame = static_cast<uint8_t*> (aBuffer);
const uint8_t lumaBpp = 8;
const uint8_t chromaBpp = 4;
@ -407,8 +405,9 @@ MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
#ifdef DEBUG
static uint32_t frame_num = 0;
LOGFRAME(("frame %d (%dx%d); timestamp %u, ntp_time %" PRIu64 ", render_time %" PRIu64,
frame_num++, mWidth, mHeight, time_stamp, ntp_time, render_time));
LOGFRAME(("frame %d (%dx%d); timeStamp %u, ntpTimeMs %" PRIu64 ", renderTimeMs %" PRIu64,
frame_num++, mWidth, mHeight,
aProps.timeStamp(), aProps.ntpTimeMs(), aProps.renderTimeMs()));
#endif
// we don't touch anything in 'this' until here (except for snapshot,

View file

@ -19,6 +19,8 @@
#include "nsDirectoryServiceDefs.h"
#include "nsComponentManagerUtils.h"
// Avoid warnings about redefinition of WARN_UNUSED_RESULT
#include "ipc/IPCMessageUtils.h"
#include "VideoUtils.h"
#include "MediaEngineCameraVideoSource.h"
#include "VideoSegment.h"
@ -31,40 +33,29 @@
// WebRTC library includes follow
#include "webrtc/common.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "webrtc/video_engine/include/vie_render.h"
// Camera Access via IPC
#include "CamerasChild.h"
#include "NullTransport.h"
namespace webrtc {
class I420VideoFrame;
}
namespace mozilla {
/**
* The WebRTC implementation of the MediaEngine interface.
*/
class MediaEngineRemoteVideoSource : public MediaEngineCameraVideoSource,
public webrtc::ExternalRenderer
public camera::FrameRelay
{
typedef MediaEngineCameraVideoSource Super;
public:
NS_DECL_THREADSAFE_ISUPPORTS
// Old ExternalRenderer
void FrameSizeChange(unsigned int w, unsigned int h) override;
// ExternalRenderer
int FrameSizeChange(unsigned int w, unsigned int h,
unsigned int streams) override;
int DeliverFrame(unsigned char* buffer,
size_t size,
uint32_t time_stamp,
int64_t ntp_time,
int64_t render_time,
void *handle) override;
// XXX!!!! FIX THIS
int DeliverI420Frame(const webrtc::I420VideoFrame& webrtc_frame) override { return 0; };
bool IsTextureSupported() override { return false; };
int DeliverFrame(uint8_t* buffer,
const camera::VideoFrameProperties& properties) override;
// MediaEngineCameraVideoSource
MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine,

View file

@ -24,6 +24,7 @@
#include "nsComponentManagerUtils.h"
#include "nsRefPtrHashtable.h"
#include "ipc/IPCMessageUtils.h"
#include "VideoUtils.h"
#include "MediaEngineCameraVideoSource.h"
#include "VideoSegment.h"
@ -36,6 +37,8 @@
#include "MediaEngineWrapper.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "CamerasChild.h"
// WebRTC library includes follow
#include "webrtc/common.h"
// Audio Engine
@ -52,11 +55,9 @@
// Video Engine
// conflicts with #include of scoped_ptr.h
#undef FF
#include "webrtc/video_engine/include/vie_base.h"
#include "webrtc/video_engine/include/vie_codec.h"
#include "webrtc/video_engine/include/vie_render.h"
#include "webrtc/video_engine/include/vie_capture.h"
#include "CamerasChild.h"
// WebRTC imports
#include "webrtc/modules/video_capture/video_capture_defines.h"
#include "NullTransport.h"
#include "AudioOutputObserver.h"
@ -256,10 +257,10 @@ public:
MOZ_ASSERT(mDevices);
if (mInUseCount == 0) {
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> ptrVoERender;
ptrVoERender = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (ptrVoERender) {
ptrVoERender->SetExternalRecordingStatus(true);
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> ptrVoEXMedia;
ptrVoEXMedia = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
if (ptrVoEXMedia) {
ptrVoEXMedia->SetExternalRecordingStatus(true);
}
mAnyInUse = true;
}
@ -475,9 +476,9 @@ public:
const nsString& aDeviceId) const override;
// VoEMediaProcess.
void Process(int channel, webrtc::ProcessingTypes type,
int16_t audio10ms[], int length,
int samplingFreq, bool isStereo) override;
virtual void Process(int channel, webrtc::ProcessingTypes type,
int16_t audio10ms[], size_t length,
int samplingFreq, bool isStereo) override;
void Shutdown() override;

View file

@ -824,7 +824,7 @@ typedef int16_t sample;
void
MediaEngineWebRTCMicrophoneSource::Process(int channel,
webrtc::ProcessingTypes type,
sample *audio10ms, int length,
sample *audio10ms, size_t length,
int samplingFreq, bool isStereo)
{
MOZ_ASSERT(!PassThrough(), "This should be bypassed when in PassThrough mode.");

View file

@ -13,6 +13,9 @@
namespace mozilla {
using dom::ConstrainBooleanParameters;
using dom::OwningLongOrConstrainLongRange;
template<class ValueType>
template<class ConstrainRange>
void

View file

@ -81,6 +81,11 @@ nrappkit copyright:
#include "mozilla/Unused.h"
#include "databuffer.h"
// mozilla/utils.h defines this as well
#ifdef UNIMPLEMENTED
#undef UNIMPLEMENTED
#endif
extern "C" {
#include "nr_api.h"
#include "async_wait.h"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,76 @@
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../build/webrtc.gni")
config("ios_config") {
libs = [
"CoreGraphics.framework",
"GLKit.framework",
"OpenGLES.framework",
"QuartzCore.framework",
]
}
if (is_ios) {
source_set("rtc_api_objc") {
deps = [
"//webrtc/base:rtc_base_objc",
#"//talk/libjingle:libjingle_peerconnection",
]
cflags = [
"-fobjc-arc",
"-Wobjc-missing-property-synthesis",
]
sources = [
# Add these when there's a BUILD.gn for peer connection APIs
#"objc/RTCIceCandidate+Private.h",
#"objc/RTCIceCandidate.h",
#"objc/RTCIceCandidate.mm",
#"objc/RTCMediaSource+Private.h",
#"objc/RTCMediaSource.h",
#"objc/RTCMediaSource.mm",
#"objc/RTCMediaStreamTrack+Private.h",
#"objc/RTCMediaStreamTrack.h",
#"objc/RTCMediaStreamTrack.mm",
"objc/RTCIceServer+Private.h",
"objc/RTCIceServer.h",
"objc/RTCIceServer.mm",
"objc/RTCMediaConstraints+Private.h",
"objc/RTCMediaConstraints.h",
"objc/RTCMediaConstraints.mm",
"objc/RTCOpenGLVideoRenderer.h",
"objc/RTCOpenGLVideoRenderer.mm",
"objc/RTCSessionDescription+Private.h",
"objc/RTCSessionDescription.h",
"objc/RTCSessionDescription.mm",
"objc/RTCStatsReport+Private.h",
"objc/RTCStatsReport.h",
"objc/RTCStatsReport.mm",
"objc/RTCVideoFrame+Private.h",
"objc/RTCVideoFrame.h",
"objc/RTCVideoFrame.mm",
"objc/RTCVideoRenderer.h",
"objc/WebRTC-Prefix.pch",
]
if (is_ios) {
sources += [
"objc/RTCEAGLVideoView.h",
"objc/RTCEAGLVideoView.m",
]
}
if (is_mac) {
sources += [
"objc/RTCNSGLVideoView.h",
"objc/RTCNSGLVideoView.m",
]
}
}
}

View file

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

View file

@ -0,0 +1,83 @@
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
{
'includes': [ '../build/common.gypi', ],
'conditions': [
['OS=="ios"', {
'targets': [
{
'target_name': 'rtc_api_objc',
'type': 'static_library',
'dependencies': [
'<(webrtc_root)/base/base.gyp:rtc_base_objc',
'../../talk/libjingle.gyp:libjingle_peerconnection',
],
'sources': [
'objc/RTCIceCandidate+Private.h',
'objc/RTCIceCandidate.h',
'objc/RTCIceCandidate.mm',
'objc/RTCIceServer+Private.h',
'objc/RTCIceServer.h',
'objc/RTCIceServer.mm',
'objc/RTCMediaConstraints+Private.h',
'objc/RTCMediaConstraints.h',
'objc/RTCMediaConstraints.mm',
'objc/RTCMediaSource+Private.h',
'objc/RTCMediaSource.h',
'objc/RTCMediaSource.mm',
'objc/RTCMediaStreamTrack+Private.h',
'objc/RTCMediaStreamTrack.h',
'objc/RTCMediaStreamTrack.mm',
'objc/RTCOpenGLVideoRenderer.h',
'objc/RTCOpenGLVideoRenderer.mm',
'objc/RTCSessionDescription+Private.h',
'objc/RTCSessionDescription.h',
'objc/RTCSessionDescription.mm',
'objc/RTCStatsReport+Private.h',
'objc/RTCStatsReport.h',
'objc/RTCStatsReport.mm',
'objc/RTCVideoFrame+Private.h',
'objc/RTCVideoFrame.h',
'objc/RTCVideoFrame.mm',
'objc/RTCVideoRenderer.h',
],
'conditions': [
['OS=="ios"', {
'sources': [
'objc/RTCEAGLVideoView.h',
'objc/RTCEAGLVideoView.m',
],
'all_dependent_settings': {
'xcode_settings': {
'OTHER_LDFLAGS': [
'-framework CoreGraphics',
'-framework GLKit',
'-framework OpenGLES',
'-framework QuartzCore',
]
}
}
}],
['OS=="mac"', {
'sources': [
'objc/RTCNSGLVideoView.h',
'objc/RTCNSGLVideoView.m',
],
}],
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
},
}
],
}], # OS=="ios"
],
}

View file

@ -0,0 +1,40 @@
# Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
{
'includes': [ '../build/common.gypi', ],
'conditions': [
['OS=="ios"', {
'targets': [
{
'target_name': 'rtc_api_objc_test',
'type': 'executable',
'dependencies': [
'<(webrtc_root)/api/api.gyp:rtc_api_objc',
'<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils',
],
'sources': [
'objctests/RTCIceCandidateTest.mm',
'objctests/RTCIceServerTest.mm',
'objctests/RTCMediaConstraintsTest.mm',
'objctests/RTCSessionDescriptionTest.mm',
],
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
'CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS': 'YES',
'GCC_PREFIX_HEADER': 'objc/WebRTC-Prefix.pch',
# |-ObjC| flag needed to make sure category method implementations
# are included:
# https://developer.apple.com/library/mac/qa/qa1490/_index.html
'OTHER_LDFLAGS': ['-ObjC'],
},
}
],
}], # OS=="ios"
],
}

View file

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

View file

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

View file

@ -0,0 +1,35 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "RTCVideoRenderer.h"
NS_ASSUME_NONNULL_BEGIN
@class RTCEAGLVideoView;
@protocol RTCEAGLVideoViewDelegate
- (void)videoView:(RTCEAGLVideoView *)videoView didChangeVideoSize:(CGSize)size;
@end
/**
* RTCEAGLVideoView is an RTCVideoRenderer which renders video frames in its
* bounds using OpenGLES 2.0.
*/
@interface RTCEAGLVideoView : UIView <RTCVideoRenderer>
@property(nonatomic, weak) id<RTCEAGLVideoViewDelegate> delegate;
@end
NS_ASSUME_NONNULL_END

View file

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

View file

@ -0,0 +1,36 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCIceCandidate.h"
#include "talk/app/webrtc/jsep.h"
#include "webrtc/base/scoped_ptr.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceCandidate ()
/**
* The native IceCandidateInterface representation of this RTCIceCandidate
* object. This is needed to pass to the underlying C++ APIs.
*/
@property(nonatomic, readonly)
rtc::scoped_ptr<webrtc::IceCandidateInterface> nativeCandidate;
/**
* Initialize an RTCIceCandidate from a native IceCandidateInterface. No
* ownership is taken of the native candidate.
*/
- (instancetype)initWithNativeCandidate:
(webrtc::IceCandidateInterface *)candidate;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,44 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceCandidate : NSObject
/**
* If present, the identifier of the "media stream identification" for the media
* component this candidate is associated with.
*/
@property(nonatomic, readonly, nullable) NSString *sdpMid;
/**
* The index (starting at zero) of the media description this candidate is
* associated with in the SDP.
*/
@property(nonatomic, readonly) NSInteger sdpMLineIndex;
/** The SDP string for this candidate. */
@property(nonatomic, readonly) NSString *sdp;
- (instancetype)init NS_UNAVAILABLE;
/**
* Initialize an RTCIceCandidate from SDP.
*/
- (instancetype)initWithSdp:(NSString *)sdp
sdpMLineIndex:(NSInteger)sdpMLineIndex
sdpMid:(nullable NSString *)sdpMid
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,70 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCIceCandidate.h"
#import "webrtc/api/objc/RTCIceCandidate+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
#import "webrtc/base/objc/RTCLogging.h"
@implementation RTCIceCandidate
@synthesize sdpMid = _sdpMid;
@synthesize sdpMLineIndex = _sdpMLineIndex;
@synthesize sdp = _sdp;
- (instancetype)initWithSdp:(NSString *)sdp
sdpMLineIndex:(NSInteger)sdpMLineIndex
sdpMid:(NSString *)sdpMid {
NSParameterAssert(sdp.length);
if (self = [super init]) {
_sdpMid = [sdpMid copy];
_sdpMLineIndex = sdpMLineIndex;
_sdp = [sdp copy];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCIceCandidate:\n%@\n%ld\n%@",
_sdpMid,
(long)_sdpMLineIndex,
_sdp];
}
#pragma mark - Private
- (instancetype)initWithNativeCandidate:
(webrtc::IceCandidateInterface *)candidate {
NSParameterAssert(candidate);
std::string sdp;
candidate->ToString(&sdp);
return [self initWithSdp:[NSString stringForStdString:sdp]
sdpMLineIndex:candidate->sdp_mline_index()
sdpMid:[NSString stringForStdString:candidate->sdp_mid()]];
}
- (rtc::scoped_ptr<webrtc::IceCandidateInterface>)nativeCandidate {
webrtc::SdpParseError error;
webrtc::IceCandidateInterface *candidate = webrtc::CreateIceCandidate(
_sdpMid.stdString, _sdpMLineIndex, _sdp.stdString, &error);
if (!candidate) {
RTCLog(@"Failed to create ICE candidate: %s\nline: %s",
error.description.c_str(),
error.line.c_str());
}
return rtc::scoped_ptr<webrtc::IceCandidateInterface>(candidate);
}
@end

View file

@ -0,0 +1,28 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCIceServer.h"
#include "talk/app/webrtc/peerconnectioninterface.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceServer ()
/**
* IceServer struct representation of this RTCIceServer object's data.
* This is needed to pass to the underlying C++ APIs.
*/
@property(nonatomic, readonly)
webrtc::PeerConnectionInterface::IceServer iceServer;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,42 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCIceServer : NSObject
/** URI(s) for this server represented as NSStrings. */
@property(nonatomic, copy, readonly) NSArray<NSString *> *urlStrings;
/** Username to use if this RTCIceServer object is a TURN server. */
@property(nonatomic, copy, readonly, nullable) NSString *username;
/** Credential to use if this RTCIceServer object is a TURN server. */
@property(nonatomic, copy, readonly, nullable) NSString *credential;
- (instancetype)init NS_UNAVAILABLE;
/** Convenience initializer for a server with no authentication (e.g. STUN). */
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings;
/**
* Initialize an RTCIceServer with its associated URLs, optional username,
* optional credential, and credentialType.
*/
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(nullable NSString *)username
credential:(nullable NSString *)credential
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,64 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCIceServer.h"
#import "webrtc/api/objc/RTCIceServer+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
@implementation RTCIceServer
@synthesize urlStrings = _urlStrings;
@synthesize username = _username;
@synthesize credential = _credential;
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings {
NSParameterAssert(urlStrings.count);
return [self initWithURLStrings:urlStrings
username:nil
credential:nil];
}
- (instancetype)initWithURLStrings:(NSArray<NSString *> *)urlStrings
username:(NSString *)username
credential:(NSString *)credential {
NSParameterAssert(urlStrings.count);
if (self = [super init]) {
_urlStrings = [[NSArray alloc] initWithArray:urlStrings copyItems:YES];
_username = [username copy];
_credential = [credential copy];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCIceServer:\n%@\n%@\n%@",
_urlStrings,
_username,
_credential];
}
#pragma mark - Private
- (webrtc::PeerConnectionInterface::IceServer)iceServer {
__block webrtc::PeerConnectionInterface::IceServer iceServer;
iceServer.username = [NSString stdStringForString:_username];
iceServer.password = [NSString stdStringForString:_credential];
[_urlStrings enumerateObjectsUsingBlock:^(NSString *url,
NSUInteger idx,
BOOL *stop) {
iceServer.urls.push_back(url.stdString);
}];
return iceServer;
}
@end

View file

@ -0,0 +1,53 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCMediaConstraints.h"
#include "talk/app/webrtc/mediaconstraintsinterface.h"
#include "webrtc/base/scoped_ptr.h"
namespace webrtc {
class MediaConstraints : public MediaConstraintsInterface {
public:
virtual ~MediaConstraints();
MediaConstraints();
MediaConstraints(
const MediaConstraintsInterface::Constraints& mandatory,
const MediaConstraintsInterface::Constraints& optional);
virtual const Constraints& GetMandatory() const;
virtual const Constraints& GetOptional() const;
private:
MediaConstraintsInterface::Constraints mandatory_;
MediaConstraintsInterface::Constraints optional_;
};
} // namespace webrtc
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaConstraints ()
/**
* A MediaConstraints representation of this RTCMediaConstraints object. This is
* needed to pass to the underlying C++ APIs.
*/
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints;
/** Return a native Constraints object representing these constraints */
+ (webrtc::MediaConstraintsInterface::Constraints)
nativeConstraintsForConstraints:
(NSDictionary<NSString *, NSString *> *)constraints;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,28 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaConstraints : NSObject
- (instancetype)init NS_UNAVAILABLE;
/** Initialize with mandatory and/or optional constraints. */
- (instancetype)initWithMandatoryConstraints:
(nullable NSDictionary<NSString *, NSString *> *)mandatory
optionalConstraints:
(nullable NSDictionary<NSString *, NSString *> *)optional
NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,92 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCMediaConstraints.h"
#import "webrtc/api/objc/RTCMediaConstraints+Private.h"
#import "webrtc/base/objc/NSString+StdString.h"
namespace webrtc {
MediaConstraints::~MediaConstraints() {}
MediaConstraints::MediaConstraints() {}
MediaConstraints::MediaConstraints(
const MediaConstraintsInterface::Constraints& mandatory,
const MediaConstraintsInterface::Constraints& optional)
: mandatory_(mandatory), optional_(optional) {}
const MediaConstraintsInterface::Constraints&
MediaConstraints::GetMandatory() const {
return mandatory_;
}
const MediaConstraintsInterface::Constraints&
MediaConstraints::GetOptional() const {
return optional_;
}
} // namespace webrtc
@implementation RTCMediaConstraints {
NSDictionary<NSString *, NSString *> *_mandatory;
NSDictionary<NSString *, NSString *> *_optional;
}
- (instancetype)initWithMandatoryConstraints:
(NSDictionary<NSString *, NSString *> *)mandatory
optionalConstraints:
(NSDictionary<NSString *, NSString *> *)optional {
if (self = [super init]) {
_mandatory = [[NSDictionary alloc] initWithDictionary:mandatory
copyItems:YES];
_optional = [[NSDictionary alloc] initWithDictionary:optional
copyItems:YES];
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCMediaConstraints:\n%@\n%@",
_mandatory,
_optional];
}
#pragma mark - Private
- (rtc::scoped_ptr<webrtc::MediaConstraints>)nativeConstraints {
webrtc::MediaConstraintsInterface::Constraints mandatory =
[[self class] nativeConstraintsForConstraints:_mandatory];
webrtc::MediaConstraintsInterface::Constraints optional =
[[self class] nativeConstraintsForConstraints:_optional];
webrtc::MediaConstraints *nativeConstraints =
new webrtc::MediaConstraints(mandatory, optional);
return rtc::scoped_ptr<webrtc::MediaConstraints>(nativeConstraints);
}
+ (webrtc::MediaConstraintsInterface::Constraints)
nativeConstraintsForConstraints:
(NSDictionary<NSString *, NSString *> *)constraints {
webrtc::MediaConstraintsInterface::Constraints nativeConstraints;
for (NSString *key in constraints) {
NSAssert([key isKindOfClass:[NSString class]],
@"%@ is not an NSString.", key);
NSAssert([constraints[key] isKindOfClass:[NSString class]],
@"%@ is not an NSString.", constraints[key]);
nativeConstraints.push_back(webrtc::MediaConstraintsInterface::Constraint(
key.stdString, constraints[key].stdString));
}
return nativeConstraints;
}
@end

View file

@ -0,0 +1,41 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCMediaSource.h"
#include "talk/app/webrtc/mediastreaminterface.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaSource ()
/**
* The MediaSourceInterface object passed to this RTCMediaSource during
* construction.
*/
@property(nonatomic, readonly)
rtc::scoped_refptr<webrtc::MediaSourceInterface> nativeMediaSource;
/** Initialize an RTCMediaSource from a native MediaSourceInterface. */
- (instancetype)initWithNativeMediaSource:
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource
NS_DESIGNATED_INITIALIZER;
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
(RTCSourceState)state;
+ (RTCSourceState)sourceStateForNativeState:
(webrtc::MediaSourceInterface::SourceState)nativeState;
+ (NSString *)stringForState:(RTCSourceState)state;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,31 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, RTCSourceState) {
RTCSourceStateInitializing,
RTCSourceStateLive,
RTCSourceStateEnded,
RTCSourceStateMuted,
};
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaSource : NSObject
/** The current state of the RTCMediaSource. */
@property(nonatomic, readonly) RTCSourceState state;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,84 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCMediaSource.h"
#import "webrtc/api/objc/RTCMediaSource+Private.h"
@implementation RTCMediaSource {
rtc::scoped_refptr<webrtc::MediaSourceInterface> _nativeMediaSource;
}
- (RTCSourceState)state {
return [[self class] sourceStateForNativeState:_nativeMediaSource->state()];
}
- (NSString *)description {
return [NSString stringWithFormat:@"RTCMediaSource:\n%@",
[[self class] stringForState:self.state]];
}
#pragma mark - Private
- (rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
return _nativeMediaSource;
}
- (instancetype)initWithNativeMediaSource:
(rtc::scoped_refptr<webrtc::MediaSourceInterface>)nativeMediaSource {
NSParameterAssert(nativeMediaSource);
if (self = [super init]) {
_nativeMediaSource = nativeMediaSource;
}
return self;
}
+ (webrtc::MediaSourceInterface::SourceState)nativeSourceStateForState:
(RTCSourceState)state {
switch (state) {
case RTCSourceStateInitializing:
return webrtc::MediaSourceInterface::kInitializing;
case RTCSourceStateLive:
return webrtc::MediaSourceInterface::kLive;
case RTCSourceStateEnded:
return webrtc::MediaSourceInterface::kEnded;
case RTCSourceStateMuted:
return webrtc::MediaSourceInterface::kMuted;
}
}
+ (RTCSourceState)sourceStateForNativeState:
(webrtc::MediaSourceInterface::SourceState)nativeState {
switch (nativeState) {
case webrtc::MediaSourceInterface::kInitializing:
return RTCSourceStateInitializing;
case webrtc::MediaSourceInterface::kLive:
return RTCSourceStateLive;
case webrtc::MediaSourceInterface::kEnded:
return RTCSourceStateEnded;
case webrtc::MediaSourceInterface::kMuted:
return RTCSourceStateMuted;
}
}
+ (NSString *)stringForState:(RTCSourceState)state {
switch (state) {
case RTCSourceStateInitializing:
return @"Initializing";
case RTCSourceStateLive:
return @"Live";
case RTCSourceStateEnded:
return @"Ended";
case RTCSourceStateMuted:
return @"Muted";
}
}
@end

View file

@ -0,0 +1,45 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import "RTCMediaStreamTrack.h"
#include "talk/app/webrtc/mediastreaminterface.h"
#include "webrtc/base/scoped_ptr.h"
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaStreamTrack ()
/**
* The native MediaStreamTrackInterface representation of this
* RTCMediaStreamTrack object. This is needed to pass to the underlying C++
* APIs.
*/
@property(nonatomic, readonly)
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> nativeTrack;
/**
* Initialize an RTCMediaStreamTrack from a native MediaStreamTrackInterface.
*/
- (instancetype)initWithNativeTrack:
(rtc::scoped_refptr<webrtc::MediaStreamTrackInterface>)nativeTrack
NS_DESIGNATED_INITIALIZER;
+ (webrtc::MediaStreamTrackInterface::TrackState)nativeTrackStateForState:
(RTCMediaStreamTrackState)state;
+ (RTCMediaStreamTrackState)trackStateForNativeState:
(webrtc::MediaStreamTrackInterface::TrackState)nativeState;
+ (NSString *)stringForState:(RTCMediaStreamTrackState)state;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,47 @@
/*
* Copyright 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#import <Foundation/Foundation.h>
/**
* Represents the state of the track. This exposes the same states in C++,
* which include two more states than are in the W3C spec.
*/
typedef NS_ENUM(NSInteger, RTCMediaStreamTrackState) {
RTCMediaStreamTrackStateInitializing,
RTCMediaStreamTrackStateLive,
RTCMediaStreamTrackStateEnded,
RTCMediaStreamTrackStateFailed,
};
NS_ASSUME_NONNULL_BEGIN
@interface RTCMediaStreamTrack : NSObject
/**
* The kind of track. For example, "audio" if this track represents an audio
* track and "video" if this track represents a video track.
*/
@property(nonatomic, readonly) NSString *kind;
/** An identifier string. */
@property(nonatomic, readonly) NSString *trackId;
/** The enabled state of the track. */
@property(nonatomic) BOOL isEnabled;
/** The state of the track. */
@property(nonatomic, readonly) RTCMediaStreamTrackState readyState;
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END

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