Bug 1450658 - Should bring window to front when screen-sharing a window; r?pehrsons
This adds a FocusOnSelectedSource method to PCameras and uses it to focus the
selected window while window sharing. We can't just focus the window as soon as
it is shared because we have a live preview in the getUserMedia permissions
prompt which would cause the prompt to lose focus. Instead, this only focuses the
window when the sharing is not done from a chrome context.
MozReview-Commit-ID: 5jre75E3JLi
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1001,16 +1001,23 @@ MediaDevice::Reconfigure(const dom::Medi
return mSource->Reconfigure(mAllocationHandle,
aConstraints,
aPrefs,
mID,
aOutBadConstraint);
}
nsresult
+MediaDevice::FocusOnSelectedSource()
+{
+ MOZ_ASSERT(MediaManager::IsInMediaThread());
+ return mSource->FocusOnSelectedSource(mAllocationHandle);
+}
+
+nsresult
MediaDevice::Stop()
{
MOZ_ASSERT(MediaManager::IsInMediaThread());
return mSource->Stop(mAllocationHandle);
}
nsresult
MediaDevice::Deallocate()
@@ -1114,17 +1121,18 @@ public:
const nsMainThreadPtrHandle<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
uint64_t aWindowID,
GetUserMediaWindowListener* aWindowListener,
SourceListener* aSourceListener,
const ipc::PrincipalInfo& aPrincipalInfo,
const MediaStreamConstraints& aConstraints,
MediaDevice* aAudioDevice,
MediaDevice* aVideoDevice,
- PeerIdentity* aPeerIdentity)
+ PeerIdentity* aPeerIdentity,
+ bool aIsChrome)
: Runnable("GetUserMediaStreamRunnable")
, mOnSuccess(aOnSuccess)
, mOnFailure(aOnFailure)
, mConstraints(aConstraints)
, mAudioDevice(aAudioDevice)
, mVideoDevice(aVideoDevice)
, mWindowID(aWindowID)
, mWindowListener(aWindowListener)
@@ -1704,16 +1712,23 @@ public:
nsTArray<RefPtr<MediaDevice>> devices;
devices.AppendElement(mVideoDevice);
badConstraint = MediaConstraintsHelper::SelectSettings(
NormalizedConstraints(constraints), devices, mIsChrome);
}
if (mAudioDevice) {
mAudioDevice->Deallocate();
}
+ } else {
+ if (!mIsChrome) {
+ rv = mVideoDevice->FocusOnSelectedSource();
+ if (NS_FAILED(rv)) {
+ LOG(("FocusOnSelectedSource failed"));
+ }
+ }
}
}
if (errorMsg) {
LOG(("%s %" PRIu32, errorMsg, static_cast<uint32_t>(rv)));
if (badConstraint) {
Fail(MediaMgrError::Name::OverconstrainedError,
NS_LITERAL_STRING(""),
NS_ConvertUTF8toUTF16(badConstraint));
@@ -1736,17 +1751,17 @@ public:
peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
}
NS_DispatchToMainThread(do_AddRef(
new GetUserMediaStreamRunnable(mOnSuccess, mOnFailure, mWindowID,
mWindowListener, mSourceListener,
mPrincipalInfo, mConstraints,
mAudioDevice, mVideoDevice,
- peerIdentity)));
+ peerIdentity, mIsChrome)));
return NS_OK;
}
nsresult
Denied(MediaMgrError::Name aName,
const nsAString& aMessage = EmptyString())
{
MOZ_ASSERT(mOnSuccess);
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -84,16 +84,17 @@ public:
const char** aOutBadConstraint);
nsresult SetTrack(const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
const PrincipalHandle& aPrincipal);
nsresult Start();
nsresult Reconfigure(const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const char** aOutBadConstraint);
+ nsresult FocusOnSelectedSource();
nsresult Stop();
nsresult Deallocate();
void Pull(const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipal);
--- a/dom/media/systemservices/CamerasChild.cpp
+++ b/dom/media/systemservices/CamerasChild.cpp
@@ -535,16 +535,32 @@ CamerasChild::StartCapture(CaptureEngine
aCapEngine,
capture_id,
capCap);
LockAndDispatch<> dispatcher(this, __func__, runnable, -1, mZero);
return dispatcher.ReturnValue();
}
int
+CamerasChild::FocusOnSelectedSource(CaptureEngine aCapEngine,
+ const int aCaptureId)
+{
+ LOG((__PRETTY_FUNCTION__));
+ nsCOMPtr<nsIRunnable> runnable =
+ mozilla::NewRunnableMethod<CaptureEngine, int>(
+ "camera::PCamerasChild::SendFocusOnSelectedSource",
+ this,
+ &CamerasChild::SendFocusOnSelectedSource,
+ aCapEngine,
+ aCaptureId);
+ LockAndDispatch<> dispatcher(this, __func__, runnable, -1, mZero);
+ return dispatcher.ReturnValue();
+}
+
+int
CamerasChild::StopCapture(CaptureEngine aCapEngine, const int capture_id)
{
LOG((__PRETTY_FUNCTION__));
nsCOMPtr<nsIRunnable> runnable =
mozilla::NewRunnableMethod<CaptureEngine, int>(
"camera::PCamerasChild::SendStopCapture",
this,
&CamerasChild::SendStopCapture,
--- a/dom/media/systemservices/CamerasChild.h
+++ b/dom/media/systemservices/CamerasChild.h
@@ -187,16 +187,17 @@ public:
int NumberOfCaptureDevices(CaptureEngine aCapEngine);
int NumberOfCapabilities(CaptureEngine aCapEngine,
const char* deviceUniqueIdUTF8);
int ReleaseCaptureDevice(CaptureEngine aCapEngine,
const int capture_id);
int StartCapture(CaptureEngine aCapEngine,
const int capture_id, webrtc::VideoCaptureCapability& capability,
FrameRelay* func);
+ int FocusOnSelectedSource(CaptureEngine aCapEngine, const int capture_id);
int StopCapture(CaptureEngine aCapEngine, const int capture_id);
int AllocateCaptureDevice(CaptureEngine aCapEngine,
const char* unique_idUTF8,
const unsigned int unique_idUTF8Length,
int& capture_id,
const mozilla::ipc::PrincipalInfo& aPrincipalInfo);
int GetCaptureCapability(CaptureEngine aCapEngine,
const char* unique_idUTF8,
--- a/dom/media/systemservices/CamerasParent.cpp
+++ b/dom/media/systemservices/CamerasParent.cpp
@@ -972,16 +972,53 @@ CamerasParent::RecvStartCapture(const Ca
});
self->mPBackgroundEventTarget->Dispatch(ipc_runnable, NS_DISPATCH_NORMAL);
return NS_OK;
});
DispatchToVideoCaptureThread(webrtc_runnable);
return IPC_OK();
}
+mozilla::ipc::IPCResult
+CamerasParent::RecvFocusOnSelectedSource(const CaptureEngine& aCapEngine,
+ const int& aCapNum)
+{
+ LOG((__PRETTY_FUNCTION__));
+ RefPtr<Runnable> webrtc_runnable =
+ media::NewRunnableFrom([self = RefPtr<CamerasParent>(this),
+ aCapEngine, aCapNum]() -> nsresult {
+ if (auto engine = self->EnsureInitialized(aCapEngine)) {
+ engine->WithEntry(aCapNum, [self](VideoEngine::CaptureEntry& cap){
+ if (cap.VideoCapture()) {
+ bool result = cap.VideoCapture()->FocusOnSelectedSource();
+ RefPtr<nsIRunnable> ipc_runnable =
+ media::NewRunnableFrom([self, result]() -> nsresult {
+ if (!self->mChildIsAlive) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (result) {
+ Unused << self->SendReplySuccess();
+ return NS_OK;
+ }
+
+ Unused << self->SendReplyFailure();
+ return NS_ERROR_FAILURE;
+ });
+ self->mPBackgroundEventTarget->Dispatch(ipc_runnable,
+ NS_DISPATCH_NORMAL);
+ }
+ });
+ }
+ return NS_ERROR_FAILURE;
+ });
+ DispatchToVideoCaptureThread(webrtc_runnable);
+ return IPC_OK();
+}
+
void
CamerasParent::StopCapture(const CaptureEngine& aCapEngine,
const int& capnum)
{
if (auto engine = EnsureInitialized(aCapEngine)) {
// we're removing elements, iterate backwards
for (size_t i = mCallbacks.Length(); i > 0; i--) {
if (mCallbacks[i - 1]->mCapEngine == aCapEngine &&
--- a/dom/media/systemservices/CamerasParent.h
+++ b/dom/media/systemservices/CamerasParent.h
@@ -94,16 +94,18 @@ public:
mozilla::ipc::IPCResult RecvNumberOfCaptureDevices(const CaptureEngine&) override;
mozilla::ipc::IPCResult RecvNumberOfCapabilities(const CaptureEngine&,
const nsCString&) override;
mozilla::ipc::IPCResult RecvGetCaptureCapability(const CaptureEngine&, const nsCString&,
const int&) override;
mozilla::ipc::IPCResult RecvGetCaptureDevice(const CaptureEngine&, const int&) override;
mozilla::ipc::IPCResult RecvStartCapture(const CaptureEngine&, const int&,
const VideoCaptureCapability&) override;
+ mozilla::ipc::IPCResult RecvFocusOnSelectedSource(const CaptureEngine&,
+ const int&) override;
mozilla::ipc::IPCResult RecvStopCapture(const CaptureEngine&, const int&) override;
mozilla::ipc::IPCResult RecvReleaseFrame(mozilla::ipc::Shmem&&) override;
mozilla::ipc::IPCResult RecvAllDone() override;
void ActorDestroy(ActorDestroyReason aWhy) override;
mozilla::ipc::IPCResult RecvEnsureInitialized(const CaptureEngine&) override;
nsIEventTarget* GetBackgroundEventTarget() { return mPBackgroundEventTarget; };
bool IsShuttingDown()
--- a/dom/media/systemservices/PCameras.ipdl
+++ b/dom/media/systemservices/PCameras.ipdl
@@ -75,16 +75,17 @@ parent:
async GetCaptureCapability(CaptureEngine engine, nsCString unique_idUTF8,
int capability_number);
async GetCaptureDevice(CaptureEngine engine, int num);
async AllocateCaptureDevice(CaptureEngine engine, nsCString unique_idUTF8,
PrincipalInfo principal);
async ReleaseCaptureDevice(CaptureEngine engine, int numdev);
async StartCapture(CaptureEngine engine, int numdev, VideoCaptureCapability capability);
+ async FocusOnSelectedSource(CaptureEngine engine, int numdev);
async StopCapture(CaptureEngine engine, int numdev);
// transfers frame back
async ReleaseFrame(Shmem s);
// Ask parent to delete us
async AllDone();
// setup camera engine
async EnsureInitialized(CaptureEngine engine);
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp
@@ -338,16 +338,28 @@ MediaEngineRemoteVideoSource::Start(cons
}
settings->mFrameRate.Value() = cap.maxFPS;
}));
return NS_OK;
}
nsresult
+MediaEngineRemoteVideoSource::FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle)
+{
+ LOG((__PRETTY_FUNCTION__));
+ AssertIsOnOwningThread();
+
+ int result;
+ result = camera::GetChildAndCall(&camera::CamerasChild::FocusOnSelectedSource,
+ mCapEngine, mCaptureIndex);
+ return result == 0 ? NS_OK : NS_ERROR_FAILURE;
+}
+
+nsresult
MediaEngineRemoteVideoSource::Stop(const RefPtr<const AllocationHandle>& aHandle)
{
LOG((__PRETTY_FUNCTION__));
AssertIsOnOwningThread();
if (mState == kStopped || mState == kAllocated) {
return NS_OK;
}
--- a/dom/media/webrtc/MediaEngineRemoteVideoSource.h
+++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.h
@@ -139,16 +139,17 @@ public:
TrackID aTrackID,
const PrincipalHandle& aPrincipal) override;
nsresult Start(const RefPtr<const AllocationHandle>& aHandle) override;
nsresult Reconfigure(const RefPtr<AllocationHandle>& aHandle,
const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
+ nsresult FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle) override;
nsresult Stop(const RefPtr<const AllocationHandle>& aHandle) override;
void Pull(const RefPtr<const AllocationHandle>& aHandle,
const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle) override;
--- a/dom/media/webrtc/MediaEngineSource.cpp
+++ b/dom/media/webrtc/MediaEngineSource.cpp
@@ -50,16 +50,22 @@ MediaEngineSource::IsFake() const
}
bool
MediaEngineSource::GetScary() const
{
return false;
}
+nsresult
+MediaEngineSource::FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
void
MediaEngineSource::Shutdown()
{
}
nsresult
MediaEngineSource::TakePhoto(MediaEnginePhotoCallback* aCallback)
{
--- a/dom/media/webrtc/MediaEngineSource.h
+++ b/dom/media/webrtc/MediaEngineSource.h
@@ -147,16 +147,29 @@ public:
* the given AllocationHandle.
*
* If this is the first AllocationHandle to start, the underlying device
* will be started.
*/
virtual nsresult Start(const RefPtr<const AllocationHandle>& aHandle) = 0;
/**
+ * This brings focus to the selected source, e.g. to bring a captured window
+ * to the front.
+ *
+ * We return one of the following:
+ * NS_OK - Success.
+ * NS_ERROR_NOT_AVAILABLE - For backends where focusing does not make sense.
+ * NS_ERROR_NOT_IMPLEMENTED - For backends where focusing makes sense, but
+ * is not yet implemented.
+ * NS_ERROR_FAILURE - Failures reported from underlying code.
+ */
+ virtual nsresult FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle) = 0;
+
+ /**
* Applies new constraints to the capability selection for the underlying
* device.
*
* Should the constraints lead to choosing a new capability while the device
* is actively being captured, the device will restart using the new
* capability.
*
* We return one of the following:
@@ -274,16 +287,19 @@ public:
bool RequiresSharing() const override;
// Not fake by default.
bool IsFake() const override;
// Not scary by default.
bool GetScary() const override;
+ // Returns NS_ERROR_NOT_AVAILABLE by default.
+ nsresult FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle) override;
+
// Shutdown does nothing by default.
void Shutdown() override;
// TakePhoto returns NS_ERROR_NOT_IMPLEMENTED by default,
// to tell the caller to fallback to other methods.
nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) override;
// Makes aOutSettings empty by default.
--- a/dom/media/webrtc/MediaEngineTabVideoSource.cpp
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.cpp
@@ -392,16 +392,22 @@ MediaEngineTabVideoSource::Draw() {
RefPtr<layers::SourceSurfaceImage> image = new layers::SourceSurfaceImage(size, surface);
MutexAutoLock lock(mMutex);
mImage = image;
mImageSize = size;
}
nsresult
+MediaEngineTabVideoSource::FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
MediaEngineTabVideoSource::Stop(const RefPtr<const AllocationHandle>& aHandle)
{
AssertIsOnOwningThread();
if (mState == kStopped || mState == kAllocated) {
return NS_OK;
}
--- a/dom/media/webrtc/MediaEngineTabVideoSource.h
+++ b/dom/media/webrtc/MediaEngineTabVideoSource.h
@@ -41,16 +41,17 @@ public:
TrackID aTrackID,
const PrincipalHandle& aPrincipal) override;
nsresult Start(const RefPtr<const AllocationHandle>& aHandle) override;
nsresult Reconfigure(const RefPtr<AllocationHandle>& aHandle,
const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint) override;
+ nsresult FocusOnSelectedSource(const RefPtr<const AllocationHandle>& aHandle) override;
nsresult Stop(const RefPtr<const AllocationHandle>& aHandle) override;
void Pull(const RefPtr<const AllocationHandle>& aHandle,
const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle) override;
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.cc
@@ -179,9 +179,13 @@ void DesktopAndCursorComposer::OnMouseCu
void DesktopAndCursorComposer::OnMouseCursorPosition(
MouseCursorMonitor::CursorState state,
const DesktopVector& position) {
cursor_state_ = state;
cursor_position_ = position;
}
+bool DesktopAndCursorComposer::FocusOnSelectedSource() {
+ return desktop_capturer_->FocusOnSelectedSource();
+}
+
} // namespace webrtc
--- a/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h
+++ b/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_and_cursor_composer.h
@@ -35,16 +35,17 @@ class DesktopAndCursorComposer : public
// DesktopCapturer interface.
void Start(DesktopCapturer::Callback* callback) override;
void Stop() override;
void SetSharedMemoryFactory(
std::unique_ptr<SharedMemoryFactory> shared_memory_factory) override;
void CaptureFrame() override;
void SetExcludedWindow(WindowId window) override;
+ bool FocusOnSelectedSource() override;
private:
// DesktopCapturer::Callback interface.
void OnCaptureResult(DesktopCapturer::Result result,
std::unique_ptr<DesktopFrame> frame) override;
// MouseCursorMonitor::Callback interface.
void OnMouseCursor(MouseCursor* cursor) override;
--- a/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/video_capture.h
@@ -163,16 +163,18 @@ class VideoCaptureModule: public rtc::Re
rtc::VideoSinkInterface<VideoFrame> *dataCallback) = 0;
// Start capture device
virtual int32_t StartCapture(
const VideoCaptureCapability& capability) = 0;
virtual int32_t StopCaptureIfAllClientsClose() = 0;
+ virtual bool FocusOnSelectedSource() { return false; };
+
virtual int32_t StopCapture() = 0;
// Returns the name of the device used by this module.
virtual const char* CurrentDeviceName() const = 0;
// Returns true if the capture device is running
virtual bool CaptureStarted() = 0;
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.cc
@@ -667,16 +667,21 @@ int32_t DesktopCaptureImpl::StartCapture
desktop_capturer_cursor_composer_->Start(this);
capturer_thread_->Start();
started_ = true;
return 0;
}
+bool DesktopCaptureImpl::FocusOnSelectedSource()
+{
+ return desktop_capturer_cursor_composer_->FocusOnSelectedSource();
+}
+
int32_t DesktopCaptureImpl::StopCapture() {
if (started_) {
capturer_thread_->Stop(); // thread is guaranteed stopped before this returns
desktop_capturer_cursor_composer_->Stop();
started_ = false;
return 0;
}
return -1;
--- a/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
+++ b/media/webrtc/trunk/webrtc/video_engine/desktop_capture_impl.h
@@ -187,16 +187,17 @@ public:
// |capture_time| must be specified in the NTP time format in milliseconds.
virtual int32_t IncomingFrame(uint8_t* videoFrame,
size_t videoFrameLength,
const VideoCaptureCapability& frameInfo,
int64_t captureTime = 0) override;
// Platform dependent
virtual int32_t StartCapture(const VideoCaptureCapability& capability) override;
+ virtual bool FocusOnSelectedSource() override;
virtual int32_t StopCapture() override;
virtual bool CaptureStarted() override;
virtual int32_t CaptureSettings(VideoCaptureCapability& settings) override;
protected:
DesktopCaptureImpl(const int32_t id);
virtual ~DesktopCaptureImpl();
int32_t DeliverCapturedFrame(webrtc::VideoFrame& captureFrame,