Returns a NULL frame on all platforms if the captured window is closed.

Part of the fix for crbug/360181.
On Mac/Linux, it previously continues capturing even if the window is closed.
Now it stops by returning a NULL frame.
On Windows, it used to stop capturing when the window is minimized. Now fixed to match other platforms.
Note: the crbug still needs a chrome side fix to close the notification bar.
This fix only stops the stream (i.e. stream onended event fired).

BUG=crbug/360181
TESTED=manually tested in Chrome
R=sergeyu@chromium.org

Review URL: https://webrtc-codereview.appspot.com/12329007

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5977 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
jiayl@webrtc.org 2014-04-24 23:45:56 +00:00
parent cd70119a10
commit cc1ba15fe7
5 changed files with 41 additions and 17 deletions

View File

@ -42,6 +42,18 @@ bool CFStringRefToUtf8(const CFStringRef string, std::string* str_utf8) {
return true;
}
bool IsWindowValid(CGWindowID id) {
CFArrayRef window_id_array =
CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
CFArrayRef window_array =
CGWindowListCreateDescriptionFromArray(window_id_array);
bool valid = window_array && CFArrayGetCount(window_array);
CFRelease(window_id_array);
CFRelease(window_array);
return valid;
}
class WindowCapturerMac : public WindowCapturer {
public:
WindowCapturerMac();
@ -115,22 +127,8 @@ bool WindowCapturerMac::GetWindowList(WindowList* windows) {
}
bool WindowCapturerMac::SelectWindow(WindowId id) {
// Request description for the specified window to make sure |id| is valid.
CGWindowID ids[1];
ids[0] = id;
CFArrayRef window_id_array =
CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
CFArrayRef window_array =
CGWindowListCreateDescriptionFromArray(window_id_array);
int results_count = window_array ? CFArrayGetCount(window_array) : 0;
CFRelease(window_id_array);
CFRelease(window_array);
if (results_count == 0) {
// Could not find the window. It might have been closed.
if (!IsWindowValid(id))
return false;
}
window_id_ = id;
return true;
}
@ -180,6 +178,11 @@ void WindowCapturerMac::Start(Callback* callback) {
}
void WindowCapturerMac::Capture(const DesktopRegion& region) {
if (!IsWindowValid(window_id_)) {
callback_->OnCaptureCompleted(NULL);
return;
}
CGImageRef window_image = CGWindowListCreateImage(
CGRectNull, kCGWindowListOptionIncludingWindow,
window_id_, kCGWindowImageBoundsIgnoreFraming);

View File

@ -182,8 +182,8 @@ void WindowCapturerWin::Capture(const DesktopRegion& region) {
return;
}
// Stop capturing if the window has been minimized or hidden.
if (IsIconic(window_) || !IsWindowVisible(window_)) {
// Stop capturing if the window has been closed or hidden.
if (!IsWindow(window_) || !IsWindowVisible(window_)) {
callback_->OnCaptureCompleted(NULL);
return;
}

View File

@ -278,6 +278,12 @@ void WindowCapturerLinux::Start(Callback* callback) {
}
void WindowCapturerLinux::Capture(const DesktopRegion& region) {
if (!x_server_pixel_buffer_.IsWindowValid()) {
LOG(LS_INFO) << "The window is no longer valid.";
callback_->OnCaptureCompleted(NULL);
return;
}
x_display_->ProcessPendingXEvents();
if (!has_composite_extension_) {

View File

@ -213,6 +213,18 @@ bool XServerPixelBuffer::InitPixmaps(int depth) {
return true;
}
bool XServerPixelBuffer::IsWindowValid() const {
XWindowAttributes attributes;
{
XErrorTrap error_trap(display_);
if (!XGetWindowAttributes(display_, window_, &attributes) ||
error_trap.GetLastErrorAndDisable() != 0) {
return false;
}
}
return true;
}
void XServerPixelBuffer::Synchronize() {
if (shm_segment_info_ && !shm_pixmap_) {
// XShmGetImage can fail if the display is being reconfigured.

View File

@ -40,6 +40,9 @@ class XServerPixelBuffer {
// Returns the size of the window the buffer was initialized for.
const DesktopSize& window_size() { return window_size_; }
// Returns true if the window can be found.
bool IsWindowValid() const;
// If shared memory is being used without pixmaps, synchronize this pixel
// buffer with the root window contents (otherwise, this is a no-op).
// This is to avoid doing a full-screen capture for each individual