[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 # don't use openssl
'use_openssl': 0, 'use_openssl': 0,
'debug': 1 if CONFIG['DEBUG'] else 0,
'use_x11': 1 if CONFIG['MOZ_X11'] else 0, 'use_x11': 1 if CONFIG['MOZ_X11'] else 0,
'use_glib': 1 if CONFIG['GLIB_LIBS'] 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 [" + info("Waiting for video " + video.id + " to match [" +
refColor.data.join(',') + "] - " + refColor.name + refColor.data.join(',') + "] - " + refColor.name +
" (" + infoString + ")"); " (" + infoString + ")");
var paintedFrames = video.mozPaintedFrames-1;
return this.waitForPixel(video, 0, 0, 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)); .then(() => ok(true, video.id + " " + infoString));
}, },

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,7 +10,8 @@ using mozilla::camera::CaptureEngine from "mozilla/media/CamerasTypes.h";
namespace mozilla { namespace mozilla {
namespace camera { namespace camera {
struct CaptureCapability // IPC analog for webrtc::VideoCaptureCapability
struct VideoCaptureCapability
{ {
int width; int width;
int height; int height;
@ -21,6 +22,32 @@ struct CaptureCapability
bool interlaced; 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 async protocol PCameras
{ {
manager PBackground; manager PBackground;
@ -28,14 +55,13 @@ async protocol PCameras
child: child:
async FrameSizeChange(CaptureEngine capEngine, int cap_id, int w, int h); async FrameSizeChange(CaptureEngine capEngine, int cap_id, int w, int h);
// transfers ownership of |buffer| from parent to child // transfers ownership of |buffer| from parent to child
async DeliverFrame(CaptureEngine capEngine, int cap_id, async DeliverFrame(CaptureEngine capEngine, int streamId,
Shmem buffer, size_t size, uint32_t time_stamp, Shmem buffer, VideoFrameProperties props);
int64_t ntp_time, int64_t render_time);
async DeviceChange(); async DeviceChange();
async ReplyNumberOfCaptureDevices(int numdev); async ReplyNumberOfCaptureDevices(int numdev);
async ReplyNumberOfCapabilities(int numdev); async ReplyNumberOfCapabilities(int numdev);
async ReplyAllocateCaptureDevice(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 ReplyGetCaptureDevice(nsCString device_name, nsCString device_id, bool scary);
async ReplyFailure(); async ReplyFailure();
async ReplySuccess(); async ReplySuccess();
@ -45,12 +71,13 @@ parent:
async NumberOfCaptureDevices(CaptureEngine engine); async NumberOfCaptureDevices(CaptureEngine engine);
async NumberOfCapabilities(CaptureEngine engine, nsCString deviceUniqueIdUTF8); 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 GetCaptureDevice(CaptureEngine engine, int num);
async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8, nsCString origin); async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8, nsCString origin);
async ReleaseCaptureDevice(CaptureEngine engine, int numdev); 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); async StopCapture(CaptureEngine engine, int numdev);
// transfers frame back // transfers frame back
async ReleaseFrame(Shmem s); 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?"); 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")); LOG(("Free Shmem but not of the right size"));
return ShmemBuffer(); return ShmemBuffer();
} }
@ -64,7 +64,7 @@ void ShmemPool::Put(ShmemBuffer&& aShmem)
#ifdef DEBUG #ifdef DEBUG
size_t poolUse = mShmemPool.Length() - mPoolFree; size_t poolUse = mShmemPool.Length() - mPoolFree;
if (poolUse > 0) { if (poolUse > 0) {
LOG(("ShmemPool usage reduced to %d buffers", poolUse)); LOG_VERBOSE(("ShmemPool usage reduced to %d buffers", poolUse));
} }
#endif #endif
} }

View file

