9b29befdc8
Capturing window thmubnails is expensive as it actually uses the window capturer and it records one full frame per window and then downscale to the default size 150x150. When only interested in the window names or the app icons we do not need all of this. Underlying change is merged in chromium72 so this patch only modifies the doc, see: https://chromium.googlesource.com/chromium/src.git/+log/72.0.3626.52/chrome/browser/media/webrtc/native_desktop_media_list.cc Example: desktopCapturer.getSources({thumbnailSize: {width: 0, height: 0}}, ...) Also added a unit test in spec/api-desktop-capturer-spec.js that verifies that the returned thumbails are of type NativeImage and empty, when the user disable fetching thumbnails. notes: Can disable fetching the thumbnails for the DesktopCapturer. https://github.com/electron/electron/issues/14872
125 lines
4.5 KiB
JavaScript
125 lines
4.5 KiB
JavaScript
const chai = require('chai')
|
|
const dirtyChai = require('dirty-chai')
|
|
const chaiAsPromised = require('chai-as-promised')
|
|
const { desktopCapturer, ipcRenderer, remote } = require('electron')
|
|
const { screen } = remote
|
|
const features = process.atomBinding('features')
|
|
const { emittedOnce } = require('./events-helpers')
|
|
|
|
const { expect } = chai
|
|
chai.use(dirtyChai)
|
|
chai.use(chaiAsPromised)
|
|
|
|
const isCI = remote.getGlobal('isCi')
|
|
|
|
describe('desktopCapturer', () => {
|
|
before(function () {
|
|
if (!features.isDesktopCapturerEnabled() || process.arch.indexOf('arm') === 0) {
|
|
// It's been disabled during build time.
|
|
this.skip()
|
|
return
|
|
}
|
|
|
|
if (isCI && process.platform === 'win32') {
|
|
this.skip()
|
|
}
|
|
})
|
|
|
|
it('should return a non-empty array of sources', async () => {
|
|
const sources = await desktopCapturer.getSources({ types: ['window', 'screen'] })
|
|
expect(sources).to.be.an('array').that.is.not.empty()
|
|
})
|
|
|
|
// TODO(codebytere): remove when promisification is complete
|
|
it('should return a non-empty array of sources (callback)', (done) => {
|
|
desktopCapturer.getSources({ types: ['window', 'screen'] }, (err, sources) => {
|
|
expect(sources).to.be.an('array').that.is.not.empty()
|
|
expect(err).to.be.null()
|
|
done()
|
|
})
|
|
})
|
|
|
|
it('throws an error for invalid options', async () => {
|
|
const promise = desktopCapturer.getSources(['window', 'screen'])
|
|
expect(promise).to.be.eventually.rejectedWith(Error, 'Invalid options')
|
|
})
|
|
|
|
it('does not throw an error when called more than once (regression)', async () => {
|
|
const sources1 = await desktopCapturer.getSources({ types: ['window', 'screen'] })
|
|
expect(sources1).to.be.an('array').that.is.not.empty()
|
|
|
|
const sources2 = await desktopCapturer.getSources({ types: ['window', 'screen'] })
|
|
expect(sources2).to.be.an('array').that.is.not.empty()
|
|
})
|
|
|
|
it('responds to subsequent calls of different options', async () => {
|
|
const promise1 = desktopCapturer.getSources({ types: ['window'] })
|
|
expect(promise1).to.not.eventually.be.rejected()
|
|
|
|
const promise2 = desktopCapturer.getSources({ types: ['screen'] })
|
|
expect(promise2).to.not.eventually.be.rejected()
|
|
})
|
|
|
|
// TODO(codebytere): remove when promisification is complete
|
|
it('responds to subsequent calls of different options (callback)', (done) => {
|
|
let callCount = 0
|
|
const callback = (err, sources) => {
|
|
callCount++
|
|
expect(err).to.be.null()
|
|
expect(sources).to.not.be.null()
|
|
if (callCount === 2) done()
|
|
}
|
|
|
|
desktopCapturer.getSources({ types: ['window'] }, callback)
|
|
desktopCapturer.getSources({ types: ['screen'] }, callback)
|
|
})
|
|
|
|
it('returns an empty display_id for window sources on Windows and Mac', async () => {
|
|
// Linux doesn't return any window sources.
|
|
if (process.platform !== 'win32' && process.platform !== 'darwin') return
|
|
|
|
const { BrowserWindow } = remote
|
|
const w = new BrowserWindow({ width: 200, height: 200 })
|
|
|
|
const sources = await desktopCapturer.getSources({ types: ['window'] })
|
|
w.destroy()
|
|
expect(sources).to.be.an('array').that.is.not.empty()
|
|
for (const { display_id: displayId } of sources) {
|
|
expect(displayId).to.be.a('string').and.be.empty()
|
|
}
|
|
})
|
|
|
|
it('returns display_ids matching the Screen API on Windows and Mac', async () => {
|
|
if (process.platform !== 'win32' && process.platform !== 'darwin') return
|
|
|
|
const displays = screen.getAllDisplays()
|
|
const sources = await desktopCapturer.getSources({ types: ['screen'] })
|
|
expect(sources).to.be.an('array').of.length(displays.length)
|
|
|
|
for (let i = 0; i < sources.length; i++) {
|
|
expect(sources[i].display_id).to.equal(displays[i].id.toString())
|
|
}
|
|
|
|
it('returns empty sources when blocked', async () => {
|
|
ipcRenderer.send('handle-next-desktop-capturer-get-sources')
|
|
const sources = await desktopCapturer.getSources({ types: ['screen'] })
|
|
expect(sources).to.be.empty()
|
|
})
|
|
})
|
|
|
|
it('disabling thumbnail should return empty images', async () => {
|
|
const { BrowserWindow } = remote
|
|
const w = new BrowserWindow({ show: false, width: 200, height: 200 })
|
|
const wShown = emittedOnce(w, 'show')
|
|
w.show()
|
|
await wShown
|
|
|
|
const sources = await desktopCapturer.getSources({ types: ['window', 'screen'], thumbnailSize: { width: 0, height: 0 } })
|
|
w.destroy()
|
|
expect(sources).to.be.an('array').that.is.not.empty()
|
|
for (const { thumbnail: thumbnailImage } of sources) {
|
|
expect(thumbnailImage).to.be.a('NativeImage')
|
|
expect(thumbnailImage.isEmpty()).to.be.true()
|
|
}
|
|
})
|
|
})
|