Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linux Support (again) #32

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 80 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,32 @@ const macosVersion = require('macos-version');

const debuglog = util.debuglog('aperture');

const IS_LINUX = process.platform === 'linux';
const IS_MACOS = process.platform === 'darwin';

class Aperture {
constructor() {
macosVersion.assertGreaterThanOrEqualTo('10.10');
if (IS_MACOS) {
macosVersion.assertGreaterThanOrEqualTo('10.10');
}
}

getAudioSources() {
return execa.stdout(path.join(__dirname, 'swift/main'), ['list-audio-devices']).then(JSON.parse);
if (IS_MACOS) {
return execa.stdout(path.join(__dirname, 'swift/main'), ['list-audio-devices']).then(JSON.parse);
} else if (IS_LINUX) {
return execa.stdout('arecord', ['-l']).then(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-l => --list-devices

stdout => stdout.split('\n').reduce((result, line) => {
const match = line.match(/card (\d+): ([^,]+),/);

if (match) {
result.push(`${match[1]}:${match[2]}`);
}

return result;
}, [])
);
}
}

startRecording({
Expand All @@ -25,6 +44,8 @@ class Aperture {
audioSourceId = 'none'
} = {}) {
return new Promise((resolve, reject) => {
let cropAreaOpts;

if (this.recorder !== undefined) {
reject(new Error('Call `.stopRecording()` first'));
return;
Expand All @@ -45,20 +66,37 @@ class Aperture {
return;
}

cropArea = `${cropArea.x}:${cropArea.y}:${cropArea.width}:${cropArea.height}`;
cropAreaOpts = `${cropArea.x}:${cropArea.y}:${cropArea.width}:${cropArea.height}`;
}

const recorderOpts = [
this.tmpPath,
fps,
cropArea,
showCursor,
highlightClicks,
displayId,
audioSourceId
];
if (IS_MACOS) {
const recorderOpts = [
this.tmpPath,
fps,
cropAreaOpts || cropArea,
showCursor,
highlightClicks,
displayId,
audioSourceId
];

this.recorder = execa(path.join(__dirname, 'swift', 'main'), recorderOpts);
} else if (IS_LINUX) {
const args = ['-f', 'x11grab'];

if (typeof cropArea === 'object') {
args.push(
'-video_size', `${cropArea.width}x${cropArea.height}`,
'-i', `:0+${cropArea.x},${cropArea.y}`
);
} else {
args.push('-i', ':0');
}

args.push('-framerate', fps, '-draw_mouse', +(showCursor === true), this.tmpPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String(showCursor === true)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you verify this works? Based on the documentation, draw_mouse expects a binary value. That's why I'm coercing the boolean to an int.


this.recorder = execa(path.join(__dirname, 'swift', 'main'), recorderOpts);
this.recorder = execa('ffmpeg', args);
}

const timeout = setTimeout(() => {
// `.stopRecording()` was called already
Expand All @@ -71,7 +109,7 @@ class Aperture {
this.recorder.kill();
delete this.recorder;
reject(err);
}, 5000);
}, 7500);

this.recorder.catch(err => {
clearTimeout(timeout);
Expand All @@ -80,15 +118,28 @@ class Aperture {
});

this.recorder.stdout.setEncoding('utf8');
this.recorder.stdout.on('data', data => {
debuglog(data);

if (data.trim() === 'R') {
// `R` is printed by Swift when the recording **actually** starts
clearTimeout(timeout);
resolve(this.tmpPath);
}
});
if (IS_MACOS) {
this.recorder.stdout.on('data', data => {
debuglog(data);

if (data.trim() === 'R') {
// `R` is printed by Swift when the recording **actually** starts
clearTimeout(timeout);
resolve(this.tmpPath);
}
});
} else if (IS_LINUX) {
this.recorder.stderr.on('data', data => {
debuglog(data);

if (/^frame=\s*\d+\sfps=\s\d+/.test(data.toString('utf8').trim())) {
// fmpeg prints lines like this while it's reocrding
// frame= 203 fps= 30 q=-1.0 Lsize= 54kB time=00:00:06.70 bitrate= 65.8kbits/s dup=21 drop=19 speed=0.996x
clearTimeout(timeout);
resolve(this.tmpPath);
}
});
}
});
}

Expand All @@ -106,7 +157,12 @@ class Aperture {
reject(err.stderr ? new Error(err.stderr) : err);
});

this.recorder.kill();
if (IS_MACOS) {
this.recorder.kill();
} else if (IS_LINUX) {
this.recorder.stdin.setEncoding('utf8');
this.recorder.stdin.write('q');
}
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
},
"scripts": {
"test": "xo",
"build": "cd swift && xcodebuild -derivedDataPath $(mktemp -d) -scheme aperture",
"prepublish": "npm run build"
"build-macos": "cd swift && xcodebuild -derivedDataPath $(mktemp -d) -scheme aperture",
"prepublish": "[ \"$(uname)\" = \"Darwin\" ] && npm run build-macos"
},
"files": [
"index.js",
Expand Down