@ -47,8 +47,8 @@ public:
return mInitialized; return mInitialized;
} }
char* GetBytes() { uint8_t * GetBytes() {
return mShmem.get<char>(); return mShmem.get<uint8_t>();
} }
mozilla::ipc::Shmem& Get() { 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 # 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 # 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/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
@ -10,6 +10,8 @@ if CONFIG['MOZ_WEBRTC']:
'LoadManager.h', 'LoadManager.h',
'LoadManagerFactory.h', 'LoadManagerFactory.h',
'LoadMonitor.h', 'LoadMonitor.h',
'VideoEngine.h',
'VideoFrameUtils.h'
] ]
SOURCES += [ SOURCES += [
'CamerasChild.cpp', 'CamerasChild.cpp',
@ -18,6 +20,8 @@ if CONFIG['MOZ_WEBRTC']:
'LoadManagerFactory.cpp', 'LoadManagerFactory.cpp',
'LoadMonitor.cpp', 'LoadMonitor.cpp',
'ShmemPool.cpp', 'ShmemPool.cpp',
'VideoEngine.cpp',
'VideoFrameUtils.cpp'
] ]
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'/media/webrtc/signaling', '/media/webrtc/signaling',
@ -29,6 +33,9 @@ if CONFIG['OS_TARGET'] == 'WINNT':
else: else:
DEFINES['WEBRTC_POSIX'] = True DEFINES['WEBRTC_POSIX'] = True
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['WEBRTC_ANDROID'] = True
if CONFIG['OS_TARGET'] == 'Android': if CONFIG['OS_TARGET'] == 'Android':
EXPORTS += [ 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 skip-if = true # needed by test_enumerateDevices.html on builders
[test_ondevicechange.html] [test_ondevicechange.html]
skip-if = os == 'android' skip-if = os == 'android'
[test_getUserMedia_active_autoplay.html]
[test_getUserMedia_audioCapture.html] [test_getUserMedia_audioCapture.html]
skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator) skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
[test_getUserMedia_addTrackRemoveTrack.html] [test_getUserMedia_addTrackRemoveTrack.html]
@ -99,7 +98,7 @@ skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioNATRelayTCP.html] [test_peerConnection_basicAudioNATRelayTCP.html]
skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217) skip-if = toolkit == 'android' # websockets don't work on android (bug 1266217)
[test_peerConnection_basicAudioRequireEOC.html] [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] [test_peerConnection_basicAudioPcmaPcmuOnly.html]
skip-if = android_version == '18' skip-if = android_version == '18'
[test_peerConnection_basicAudioDynamicPtMissingRtpmap.html] [test_peerConnection_basicAudioDynamicPtMissingRtpmap.html]
@ -127,7 +126,7 @@ skip-if = os == 'android' # bug 1043403
[test_peerConnection_bug822674.html] [test_peerConnection_bug822674.html]
[test_peerConnection_bug825703.html] [test_peerConnection_bug825703.html]
[test_peerConnection_bug827843.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_bug834153.html]
[test_peerConnection_bug1013809.html] [test_peerConnection_bug1013809.html]
skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator) 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. * A promise that resolves when media is flowing.
*/ */
waitForRtpFlow(track) { waitForRtpFlow(track) {
var hasFlow = stats => { var hasFlow = (stats, retries) => {
var rtp = stats.get([...stats.keys()].find(key => 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"))); !stats.get(key).isRemote && stats.get(key).type.endsWith("boundrtp")));
ok(rtp, "Should have RTP stats for track " + track.id);
if (!rtp) { if (!rtp) {
return false; return false;
} }
info("Should have RTP stats for track " + track.id);
info("RTP stats: "+JSON.stringify(rtp));
var nrPackets = rtp[rtp.type == "outboundrtp" ? "packetsSent" var nrPackets = rtp[rtp.type == "outboundrtp" ? "packetsSent"
: "packetsReceived"]; : "packetsReceived"];
info("Track " + track.id + " has " + nrPackets + " " + info("Track " + track.id + " has " + nrPackets + " " +
@ -1429,12 +1433,44 @@ PeerConnectionWrapper.prototype = {
return nrPackets > 0; 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) info("Checking RTP packet flow for track " + track.id);
.then(stats => hasFlow(stats)? ok(true, "RTP flowing for track " + track.id) : var retry = Promise.race([checkStats.then(new Promise((resolve, reject)=>{
wait(delay).then(retry(1000))); info("checkStats completed for " + track.kind + " track " + track.id);
return retry(200); 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) var minimum = this.whenCreated - 1000; // on Windows XP (Bug 979649)
if (isWinXP) { if (isWinXP) {
todo(false, "Can't reliably test rtcp timestamps on WinXP (Bug 979649)"); 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 // Bug 1225729: On android, sometimes the first RTCP of the first
// test run gets this value, likely because no RTP has been sent yet. // test run gets this value, likely because no RTP has been sent yet.
if (res.timestamp != 2085978496000) { if (res.timestamp != 2085978496000) {
@ -1584,8 +1622,17 @@ PeerConnectionWrapper.prototype = {
ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived"); ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived");
ok(rem.packetsLost !== undefined, "Rtcp packetsLost"); ok(rem.packetsLost !== undefined, "Rtcp packetsLost");
ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived"); ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived");
if (!this.disableRtpCountChecking) { if (false) { // Bug 1325430 if (!this.disableRtpCountChecking) {
ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets"); // 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.bytesReceived <= res.bytesSent, "No more than sent bytes");
} }
ok(rem.jitter !== undefined, "Rtcp jitter"); ok(rem.jitter !== undefined, "Rtcp jitter");

View file

@ -46,6 +46,18 @@ runNetworkTest(() => {
// i.e., this order of `requestFrame(); draw();` should work. // i.e., this order of `requestFrame(); draw();` should work.
stream.requestFrame(); stream.requestFrame();
h.drawColor(canvas, h.red); 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() { function PC_REMOTE_WAIT_FOR_REMOTE_RED() {
return h.waitForPixelColor(mediaElement, h.red, 128, return h.waitForPixelColor(mediaElement, h.red, 128,

View file

@ -52,7 +52,7 @@ runNetworkTest(() => {
if (!program) { if (!program) {
ok(false, "Program should link"); ok(false, "Program should link");
return Promise.reject(); return Promise.reject("Program should link");
} }
gl.useProgram(program); gl.useProgram(program);
@ -100,6 +100,16 @@ runNetworkTest(() => {
}, },
function DRAW_LOCAL_RED() { function DRAW_LOCAL_RED() {
h.drawColor(canvas, h.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() { function WAIT_FOR_REMOTE_RED() {
return h.waitForPixelColor(vremote, h.red, 128, 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. // 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, // Next render will happen at next stable state, at the earliest,
// i.e., this order of `requestFrame(); draw();` should work. // i.e., this order of `requestFrame(); draw();` should work.
stream1.requestFrame();
h.drawColor(canvas1, h.red); 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() { function DRAW_LOCAL2_RED() {
// After requesting a frame it will be captured at the time of next render. // 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, // Next render will happen at next stable state, at the earliest,
// i.e., this order of `requestFrame(); draw();` should work. // i.e., this order of `requestFrame(); draw();` should work.
stream2.requestFrame();
h.drawColor(canvas2, h.red); 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() { function WAIT_FOR_REMOTE1_RED() {
return h.waitForPixelColor(vremote1, h.red, 128, return h.waitForPixelColor(vremote1, h.red, 128,

View file

@ -63,7 +63,8 @@
test.originalOffer.sdp, test._remote_answer.sdp); test.originalOffer.sdp, test._remote_answer.sdp);
info("Answer with RIDs: " + JSON.stringify(test._remote_answer)); 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=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(vremote, "Should have remote video element for pcRemote");
ok(vlocal.videoWidth > 0, "source width is positive"); ok(vlocal.videoWidth > 0, "source width is positive");
ok(vlocal.videoHeight > 0, "source height 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.videoWidth, vlocal.videoWidth, "sink is same width as source");
is(vremote.videoHeight, vlocal.videoHeight / 2, "sink is 1/2 height of source"); is(vremote.videoHeight, vlocal.videoHeight, "sink is same height as 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);
}, },
]); ]);

View file

@ -51,6 +51,18 @@ runNetworkTest(() => {
// i.e., this order of `requestFrame(); draw();` should work. // i.e., this order of `requestFrame(); draw();` should work.
stream1.requestFrame(); stream1.requestFrame();
h1.drawColor(canvas1, h1.red); 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() { function WAIT_FOR_REMOTE_RED() {
return h1.waitForPixelColor(vremote1, h1.red, 128, return h1.waitForPixelColor(vremote1, h1.red, 128,

View file

@ -390,22 +390,4 @@ MediaEngineCameraVideoSource::SetDirectListeners(bool aHasDirectListeners)
mHasDirectListeners = 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 } // namespace mozilla

View file

@ -11,15 +11,18 @@
// conflicts with #include of scoped_ptr.h // conflicts with #include of scoped_ptr.h
#undef FF #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 { 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 class MediaEngineCameraVideoSource : public MediaEngineVideoSource
{ {
public: public:

View file

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

View file

@ -19,6 +19,8 @@
#include "nsDirectoryServiceDefs.h" #include "nsDirectoryServiceDefs.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
// Avoid warnings about redefinition of WARN_UNUSED_RESULT
#include "ipc/IPCMessageUtils.h"
#include "VideoUtils.h" #include "VideoUtils.h"
#include "MediaEngineCameraVideoSource.h" #include "MediaEngineCameraVideoSource.h"
#include "VideoSegment.h" #include "VideoSegment.h"
@ -31,40 +33,29 @@
// WebRTC library includes follow // WebRTC library includes follow
#include "webrtc/common.h" #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 "CamerasChild.h"
#include "NullTransport.h" #include "NullTransport.h"
namespace webrtc {
class I420VideoFrame;
}
namespace mozilla { namespace mozilla {
/** /**
* The WebRTC implementation of the MediaEngine interface. * The WebRTC implementation of the MediaEngine interface.
*/ */
class MediaEngineRemoteVideoSource : public MediaEngineCameraVideoSource, class MediaEngineRemoteVideoSource : public MediaEngineCameraVideoSource,
public webrtc::ExternalRenderer public camera::FrameRelay
{ {
typedef MediaEngineCameraVideoSource Super; typedef MediaEngineCameraVideoSource Super;
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
// Old ExternalRenderer
void FrameSizeChange(unsigned int w, unsigned int h) override;
// ExternalRenderer // ExternalRenderer
int FrameSizeChange(unsigned int w, unsigned int h, int DeliverFrame(uint8_t* buffer,
unsigned int streams) override; const camera::VideoFrameProperties& properties) 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; };
// MediaEngineCameraVideoSource // MediaEngineCameraVideoSource
MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine, MediaEngineRemoteVideoSource(int aIndex, mozilla::camera::CaptureEngine aCapEngine,

View file

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

View file

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

View file

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

View file

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

View file

@ -8,18 +8,18 @@ include('/build/gyp.mozbuild')
webrtc_non_unified_sources = [ 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/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/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_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/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', # 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/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_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_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_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/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/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_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 '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/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/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/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/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/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/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/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'] GYP_DIRS += ['trunk']
@ -65,7 +68,6 @@ if CONFIG['MOZ_WEBRTC_SIGNALING']:
'signaling/src/common/browser_logging/CSFLog.cpp', 'signaling/src/common/browser_logging/CSFLog.cpp',
'signaling/src/jsep/JsepSessionImpl.cpp', 'signaling/src/jsep/JsepSessionImpl.cpp',
'signaling/src/media-conduit/AudioConduit.cpp', 'signaling/src/media-conduit/AudioConduit.cpp',
'signaling/src/media-conduit/CodecStatistics.cpp',
'signaling/src/media-conduit/MediaCodecVideoCodec.cpp', 'signaling/src/media-conduit/MediaCodecVideoCodec.cpp',
'signaling/src/media-conduit/VideoConduit.cpp', 'signaling/src/media-conduit/VideoConduit.cpp',
'signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp', 'signaling/src/media-conduit/WebrtcMediaCodecVP8VideoCodec.cpp',

View file

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

View file

@ -41,6 +41,18 @@ public:
scaleDownBy == constraints.scaleDownBy; 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 maxWidth;
uint32_t maxHeight; uint32_t maxHeight;
uint32_t maxFps; uint32_t maxFps;

View file

@ -8,7 +8,7 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "webrtc/common_types.h" #include "webrtc/transport.h"
namespace mozilla { namespace mozilla {
@ -18,6 +18,23 @@ namespace mozilla {
class NullTransport : public webrtc::Transport class NullTransport : public webrtc::Transport
{ {
public: 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) virtual int SendPacket(int channel, const void *data, size_t len)
{ {
(void) channel; (void) data; (void) channel; (void) data;
@ -29,7 +46,7 @@ public:
(void) channel; (void) data; (void) channel; (void) data;
return len; return len;
} }
#endif
NullTransport() {} NullTransport() {}
virtual ~NullTransport() {} virtual ~NullTransport() {}

View file

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

View file

@ -4,6 +4,7 @@
#include "logging.h" #include "logging.h"
#include "webrtc/config.h"
#include "signaling/src/jsep/JsepSessionImpl.h" #include "signaling/src/jsep/JsepSessionImpl.h"
#include <string> #include <string>
#include <set> #include <set>
@ -116,15 +117,35 @@ JsepSessionImpl::AddTrack(const RefPtr<JsepTrack>& track)
{ {
mLastError.clear(); mLastError.clear();
MOZ_ASSERT(track->GetDirection() == sdp::kSend); MOZ_ASSERT(track->GetDirection() == sdp::kSend);
MOZ_MTLOG(ML_DEBUG, "Adding track.");
if (track->GetMediaType() != SdpMediaSection::kApplication) { if (track->GetMediaType() != SdpMediaSection::kApplication) {
track->SetCNAME(mCNAME); track->SetCNAME(mCNAME);
// Establish minimum number of required SSRCs
if (track->GetSsrcs().empty()) { // Note that AddTrack is only for send direction
uint32_t ssrc; 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); nsresult rv = CreateSsrc(&ssrc);
NS_ENSURE_SUCCESS(rv, rv); 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 // Add RtpStreamId Extmap
// SdpDirectionAttribute::Direction is a bitmask // SdpDirectionAttribute::Direction is a bitmask
SdpDirectionAttribute::Direction addVideoExt = SdpDirectionAttribute::kInactive; SdpDirectionAttribute::Direction addVideoExt = SdpDirectionAttribute::kInactive;
SdpDirectionAttribute::Direction addAudioExt = SdpDirectionAttribute::kInactive;
for (auto constraintEntry: constraints) { for (auto constraintEntry: constraints) {
if (constraintEntry.rid != "") { if (constraintEntry.rid != "") {
if (it->mTrack->GetMediaType() == SdpMediaSection::kVideo) { switch (it->mTrack->GetMediaType()) {
addVideoExt = static_cast<SdpDirectionAttribute::Direction>(addVideoExt case SdpMediaSection::kVideo: {
| it->mTrack->GetDirection()); 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) { if (addVideoExt != SdpDirectionAttribute::kInactive) {
AddVideoRtpExtension("urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id", addVideoExt); 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); 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; return NS_OK;
} }
@ -2218,6 +2282,7 @@ JsepSessionImpl::SetupDefaultCodecs()
); );
mSupportedCodecs.values.push_back(ulpfec); mSupportedCodecs.values.push_back(ulpfec);
mSupportedCodecs.values.push_back(new JsepApplicationCodecDescription( mSupportedCodecs.values.push_back(new JsepApplicationCodecDescription(
"5000", "5000",
"webrtc-datachannel", "webrtc-datachannel",

View file

@ -261,6 +261,9 @@ JsepTrack::CreateEncodings(
const std::vector<JsepCodecDescription*>& negotiatedCodecs, const std::vector<JsepCodecDescription*>& negotiatedCodecs,
JsepTrackNegotiatedDetails* negotiatedDetails) 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; std::vector<SdpRidAttributeList::Rid> rids;
GetRids(remote, sdp::kRecv, &rids); // Get rids we will send GetRids(remote, sdp::kRecv, &rids); // Get rids we will send
NegotiateRids(rids, &mJsEncodeConstraints); NegotiateRids(rids, &mJsEncodeConstraints);
@ -294,8 +297,6 @@ JsepTrack::CreateEncodings(
encoding->mConstraints = jsConstraints.constraints; encoding->mConstraints = jsConstraints.constraints;
} }
} }
encoding->UpdateMaxBitrate(remote);
} }
} }

View file

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

View file

@ -38,16 +38,6 @@ public:
return false; 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; EncodingConstraints mConstraints;
std::string mRid; std::string mRid;

View file

@ -25,11 +25,11 @@
#include "webrtc/common.h" #include "webrtc/common.h"
#include "webrtc/modules/audio_processing/include/audio_processing.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_dtmf.h"
#include "webrtc/voice_engine/include/voe_errors.h" #include "webrtc/voice_engine/include/voe_errors.h"
#include "webrtc/voice_engine/voice_engine_impl.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 { namespace mozilla {
@ -89,7 +89,9 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoEBase->StopSend(mChannel); mPtrVoEBase->StopSend(mChannel);
mPtrVoEBase->StopReceive(mChannel); mPtrVoEBase->StopReceive(mChannel);
mPtrVoEBase->DeleteChannel(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! // We shouldn't delete the VoiceEngine until all these are released!
@ -103,21 +105,24 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoERTP_RTCP = nullptr; mPtrVoERTP_RTCP = nullptr;
mPtrRTP = nullptr; mPtrRTP = nullptr;
if(mVoiceEngine) if (mVoiceEngine)
{ {
webrtc::VoiceEngine::Delete(mVoiceEngine); webrtc::VoiceEngine::Delete(mVoiceEngine);
} }
} }
bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc) bool WebrtcAudioConduit::SetLocalSSRCs(const std::vector<unsigned int> & aSSRCs)
{ {
unsigned int oldSsrc; // This should hold true until the WebRTC.org VoE refactor
if (!GetLocalSSRC(&oldSsrc)) { 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"); MOZ_ASSERT(false, "GetLocalSSRC failed");
return false; return false;
} }
if (oldSsrc == ssrc) { if (oldSsrcs == aSSRCs) {
return true; return true;
} }
@ -126,7 +131,7 @@ bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc)
return false; return false;
} }
if (mPtrRTP->SetLocalSSRC(mChannel, ssrc)) { if (mPtrRTP->SetLocalSSRC(mChannel, aSSRCs[0])) {
return false; return false;
} }
@ -138,8 +143,12 @@ bool WebrtcAudioConduit::SetLocalSSRC(unsigned int ssrc)
return true; return true;
} }
bool WebrtcAudioConduit::GetLocalSSRC(unsigned int* ssrc) { std::vector<unsigned int> WebrtcAudioConduit::GetLocalSSRCs() const {
return !mPtrRTP->GetLocalSSRC(mChannel, *ssrc); 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) { bool WebrtcAudioConduit::GetRemoteSSRC(unsigned int* ssrc) {
@ -270,6 +279,13 @@ MediaConduitErrorCode WebrtcAudioConduit::Init()
return kMediaConduitSessionNotInited; 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))) if(!(mPtrVoENetwork = VoENetwork::GetInterface(mVoiceEngine)))
{ {
CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__); CSFLogError(logTag, "%s Unable to initialize VoENetwork", __FUNCTION__);
@ -310,13 +326,6 @@ MediaConduitErrorCode WebrtcAudioConduit::Init()
return kMediaConduitSessionNotInited; 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) if( (mChannel = mPtrVoEBase->CreateChannel()) == -1)
{ {
CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__); CSFLogError(logTag, "%s VoiceEngine Channel creation failed",__FUNCTION__);
@ -857,7 +866,6 @@ WebrtcAudioConduit::StartReceiving()
return kMediaConduitUnknownError; return kMediaConduitUnknownError;
} }
if(mPtrVoEBase->StartPlayout(mChannel) == -1) if(mPtrVoEBase->StartPlayout(mChannel) == -1)
{ {
CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__); CSFLogError(logTag, "%s Starting playout Failed", __FUNCTION__);
@ -871,9 +879,12 @@ WebrtcAudioConduit::StartReceiving()
//WebRTC::RTP Callback Implementation //WebRTC::RTP Callback Implementation
// Called on AudioGUM or MSG thread // 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 !defined(MOZILLA_EXTERNAL_LINKAGE)
if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) { if (MOZ_LOG_TEST(GetLatencyLog(), LogLevel::Debug)) {
@ -888,25 +899,30 @@ int WebrtcAudioConduit::SendPacket(int channel, const void* data, size_t len)
} }
#endif #endif
ReentrantMonitorAutoEnter enter(mTransportMonitor); 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 && if(mTransmitterTransport &&
(mTransmitterTransport->SendRtpPacket(data, len) == NS_OK)) (mTransmitterTransport->SendRtpPacket(data, len) == NS_OK))
{ {
CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__); CSFLogDebug(logTag, "%s Sent RTP Packet ", __FUNCTION__);
return len; return true;
} else { } else {
CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__); CSFLogError(logTag, "%s RTP Packet Send Failed ", __FUNCTION__);
return -1; return false;
} }
} }
// Called on WebRTC Process thread and perhaps others // 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__, __FUNCTION__,
channel,
(unsigned long) len, (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, // We come here if we have only one pipeline/conduit setup,
// such as for unidirectional streams. // 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. // Might be a sender report, might be a receiver report, we don't know.
CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__); CSFLogDebug(logTag, "%s Sent RTCP Packet ", __FUNCTION__);
return len; return true;
} else if(mTransmitterTransport && } else if(mTransmitterTransport &&
(mTransmitterTransport->SendRtcpPacket(data, len) == NS_OK)) { (mTransmitterTransport->SendRtcpPacket(data, len) == NS_OK)) {
CSFLogDebug(logTag, "%s Sent RTCP Packet (sender report) ", __FUNCTION__); CSFLogDebug(logTag, "%s Sent RTCP Packet (sender report) ", __FUNCTION__);
return len; return true;
} else { } else {
CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__); CSFLogError(logTag, "%s RTCP Packet Send Failed ", __FUNCTION__);
return -1; return false;
} }
} }

View file

@ -15,6 +15,7 @@
// Audio Engine Includes // Audio Engine Includes
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#include "webrtc/transport.h"
#include "webrtc/voice_engine/include/voe_base.h" #include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_volume_control.h" #include "webrtc/voice_engine/include/voe_volume_control.h"
#include "webrtc/voice_engine/include/voe_codec.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 * Concrete class for Audio session. Hooks up
* - media-source and target to external transport * - media-source and target to external transport
*/ */
class WebrtcAudioConduit:public AudioSessionConduit class WebrtcAudioConduit: public AudioSessionConduit
,public webrtc::Transport , public webrtc::Transport
{ {
public: public:
//VoiceEngine defined constant for Payload Name Size. //VoiceEngine defined constant for Payload Name Size.
@ -150,20 +151,22 @@ public:
* Webrtc transport implementation to send and receive RTP packet. * Webrtc transport implementation to send and receive RTP packet.
* AudioConduit registers itself as ExternalTransport to the VoiceEngine * 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. * Webrtc transport implementation to send and receive RTCP packet.
* AudioConduit registers itself as ExternalTransport to the VoiceEngine * 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 uint64_t CodecPluginID() override { return 0; }
virtual void DeleteStreams() override {} virtual void DeleteStreams() override {}
WebrtcAudioConduit(): explicit WebrtcAudioConduit():
mVoiceEngine(nullptr), mVoiceEngine(nullptr),
mTransportMonitor("WebrtcAudioConduit"), mTransportMonitor("WebrtcAudioConduit"),
mTransmitterTransport(nullptr), mTransmitterTransport(nullptr),
@ -188,8 +191,17 @@ public:
int GetChannel() { return mChannel; } int GetChannel() { return mChannel; }
webrtc::VoiceEngine* GetVoiceEngine() { return mVoiceEngine; } 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 GetRemoteSSRC(unsigned int* ssrc) override;
bool SetLocalCNAME(const char* cname) override; bool SetLocalCNAME(const char* cname) override;
bool GetVideoEncoderStats(double* framerateMean, bool GetVideoEncoderStats(double* framerateMean,

View file

@ -90,10 +90,15 @@ public:
bool mRembFbSet; bool mRembFbSet;
bool mFECFbSet; bool mFECFbSet;
uint32_t mTias;
EncodingConstraints mEncodingConstraints; EncodingConstraints mEncodingConstraints;
struct SimulcastEncoding { struct SimulcastEncoding {
std::string rid; std::string rid;
EncodingConstraints constraints; EncodingConstraints constraints;
bool operator==(const SimulcastEncoding& aOther) const {
return rid == aOther.rid &&
constraints == aOther.constraints;
}
}; };
std::vector<SimulcastEncoding> mSimulcastEncodings; std::vector<SimulcastEncoding> mSimulcastEncodings;
std::string mSpropParameterSets; std::string mSpropParameterSets;
@ -103,6 +108,28 @@ public:
uint8_t mPacketizationMode; uint8_t mPacketizationMode;
// TODO: add external negotiated SPS/PPS // 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, VideoCodecConfig(int type,
std::string name, std::string name,
const EncodingConstraints& constraints, const EncodingConstraints& constraints,
@ -110,6 +137,7 @@ public:
mType(type), mType(type),
mName(name), mName(name),
mFECFbSet(false), mFECFbSet(false),
mTias(0),
mEncodingConstraints(constraints), mEncodingConstraints(constraints),
mProfile(0x42), mProfile(0x42),
mConstraints(0xE0), 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 // Nothing seems to use this right now. Do we intend to support this
// someday? // someday?
bool RtcpFbAckIsSet(const std::string& type) const bool RtcpFbAckIsSet(const std::string& type) const

View file

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

View file

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

View file

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

View file

@ -17,13 +17,13 @@ class MediaCodecVideoCodec {
* Create encoder object for codec type |aCodecType|. Return |nullptr| when * Create encoder object for codec type |aCodecType|. Return |nullptr| when
* failed. * failed.
*/ */
static VideoEncoder* CreateEncoder(CodecType aCodecType); static WebrtcVideoEncoder* CreateEncoder(CodecType aCodecType);
/** /**
* Create decoder object for codec type |aCodecType|. Return |nullptr| when * Create decoder object for codec type |aCodecType|. Return |nullptr| when
* failed. * 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 kMediaConduitNACKStatusError, // Can't set NACK mode
kMediaConduitTMMBRStatusError, // Can't set TMMBR mode kMediaConduitTMMBRStatusError, // Can't set TMMBR mode
kMediaConduitFECStatusError, // Can't set FEC 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 #endif

View file

@ -9,20 +9,64 @@
#include "nsXPCOM.h" #include "nsXPCOM.h"
#include "nsDOMNavigationTiming.h" #include "nsDOMNavigationTiming.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/RefCounted.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/utils.h"
#include "CodecConfig.h" #include "CodecConfig.h"
#include "VideoTypes.h" #include "VideoTypes.h"
#include "MediaConduitErrors.h" #include "MediaConduitErrors.h"
#include "ImageContainer.h" #include "ImageContainer.h"
#include "webrtc/call.h"
#include "webrtc/config.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
namespace webrtc {
class I420VideoFrame;
}
#include <vector> #include <vector>
namespace webrtc {
class VideoFrame;
}
namespace mozilla { 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 * Abstract Interface for transporting RTP packets - audio/vidoeo
* The consumers of this interface are responsible for passing in * The consumers of this interface are responsible for passing in
@ -40,7 +84,7 @@ public:
* @param len : Length of the media packet * @param len : Length of the media packet
* @result : NS_OK on success, NS_ERROR_FAILURE otherwise * @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 * RTCP Transport Function to be implemented by concrete transport implementation
@ -48,7 +92,7 @@ public:
* @param len : Length of the RTCP packet * @param len : Length of the RTCP packet
* @result : NS_OK on success, NS_ERROR_FAILURE otherwise * @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) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TransportInterface)
}; };
@ -193,9 +237,15 @@ public:
*/ */
virtual MediaConduitErrorCode SetReceiverTransport(RefPtr<TransportInterface> aTransport) = 0; virtual MediaConduitErrorCode SetReceiverTransport(RefPtr<TransportInterface> aTransport) = 0;
virtual bool SetLocalSSRC(unsigned int ssrc) = 0; /* Sets the local SSRCs
virtual bool GetLocalSSRC(unsigned int* ssrc) = 0; * @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 GetRemoteSSRC(unsigned int* ssrc) = 0;
virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
virtual bool SetLocalCNAME(const char* cname) = 0; virtual bool SetLocalCNAME(const char* cname) = 0;
/** /**
@ -265,10 +315,12 @@ class VideoSessionConduit : public MediaSessionConduit
public: public:
/** /**
* Factory function to create and initialize a Video Conduit Session * 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 * of failure
*/ */
static RefPtr<VideoSessionConduit> Create(); static RefPtr<VideoSessionConduit> Create(RefPtr<WebRtcCallWrapper> aCall);
enum FrameRequestType enum FrameRequestType
{ {
@ -287,15 +339,28 @@ public:
virtual Type type() const { return VIDEO; } 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. * Function to attach Renderer end-point of the Media-Video conduit.
* @param aRenderer : Reference to the concrete Video renderer implementation * @param aRenderer : Reference to the concrete Video renderer implementation
* Note: Multiple invocations of this API shall remove an existing renderer * Note: Multiple invocations of this API shall remove an existing renderer
* and attaches the new to the Conduit. * 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 void DetachRenderer() = 0;
virtual bool SetRemoteSSRC(unsigned int ssrc) = 0;
/** /**
* Function to deliver a capture video frame for encoding and transport * Function to deliver a capture video frame for encoding and transport
* @param video_frame: pointer to captured video-frame. * @param video_frame: pointer to captured video-frame.
@ -313,7 +378,7 @@ public:
unsigned short height, unsigned short height,
VideoType video_type, VideoType video_type,
uint64_t capture_time) = 0; 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; virtual MediaConduitErrorCode ConfigureCodecMode(webrtc::VideoCodecMode) = 0;
/** /**
@ -335,31 +400,7 @@ public:
* *
*/ */
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs( virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
const std::vector<VideoCodecConfig* >& recvCodecConfigList) = 0; 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;
/** /**
* These methods allow unit tests to double-check that the * These methods allow unit tests to double-check that the
@ -410,11 +451,13 @@ class AudioSessionConduit : public MediaSessionConduit
{ {
public: public:
/** /**
* Factory function to create and initialize an Audio Conduit Session * Factory function to create and initialize an Audio Conduit Session
* return: Concrete AudioSessionConduitObject or nullptr in the case * @param webrtc::Call instance shared by paired audio and video
* of failure * media conduits
*/ * @result Concrete AudioSessionConduitObject or nullptr in the case
* of failure
*/
static RefPtr<AudioSessionConduit> Create(); static RefPtr<AudioSessionConduit> Create();
virtual ~AudioSessionConduit() {} virtual ~AudioSessionConduit() {}

View file

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

View file

@ -18,13 +18,13 @@ class OMXVideoCodec {
* Create encoder object for codec type |aCodecType|. Return |nullptr| when * Create encoder object for codec type |aCodecType|. Return |nullptr| when
* failed. * failed.
*/ */
static VideoEncoder* CreateEncoder(CodecType aCodecType); static WebrtcVideoEncoder* CreateEncoder(CodecType aCodecType);
/** /**
* Create decoder object for codec type |aCodecType|. Return |nullptr| when * Create decoder object for codec type |aCodecType|. Return |nullptr| when
* failed. * 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_ #ifndef VIDEO_SESSION_H_
#define VIDEO_SESSION_H_ #define VIDEO_SESSION_H_
#include "nsAutoPtr.h"
#include "mozilla/Attributes.h"
#include "mozilla/Atomics.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 "MediaConduitInterface.h"
#include "MediaEngineWrapper.h" #include "MediaEngineWrapper.h"
#include "CodecStatistics.h" #include "RunningStat.h"
#include "LoadManagerFactory.h"
#include "LoadManager.h"
#include "runnable_utils.h" #include "runnable_utils.h"
// conflicts with #include of scoped_ptr.h // conflicts with #include of scoped_ptr.h
#undef FF #undef FF
// Video Engine Includes // Video Engine Includes
#include "webrtc/call.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#ifdef FF #ifdef FF
#undef FF // Avoid name collision between scoped_ptr.h and nsCRTGlue.h. #undef FF // Avoid name collision between scoped_ptr.h and nsCRTGlue.h.
#endif #endif
#include "webrtc/modules/video_coding/codecs/interface/video_codec_interface.h" #include "webrtc/video_decoder.h"
#include "webrtc/video_engine/include/vie_base.h" #include "webrtc/video_encoder.h"
#include "webrtc/video_engine/include/vie_capture.h" #include <functional>
#include "webrtc/video_engine/include/vie_codec.h" #include <memory>
#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"
/** This file hosts several structures identifying different aspects /** This file hosts several structures identifying different aspects
* of a RTP Session. * 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 { namespace mozilla {
const int kVideoMtu = 1200;
const int kQpMax = 56;
class WebrtcAudioConduit; class WebrtcAudioConduit;
class nsThread; class nsThread;
// Interface of external video encoder for WebRTC. // Interface of external video encoder for WebRTC.
class WebrtcVideoEncoder:public VideoEncoder class WebrtcVideoEncoder : public VideoEncoder
,public webrtc::VideoEncoder , public webrtc::VideoEncoder
{}; {
};
// Interface of external video decoder for WebRTC. // Interface of external video decoder for WebRTC.
class WebrtcVideoDecoder:public VideoDecoder class WebrtcVideoDecoder : public VideoDecoder
,public webrtc::VideoDecoder , public webrtc::VideoDecoder
{}; {
};
/** /**
* Concrete class for Video session. Hooks up * Concrete class for Video session. Hooks up
@ -65,12 +60,30 @@ class WebrtcVideoDecoder:public VideoDecoder
*/ */
class WebrtcVideoConduit : public VideoSessionConduit class WebrtcVideoConduit : public VideoSessionConduit
, public webrtc::Transport , public webrtc::Transport
, public webrtc::ExternalRenderer , public webrtc::VideoRenderer
{ {
public: 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. //VoiceEngine defined constant for Payload Name Size.
static const unsigned int CODEC_PLNAME_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. * 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. * 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 * Note: Multiple invocations of this API shall remove an existing renderer
* and attaches the new to the Conduit. * 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; virtual void DetachRenderer() override;
/** /**
* APIs used by the registered external transport to this Conduit to * APIs used by the registered external transport to this Conduit to
* feed in received RTP Frames to the VideoEngine for decoding * 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 * APIs used by the registered external transport to this Conduit to
* feed in received RTP Frames to the VideoEngine for decoding * 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 StopTransmitting() override;
virtual MediaConduitErrorCode StartTransmitting() override; virtual MediaConduitErrorCode StartTransmitting() override;
@ -127,7 +140,7 @@ public:
* transmission sub-system on the engine. * transmission sub-system on the engine.
*/ */
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs( 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 * 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 width, height: dimensions of the frame
* @param cap: user-enforced max bitrate, or 0 * @param cap: user-enforced max bitrate, or 0
* @param aLastFramerateTenths: holds the current input framerate * @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, void SelectBitrates(unsigned short width,
unsigned short height, unsigned short height,
unsigned int cap, int cap,
mozilla::Atomic<int32_t, mozilla::Relaxed>& aLastFramerateTenths, int32_t aLastFramerateTenths,
unsigned int& out_min, webrtc::VideoStream& aVideoStream);
unsigned int& out_start,
unsigned int& out_max);
/** /**
* Function to select and change the encoding resolution based on incoming frame size * Function to select and change the encoding resolution based on incoming frame size
@ -160,7 +171,7 @@ public:
*/ */
bool SelectSendResolution(unsigned short width, bool SelectSendResolution(unsigned short width,
unsigned short height, unsigned short height,
webrtc::I420VideoFrame *frame); webrtc::VideoFrame* frame);
/** /**
* Function to reconfigure the current send codec for a different * Function to reconfigure the current send codec for a different
@ -170,7 +181,7 @@ public:
*/ */
nsresult ReconfigureSendCodec(unsigned short width, nsresult ReconfigureSendCodec(unsigned short width,
unsigned short height, unsigned short height,
webrtc::I420VideoFrame *frame); webrtc::VideoFrame* frame);
/** /**
* Function to select and change the encoding frame rate based on incoming frame rate * Function to select and change the encoding frame rate based on incoming frame rate
@ -178,7 +189,10 @@ public:
* @param current framerate * @param current framerate
* @result new 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 * 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 * This ensures the inserted video-frames can be transmitted by the conduit
*/ */
virtual MediaConduitErrorCode SendVideoFrame(unsigned char* video_frame, virtual MediaConduitErrorCode SendVideoFrame(unsigned char* video_frame,
unsigned int video_frame_length, unsigned int video_frame_length,
unsigned short width, unsigned short width,
unsigned short height, unsigned short height,
VideoType video_type, VideoType video_type,
uint64_t capture_time) override; uint64_t capture_time) override;
virtual MediaConduitErrorCode SendVideoFrame(webrtc::I420VideoFrame& frame) override; virtual MediaConduitErrorCode SendVideoFrame(webrtc::VideoFrame& frame) override;
/** /**
* Set an external encoder object |encoder| to the payload type |pltype| * webrtc::Transport method implementation
* 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 implementation to send and receive RTP packet. * 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. * Webrtc transport implementation to send and receive RTCP packet.
* VideoConduit registers itself as ExternalTransport to the VideoEngine * 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. * webrtc::VideoRenderer implementation
* Raw I420 Frames are delivred to the VideoConduit by the VideoEngine * ------------------------------------
* webrtc::VideoFrames are delivered to the VideoConduit by the VideoReceiveStream.
*/ */
virtual int FrameSizeChange(unsigned int, unsigned int, unsigned int) override; virtual void RenderFrame(const webrtc::VideoFrame& video_frame,
int time_to_render_ms) 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;
/** /**
* Does DeliverFrame() support a null buffer and non-null handle * webrtc::VideoRenderer implementation
* (video texture)? * ------------------------------------
* B2G support it (when using HW video decoder with graphic buffer output).
* XXX Investigate! Especially for Android
*/ */
virtual bool IsTextureSupported() override { virtual bool IsTextureSupported() const override {
#ifdef WEBRTC_GONK #ifdef WEBRTC_GONK
return true; return true;
#else #else
@ -259,6 +251,14 @@ public:
#endif #endif
} }
/**
* webrtc::VideoRenderer implementation
* ------------------------------------
*/
virtual bool SmoothsRenderedFrames() const override {
return false;
}
virtual uint64_t CodecPluginID() override; virtual uint64_t CodecPluginID() override;
unsigned short SendingWidth() override { unsigned short SendingWidth() override {
@ -285,17 +285,17 @@ public:
return 0; return 0;
} }
WebrtcVideoConduit(); explicit WebrtcVideoConduit(RefPtr<WebRtcCallWrapper> aCall);
virtual ~WebrtcVideoConduit(); virtual ~WebrtcVideoConduit();
MediaConduitErrorCode InitMain(); MediaConduitErrorCode InitMain();
virtual MediaConduitErrorCode Init(); virtual MediaConduitErrorCode Init();
int GetChannel() { return mChannel; } std::vector<unsigned int> GetLocalSSRCs() const override;
webrtc::VideoEngine* GetVideoEngine() { return mVideoEngine; } bool SetLocalSSRCs(const std::vector<unsigned int> & ssrcs) override;
bool GetLocalSSRC(unsigned int* ssrc) override;
bool SetLocalSSRC(unsigned int ssrc) override;
bool GetRemoteSSRC(unsigned int* ssrc) override; bool GetRemoteSSRC(unsigned int* ssrc) override;
bool SetRemoteSSRC(unsigned int ssrc) override;
bool SetLocalCNAME(const char* cname) override; bool SetLocalCNAME(const char* cname) override;
bool GetVideoEncoderStats(double* framerateMean, bool GetVideoEncoderStats(double* framerateMean,
double* framerateStdDev, double* framerateStdDev,
@ -325,25 +325,91 @@ public:
private: private:
DISALLOW_COPY_AND_ASSIGN(WebrtcVideoConduit); DISALLOW_COPY_AND_ASSIGN(WebrtcVideoConduit);
static inline bool OnThread(nsIEventTarget *thread) /** Shared statistics for receive and transmit video streams
{ */
bool on; class StreamStatistics {
nsresult rv; public:
rv = thread->IsOnCurrentThread(&on); 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) { * Statistics for sending streams
MOZ_ASSERT(NS_SUCCEEDED(rv)); */
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))) { /** Statistics for receiving streams
return false; */
} class ReceiveStreamStatistics : public StreamStatistics {
return on; public:
} /**
* Returns the number of discarded packets
//Local database of currently applied receive codecs * @param aOutDiscPackets: number of discarded packets
typedef std::vector<VideoCodecConfig* > RecvCodecList; */
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 //Function to convert between WebRTC and Conduit codec structures
void CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo, void CodecConfigToWebRTCCodec(const VideoCodecConfig* codecInfo,
@ -355,36 +421,37 @@ private:
//Utility function to dump recv codec database //Utility function to dump recv codec database
void DumpCodecDB() const; void DumpCodecDB() const;
bool CodecsDifferent(const nsTArray<UniquePtr<VideoCodecConfig>>& a,
const nsTArray<UniquePtr<VideoCodecConfig>>& b);
// Video Latency Test averaging filter // Video Latency Test averaging filter
void VideoLatencyUpdate(uint64_t new_sample); void VideoLatencyUpdate(uint64_t new_sample);
// Utility function to determine RED and ULPFEC payload types MediaConduitErrorCode CreateSendStream();
bool DetermineREDAndULPFECPayloadTypes(uint8_t &payload_type_red, uint8_t &payload_type_ulpfec); 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; mozilla::ReentrantMonitor mTransportMonitor;
RefPtr<TransportInterface> mTransmitterTransport; RefPtr<TransportInterface> mTransmitterTransport;
RefPtr<TransportInterface> mReceiverTransport; RefPtr<TransportInterface> mReceiverTransport;
RefPtr<VideoRenderer> mRenderer; RefPtr<mozilla::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;
// Engine state we are concerned with. // Engine state we are concerned with.
mozilla::Atomic<bool> mEngineTransmitting; //If true ==> Transmit Sub-system is up and running 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 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 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; nsAutoPtr<VideoCodecConfig> mCurSendCodecConfig;
bool mInReconfig; bool mInReconfig;
@ -400,10 +467,11 @@ private:
unsigned short mNumReceivingStreams; unsigned short mNumReceivingStreams;
bool mVideoLatencyTestEnable; bool mVideoLatencyTestEnable;
uint64_t mVideoLatencyAvg; uint64_t mVideoLatencyAvg;
uint32_t mMinBitrate; int mMinBitrate;
uint32_t mStartBitrate; int mStartBitrate;
uint32_t mMaxBitrate; int mPrefMaxBitrate;
uint32_t mMinBitrateEstimate; int mMinBitrateEstimate;
int mNegotiatedMaxBitrate;
bool mRtpStreamIdEnabled; bool mRtpStreamIdEnabled;
uint8_t mRtpStreamIdExtId; uint8_t mRtpStreamIdExtId;
@ -414,16 +482,33 @@ private:
RefPtr<WebrtcAudioConduit> mSyncedTo; 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; nsAutoPtr<LoadManager> mLoadManager;
webrtc::VideoCodecMode mCodecMode; 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 } // end namespace

View file

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

View file

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

View file

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

View file

@ -5,6 +5,8 @@
#ifndef WebrtcMediaCodecVP8VideoCodec_h__ #ifndef WebrtcMediaCodecVP8VideoCodec_h__
#define WebrtcMediaCodecVP8VideoCodec_h__ #define WebrtcMediaCodecVP8VideoCodec_h__
#include <jni.h>
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
@ -13,6 +15,8 @@
#include "AudioConduit.h" #include "AudioConduit.h"
#include "VideoConduit.h" #include "VideoConduit.h"
#include "webrtc/modules/video_coding/include/video_codec_interface.h"
namespace mozilla { namespace mozilla {
struct EncodedFrame { struct EncodedFrame {
@ -37,9 +41,9 @@ public:
int32_t numberOfCores, int32_t numberOfCores,
size_t maxPayloadSize) override; 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 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; 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", CODEC_LOGD("Decoder NewFrame: %dx%d, timestamp %lld, renderTimeMs %lld",
picSize.width, picSize.height, timestamp, renderTimeMs); picSize.width, picSize.height, timestamp, renderTimeMs);
nsAutoPtr<webrtc::I420VideoFrame> videoFrame(new webrtc::I420VideoFrame( nsAutoPtr<webrtc::VideoFrame> videoFrame(new webrtc::VideoFrame(
new ImageNativeHandle(grallocImage.forget()), new ImageNativeHandle(grallocImage.forget()),
picSize.width, picSize.width,
picSize.height, picSize.height,
@ -857,9 +857,9 @@ WebrtcOMXH264VideoEncoder::InitEncode(const webrtc::VideoCodec* aCodecSettings,
} }
int32_t int32_t
WebrtcOMXH264VideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage, WebrtcOMXH264VideoEncoder::Encode(const webrtc::VideoFrame& aInputImage,
const webrtc::CodecSpecificInfo* aCodecSpecificInfo, const webrtc::CodecSpecificInfo* aCodecSpecificInfo,
const std::vector<webrtc::VideoFrameType>* aFrameTypes) const std::vector<webrtc::FrameType>* aFrameTypes)
{ {
MOZ_ASSERT(mOMX != nullptr); MOZ_ASSERT(mOMX != nullptr);
if (mOMX == nullptr) { if (mOMX == nullptr) {
@ -973,7 +973,7 @@ WebrtcOMXH264VideoEncoder::Encode(const webrtc::I420VideoFrame& aInputImage,
#endif #endif
} }
// Wrap I420VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder. // Wrap VideoFrame input with PlanarYCbCrImage for OMXVideoEncoder.
layers::PlanarYCbCrData yuvData; layers::PlanarYCbCrData yuvData;
yuvData.mYChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kYPlane)); yuvData.mYChannel = const_cast<uint8_t*>(aInputImage.buffer(webrtc::kYPlane));
yuvData.mYSize = gfx::IntSize(aInputImage.width(), aInputImage.height()); yuvData.mYSize = gfx::IntSize(aInputImage.width(), aInputImage.height());

View file

@ -42,9 +42,9 @@ public:
int32_t aNumOfCores, int32_t aNumOfCores,
size_t aMaxPayloadSize) override; 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 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; virtual int32_t RegisterEncodeCompleteCallback(webrtc::EncodedImageCallback* aCallback) override;

View file

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

View file

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

View file

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

View file

@ -27,16 +27,6 @@
#include "MediaEngine.h" #include "MediaEngine.h"
#endif #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 #ifdef MOZILLA_INTERNAL_API
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#endif #endif
@ -167,6 +157,8 @@ NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
config->mTias = aDetails.GetTias();
for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) { for (size_t i = 0; i < aDetails.GetEncodingCount(); ++i) {
const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i)); const JsepTrackEncoding& jsepEncoding(aDetails.GetEncoding(i));
if (jsepEncoding.HasFormat(codec->mDefaultPt)) { if (jsepEncoding.HasFormat(codec->mDefaultPt)) {
@ -176,6 +168,7 @@ NegotiatedDetailsToVideoCodecConfigs(const JsepTrackNegotiatedDetails& aDetails,
config->mSimulcastEncodings.push_back(encoding); config->mSimulcastEncodings.push_back(encoding);
} }
} }
aConfigs->values.push_back(config); aConfigs->values.push_back(config);
} }
@ -453,12 +446,14 @@ MediaPipelineFactory::CreateOrUpdateMediaPipeline(
RefPtr<MediaSessionConduit> conduit; RefPtr<MediaSessionConduit> conduit;
if (aTrack.GetMediaType() == SdpMediaSection::kAudio) { if (aTrack.GetMediaType() == SdpMediaSection::kAudio) {
rv = GetOrCreateAudioConduit(aTrackPair, aTrack, &conduit); rv = GetOrCreateAudioConduit(aTrackPair, aTrack, &conduit);
if (NS_FAILED(rv)) if (NS_FAILED(rv)) {
return rv; return rv;
}
} else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) { } else if (aTrack.GetMediaType() == SdpMediaSection::kVideo) {
rv = GetOrCreateVideoConduit(aTrackPair, aTrack, &conduit); rv = GetOrCreateVideoConduit(aTrackPair, aTrack, &conduit);
if (NS_FAILED(rv)) if (NS_FAILED(rv)) {
return rv; return rv;
}
} else { } else {
// We've created the TransportFlow, nothing else to do here. // We've created the TransportFlow, nothing else to do here.
return NS_OK; return NS_OK;
@ -730,17 +725,16 @@ MediaPipelineFactory::GetOrCreateAudioConduit(
if (!aTrackPair.mSending) { if (!aTrackPair.mSending) {
// No send track, but we still need to configure an SSRC for receiver // No send track, but we still need to configure an SSRC for receiver
// reports. // reports.
if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) { if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
} else { } else {
// For now we only expect to have one ssrc per local track.
auto ssrcs = aTrack.GetSsrcs(); auto ssrcs = aTrack.GetSsrcs();
if (!ssrcs.empty()) { if (!ssrcs.empty()) {
if (!conduit->SetLocalSSRC(ssrcs.front())) { if (!conduit->SetLocalSSRCs(ssrcs)) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
@ -786,7 +780,6 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
const JsepTrack& aTrack, const JsepTrack& aTrack,
RefPtr<MediaSessionConduit>* aConduitp) RefPtr<MediaSessionConduit>* aConduitp)
{ {
if (!aTrack.GetNegotiatedDetails()) { if (!aTrack.GetNegotiatedDetails()) {
MOZ_ASSERT(false, "Track is missing negotiated details"); MOZ_ASSERT(false, "Track is missing negotiated details");
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
@ -798,7 +791,7 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
mPCMedia->GetVideoConduit(aTrackPair.mLevel); mPCMedia->GetVideoConduit(aTrackPair.mLevel);
if (!conduit) { if (!conduit) {
conduit = VideoSessionConduit::Create(); conduit = VideoSessionConduit::Create(mPCMedia->mCall);
if (!conduit) { if (!conduit) {
MOZ_MTLOG(ML_ERROR, "Could not create video conduit"); MOZ_MTLOG(ML_ERROR, "Could not create video conduit");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -822,103 +815,80 @@ MediaPipelineFactory::GetOrCreateVideoConduit(
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
const std::vector<uint32_t>* ssrcs;
if (receiving) { 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) { if (aTrackPair.mSending) {
auto ssrcs = &aTrackPair.mSending->GetSsrcs(); ssrcs = &aTrackPair.mSending->GetSsrcs();
if (!ssrcs->empty()) { if (!ssrcs->empty()) {
if (!conduit->SetLocalSSRC(ssrcs->front())) { conduit->SetLocalSSRCs(*ssrcs);
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed(1)");
return NS_ERROR_FAILURE;
}
} else {
MOZ_MTLOG(ML_ERROR, "Sending without an SSRC??");
return NS_ERROR_FAILURE;
} }
} else { } else {
// No send track, but we still need to configure an SSRC for receiver // No send track, but we still need to configure an SSRC for receiver
// reports. // reports.
if (!conduit->SetLocalSSRC(aTrackPair.mRecvonlySsrc)) { if (!conduit->SetLocalSSRCs(std::vector<unsigned int>(1,aTrackPair.mRecvonlySsrc))) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed(2)"); MOZ_MTLOG(ML_ERROR, "SetLocalSSRCs failed");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} }
// Prune out stuff we cannot actually do. We should work to eliminate the ssrcs = &aTrack.GetSsrcs();
// need for this. // NOTE(pkerr) - this is new behavior. Needed because the CreateVideoReceiveStream
bool configuredH264 = false; // method of the Call API will assert (in debug) and fail if a value is not provided
for (size_t i = 0; i < configs.values.size();) { // for the remote_ssrc that will be used by the far-end sender.
// TODO(bug 1200768): We can only handle configuring one recv H264 codec if (ssrcs->empty()) {
if (configuredH264 && (configs.values[i]->mName == "H264")) { MOZ_MTLOG(ML_ERROR, "No SSRC set for receive track");
delete configs.values[i]; return NS_ERROR_FAILURE;
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;
} }
conduit->SetRemoteSSRC(ssrcs->front());
auto error = conduit->ConfigureRecvMediaCodecs(configs.values); auto error = conduit->ConfigureRecvMediaCodecs(configs.values);
if (error) { if (error) {
MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error); MOZ_MTLOG(ML_ERROR, "ConfigureRecvMediaCodecs failed: " << error);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
} else { } else { //Create a send side
// For now we only expect to have one ssrc per local track. // For now we only expect to have one ssrc per local track.
auto ssrcs = aTrack.GetSsrcs(); ssrcs = &aTrack.GetSsrcs();
if (!ssrcs.empty()) { if (ssrcs->empty()) {
if (!conduit->SetLocalSSRC(ssrcs.front())) { MOZ_MTLOG(ML_ERROR, "No SSRC set for send track");
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed"); return NS_ERROR_FAILURE;
return NS_ERROR_FAILURE; }
}
if (!conduit->SetLocalSSRCs(*ssrcs)) {
MOZ_MTLOG(ML_ERROR, "SetLocalSSRC failed");
return NS_ERROR_FAILURE;
} }
conduit->SetLocalCNAME(aTrack.GetCNAME().c_str()); conduit->SetLocalCNAME(aTrack.GetCNAME().c_str());
rv = ConfigureVideoCodecMode(aTrack,*conduit); rv = ConfigureVideoCodecMode(aTrack, *conduit);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return 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]); 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) { if (error) {
MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error); MOZ_MTLOG(ML_ERROR, "ConfigureSendMediaCodec failed: " << error);
return NS_ERROR_FAILURE; 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; *aConduitp = conduit;
return NS_OK; return NS_OK;
@ -970,107 +940,5 @@ MediaPipelineFactory::ConfigureVideoCodecMode(const JsepTrack& aTrack,
return NS_OK; 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 } // namespace mozilla

View file

@ -52,10 +52,6 @@ private:
const JsepTrack& aTrack, const JsepTrack& aTrack,
RefPtr<MediaSessionConduit>* aConduitp); RefPtr<MediaSessionConduit>* aConduitp);
MediaConduitErrorCode EnsureExternalCodec(VideoSessionConduit& aConduit,
VideoCodecConfig* aConfig,
bool aIsSend);
nsresult CreateOrGetTransportFlow(size_t aLevel, bool aIsRtcp, nsresult CreateOrGetTransportFlow(size_t aLevel, bool aIsRtcp,
const JsepTransport& transport, const JsepTransport& transport,
RefPtr<TransportFlow>* out); 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 // We update the media pipelines here so we can apply different codec
// settings for different sources (e.g. screensharing as opposed to camera.) // 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. // 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); pco->OnReplaceTrackSuccess(jrv);
if (jrv.Failed()) { if (jrv.Failed()) {
@ -3108,7 +3112,11 @@ PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState,
// transports, but nothing further needs to be done. // transports, but nothing further needs to be done.
mMedia->ActivateOrRemoveTransports(*mJsepSession); mMedia->ActivateOrRemoveTransports(*mJsepSession);
if (!rollback) { 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(); InitializeDataChannel();
mMedia->StartIceChecks(*mJsepSession); mMedia->StartIceChecks(*mJsepSession);
} }
@ -3663,15 +3671,17 @@ PeerConnectionImpl::ExecuteStatsQuery_s(RTCStatsQuery *query) {
idstr.AppendLiteral("_"); idstr.AppendLiteral("_");
idstr.AppendInt(mp.level()); idstr.AppendInt(mp.level());
// TODO(@@NG):ssrcs handle Conduits having multiple stats at the same level
// This is pending spec work
// Gather pipeline stats. // Gather pipeline stats.
switch (mp.direction()) { switch (mp.direction()) {
case MediaPipeline::TRANSMIT: { case MediaPipeline::TRANSMIT: {
nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr; nsString localId = NS_LITERAL_STRING("outbound_rtp_") + idstr;
nsString remoteId; nsString remoteId;
nsString ssrc; nsString ssrc;
unsigned int ssrcval; std::vector<unsigned int> ssrcvals = mp.Conduit()->GetLocalSSRCs();
if (mp.Conduit()->GetLocalSSRC(&ssrcval)) { if (!ssrcvals.empty()) {
ssrc.AppendInt(ssrcval); ssrc.AppendInt(ssrcvals[0]);
} }
{ {
// First, fill in remote stat with rtcp receiver data, if present. // 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"; 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 nsresult
PeerConnectionMedia::ReplaceTrack(const std::string& aOldStreamId, PeerConnectionMedia::ReplaceTrack(const std::string& aOldStreamId,
const std::string& aOldTrackId, const std::string& aOldTrackId,
@ -406,6 +414,9 @@ nsresult PeerConnectionMedia::Init(const std::vector<NrIceStunServer>& stun_serv
} }
ConnectSignals(mIceCtxHdlr->ctx().get()); ConnectSignals(mIceCtxHdlr->ctx().get());
// This webrtc:Call instance will be shared by audio and video media conduits.
mCall = CreateCall();
return NS_OK; return NS_OK;
} }
@ -567,6 +578,7 @@ nsresult PeerConnectionMedia::UpdateMediaPipelines(
JsepTrackPair pair = *i; JsepTrackPair pair = *i;
if (pair.mReceiving) { if (pair.mReceiving) {
rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mReceiving); rv = factory.CreateOrUpdateMediaPipeline(pair, *pair.mReceiving);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;

View file

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

View file

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

View file

@ -34,7 +34,7 @@
#include "mtransport_test_utils.h" #include "mtransport_test_utils.h"
#include "runnable_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.h"
#include "FakeIPC.cpp" #include "FakeIPC.cpp"

View file

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

View file

@ -6,7 +6,7 @@
vars = { vars = {
'extra_gyp_flag': '-Dextra_gyp_flag=0', 'extra_gyp_flag': '-Dextra_gyp_flag=0',
'chromium_git': 'https://chromium.googlesource.com', '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 # NOTE: Prefer revision numbers to tags for svn deps. Use http rather than
@ -17,14 +17,14 @@ deps = {
'src/third_party/gflags/src': 'src/third_party/gflags/src':
Var('chromium_git') + '/external/gflags/src@e7390f9185c75f8d902c05ed7d20bb94eb914d0c', # from svn revision 82 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 Var('chromium_git') + '/external/webrtc/deps/third_party/junit@f35596b476aa6e62fd3b3857b9942ddcd13ce35e', # from svn revision 3367
} }
deps_os = { deps_os = {
'win': { 'win': {
'src/third_party/winsdk_samples/src': '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. # WebRTC production code.
'-base', '-base',
'-chromium', '-chromium',
'+external/webrtc/webrtc', # Android platform build.
'+gflags', '+gflags',
'+libyuv', '+libyuv',
'+net', '+net',
'+talk', '+talk',
'+testing', '+testing',
'+third_party', '+third_party',
'+unicode',
'+webrtc', '+webrtc',
] '+vpx',
# checkdeps.py shouldn't check include paths for files in these dirs:
skip_child_includes = [
'webrtc/overrides',
] ]
hooks = [ hooks = [
@ -72,6 +70,21 @@ hooks = [
'pattern': '.', 'pattern': '.',
'action': ['python', 'src/setup_links.py'], '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 # Pull sanitizer-instrumented third-party libraries if requested via
# GYP_DEFINES. This could be done as part of sync_chromium.py above # GYP_DEFINES. This could be done as part of sync_chromium.py above
@ -89,6 +102,7 @@ hooks = [
'--recursive', '--recursive',
'--num_threads=10', '--num_threads=10',
'--no_auth', '--no_auth',
'--quiet',
'--bucket', 'chromium-webrtc-resources', '--bucket', 'chromium-webrtc-resources',
'src/resources'], 'src/resources'],
}, },

View file

@ -1,4 +1,3 @@
andrew@webrtc.org
henrika@webrtc.org henrika@webrtc.org
mflodman@webrtc.org mflodman@webrtc.org
niklas.enbom@webrtc.org niklas.enbom@webrtc.org
@ -6,6 +5,7 @@ tina.legrand@webrtc.org
tommi@webrtc.org tommi@webrtc.org
per-file .gitignore=* per-file .gitignore=*
per-file AUTHORS=* per-file AUTHORS=*
per-file .gn=kjellander@webrtc.org
per-file BUILD.gn=kjellander@webrtc.org per-file BUILD.gn=kjellander@webrtc.org
per-file DEPS=* per-file DEPS=*
per-file PRESUBMIT.py=kjellander@webrtc.org 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_name%': 'Developer Build',
'android_app_version_code%': 0, 'android_app_version_code%': 0,
'sas_dll_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))', 'sas_dll_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(sas_dll_path))',
'wix_exists': '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))', 'wix_exists': 0, # '<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(wix_path))',
'windows_sdk_default_path': '<(DEPTH)/third_party/platformsdk_win8/files', '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': [ 'conditions': [
['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', { #['"<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(windows_sdk_default_path))"=="True"', {
'windows_sdk_path%': '<(windows_sdk_default_path)', # 'windows_sdk_path%': '<(windows_sdk_default_path)',
}, { #}, {
'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0', # '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"', { #['OS=="win" and "<!(<(PYTHON) <(DEPTH)/build/dir_exists.py <(directx_sdk_default_path))"=="True"', {
'directx_sdk_path%': '<(directx_sdk_default_path)', # 'directx_sdk_path%': '<(directx_sdk_default_path)',
}, { #}, {
'directx_sdk_path%': '$(DXSDK_DIR)', # 'directx_sdk_path%': '$(DXSDK_DIR)',
}], #}],
# If use_official_google_api_keys is already set (to 0 or 1), we # 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 # 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 # internal keys file is missing, the build will fail at compile
@ -3410,7 +3411,7 @@
'<(windows_sdk_path)/Include/shared', '<(windows_sdk_path)/Include/shared',
'<(windows_sdk_path)/Include/um', '<(windows_sdk_path)/Include/um',
'<(windows_sdk_path)/Include/winrt', '<(windows_sdk_path)/Include/winrt',
'<(directx_sdk_path)/Include', # '<(directx_sdk_path)/Include',
'$(VSInstallDir)/VC/atlmfc/include', '$(VSInstallDir)/VC/atlmfc/include',
], ],
'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'], 'msvs_cygwin_dirs': ['<(DEPTH)/third_party/cygwin'],
@ -3442,7 +3443,7 @@
'VCLibrarianTool': { 'VCLibrarianTool': {
'AdditionalOptions': ['/ignore:4221'], 'AdditionalOptions': ['/ignore:4221'],
'AdditionalLibraryDirectories': [ 'AdditionalLibraryDirectories': [
'<(directx_sdk_path)/Lib/x86', # '<(directx_sdk_path)/Lib/x86',
'<(windows_sdk_path)/Lib/win8/um/x86', '<(windows_sdk_path)/Lib/win8/um/x86',
], ],
}, },
@ -3488,7 +3489,7 @@
}], }],
], ],
'AdditionalLibraryDirectories': [ 'AdditionalLibraryDirectories': [
'<(directx_sdk_path)/Lib/x86', # '<(directx_sdk_path)/Lib/x86', XXXX
'<(windows_sdk_path)/Lib/win8/um/x86', '<(windows_sdk_path)/Lib/win8/um/x86',
], ],
'GenerateDebugInformation': 'true', 'GenerateDebugInformation': 'true',

View file

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

View file

@ -46,10 +46,13 @@ def FindBuildFiles():
build_files.append(file) build_files.append(file)
return build_files 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={}, def Load(build_files, format, default_variables={},
includes=[], depth='.', params=None, check=False, 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. Loads one or more specified build files.
default_variables and includes will be copied before use. 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). # This file is for projects that checkout webrtc/ directly (e.g. Chromium). It
*.mk # 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. # 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/linux/pkg_config.gni")
import("//build/config/sanitizers/sanitizers.gni")
import("build/webrtc.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 # Contains the defines and includes in common.gypi that are duplicated both as
# target_defaults and direct_dependent_settings. # target_defaults and direct_dependent_settings.
@ -20,13 +21,12 @@ config("common_inherited_config") {
defines += [ "WEBRTC_MOZILLA_BUILD" ] defines += [ "WEBRTC_MOZILLA_BUILD" ]
} }
if (build_with_chromium) { if (build_with_chromium) {
defines = [ defines = [ "WEBRTC_CHROMIUM_BUILD" ]
"WEBRTC_CHROMIUM_BUILD",
]
include_dirs = [ 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. # selecting the override headers in Chromium.
"overrides", "../webrtc_overrides",
# Allow includes to be prefixed with webrtc/ in case it is not an # Allow includes to be prefixed with webrtc/ in case it is not an
# immediate subdirectory of the top-level. # immediate subdirectory of the top-level.
"..", "..",
@ -41,6 +41,9 @@ config("common_inherited_config") {
"WEBRTC_IOS", "WEBRTC_IOS",
] ]
} }
if (is_ios && rtc_use_objc_h264) {
defines += [ "WEBRTC_OBJC_H264" ]
}
if (is_linux) { if (is_linux) {
defines += [ "WEBRTC_LINUX" ] defines += [ "WEBRTC_LINUX" ]
} }
@ -55,9 +58,6 @@ config("common_inherited_config") {
"WEBRTC_LINUX", "WEBRTC_LINUX",
"WEBRTC_ANDROID", "WEBRTC_ANDROID",
] ]
if (rtc_enable_android_opensl) {
defines += [ "WEBRTC_ANDROID_OPENSLES" ]
}
} }
} }
@ -76,6 +76,7 @@ config("common_config") {
if (rtc_have_dbus_glib) { if (rtc_have_dbus_glib) {
defines += [ "HAVE_DBUS_GLIB" ] defines += [ "HAVE_DBUS_GLIB" ]
# TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h> # TODO(kjellander): Investigate this, it seems like include <dbus/dbus.h>
# is still not found even if the execution of # is still not found even if the execution of
# build/config/linux/pkg-config.py dbus-glib-1 returns correct include # 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) { if (current_cpu != "arm64" || !is_android) {
cflags = [ cflags = [
"-Wextra", "-Wextra",
# We need to repeat some flags from Chromium"s common.gypi # We need to repeat some flags from Chromium"s common.gypi
# here that get overridden by -Wextra. # here that get overridden by -Wextra.
"-Wno-unused-parameter", "-Wno-unused-parameter",
@ -104,6 +106,7 @@ config("common_config") {
] ]
cflags_cc = [ cflags_cc = [
"-Wnon-virtual-dtor", "-Wnon-virtual-dtor",
# This is enabled for clang; enable for gcc as well. # This is enabled for clang; enable for gcc as well.
"-Woverloaded-virtual", "-Woverloaded-virtual",
] ]
@ -116,13 +119,8 @@ config("common_config") {
} }
if (current_cpu == "arm64") { if (current_cpu == "arm64") {
defines += [ "WEBRTC_ARCH_ARM" ] defines += [ "WEBRTC_ARCH_ARM64" ]
# TODO(zhongwei) Defining an unique WEBRTC_NEON and defines += [ "WEBRTC_HAS_NEON" ]
# 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" ]
} }
if (current_cpu == "arm") { if (current_cpu == "arm") {
@ -130,9 +128,9 @@ config("common_config") {
if (arm_version >= 7) { if (arm_version >= 7) {
defines += [ "WEBRTC_ARCH_ARM_V7" ] defines += [ "WEBRTC_ARCH_ARM_V7" ]
if (arm_use_neon) { if (arm_use_neon) {
defines += [ "WEBRTC_ARCH_ARM_NEON" ] defines += [ "WEBRTC_HAS_NEON" ]
} else if (is_android) { } else if (arm_optionally_use_neon) {
defines += [ "WEBRTC_DETECT_ARM_NEON" ] defines += [ "WEBRTC_DETECT_NEON" ]
} }
} }
} }
@ -155,10 +153,7 @@ config("common_config") {
} }
} }
# TODO(kjellander): Handle warnings on Windows where WebRTC differ from the if (is_android && !is_clang) {
# default warnings set in build/config/compiler/BUILD.gn.
if (is_android && is_clang) {
# The Android NDK doesn"t provide optimized versions of these # The Android NDK doesn"t provide optimized versions of these
# functions. Ensure they are disabled for all compilers. # functions. Ensure they are disabled for all compilers.
cflags += [ cflags += [
@ -174,17 +169,19 @@ source_set("webrtc") {
sources = [ sources = [
"call.h", "call.h",
"config.h", "config.h",
"experiments.h",
"frame_callback.h", "frame_callback.h",
"transport.h", "transport.h",
] ]
defines = []
configs += [ ":common_config" ] configs += [ ":common_config" ]
public_configs = [ ":common_inherited_config"] public_configs = [ ":common_inherited_config" ]
deps = [ deps = [
":webrtc_common", ":webrtc_common",
"audio",
"base:rtc_base", "base:rtc_base",
"call",
"common_audio", "common_audio",
"common_video", "common_video",
"modules/audio_coding", "modules/audio_coding",
@ -201,16 +198,20 @@ source_set("webrtc") {
"system_wrappers", "system_wrappers",
"tools", "tools",
"video", "video",
"video_engine",
"voice_engine", "voice_engine",
] ]
if (build_with_chromium) { if (build_with_chromium) {
deps += [ deps += [
"modules/video_capture", "modules/video_capture",
"modules/video_render", "modules/video_render",
] ]
} }
if (rtc_enable_protobuf) {
defines += [ "ENABLE_RTC_EVENT_LOG" ]
deps += [ ":rtc_event_log_proto" ]
}
} }
if (!build_with_chromium) { if (!build_with_chromium) {
@ -218,8 +219,8 @@ if (!build_with_chromium) {
testonly = true testonly = true
deps = [ deps = [
":webrtc", ":webrtc",
"modules/video_render:video_render_internal_impl",
"modules/video_capture:video_capture_internal_impl", "modules/video_capture:video_capture_internal_impl",
"modules/video_render:video_render_internal_impl",
"test", "test",
] ]
} }
@ -229,14 +230,20 @@ source_set("webrtc_common") {
sources = [ sources = [
"common_types.cc", "common_types.cc",
"common_types.h", "common_types.h",
"config.h",
"config.cc", "config.cc",
"config.h",
"engine_configurations.h", "engine_configurations.h",
"typedefs.h", "typedefs.h",
] ]
configs += [ ":common_config" ] configs += [ ":common_config" ]
public_configs = [ ":common_inherited_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") { source_set("gtest_prod") {
@ -244,3 +251,48 @@ source_set("gtest_prod") {
"test/testsupport/gtest_prod_util.h", "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