├── .gitignore ├── .npmrc ├── LICENSE ├── README.md ├── impl ├── darwin.js ├── linux.js └── windows │ ├── adjust_get_current_system_volume_vista_plus.exe │ └── index.js ├── index.d.ts ├── index.js ├── package.json └── test └── basics.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | node_modules 14 | 15 | npm-debug.log 16 | !adjust_get_current_system_volume_vista_plus.exe 17 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Linus Unnebäck 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-loudness 2 | 3 | A node.js library to control the systems output volume 4 | 5 | ## Usage 6 | 7 | The library currently has support for four simple async functions. The volume is specified as an integer between 0 and 100 (inc.). 8 | 9 | ```javascript 10 | const loudness = require('loudness') 11 | 12 | await loudness.setVolume(45) 13 | 14 | const vol = await loudness.getVolume() 15 | // vol = 45 16 | 17 | await loudness.setMuted(false) 18 | 19 | const mute = await loudness.getMuted() 20 | // mute = false 21 | ``` 22 | 23 | ## OS Support 24 | 25 | Currently macOS, Windows (>= Vista) and Linux (ALSA) is supported, please send a pull request if you are using another setup. 26 | -------------------------------------------------------------------------------- /impl/darwin.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | 3 | async function osascript (cmd) { 4 | return (await execa('osascript', ['-e', cmd])).stdout 5 | } 6 | 7 | exports.getVolume = async function getVolume () { 8 | return parseInt(await osascript('output volume of (get volume settings)'), 10) 9 | } 10 | 11 | exports.setVolume = async function setVolume (val) { 12 | await osascript('set volume output volume ' + val) 13 | } 14 | 15 | exports.getMuted = async function getMuted () { 16 | return (await osascript('output muted of (get volume settings)')) === 'true' 17 | } 18 | 19 | exports.setMuted = async function setMuted (val) { 20 | await osascript('set volume ' + (val ? 'with' : 'without') + ' output muted') 21 | } 22 | -------------------------------------------------------------------------------- /impl/linux.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | 3 | async function amixer (...args) { 4 | return (await execa('amixer', args)).stdout 5 | } 6 | 7 | let defaultDeviceCache = null 8 | const reDefaultDevice = /Simple mixer control '([a-z0-9 -]+)',[0-9]+/i 9 | 10 | function parseDefaultDevice (data) { 11 | const result = reDefaultDevice.exec(data) 12 | 13 | if (result === null) { 14 | throw new Error('Alsa Mixer Error: failed to parse output') 15 | } 16 | 17 | return result[1] 18 | } 19 | 20 | async function getDefaultDevice () { 21 | if (defaultDeviceCache) return defaultDeviceCache 22 | 23 | return (defaultDeviceCache = parseDefaultDevice(await amixer())) 24 | } 25 | 26 | const reInfo = /[a-z][a-z ]*: Playback [0-9-]+ \[([0-9]+)%\] (?:[[0-9.-]+dB\] )?\[(on|off)\]/i 27 | 28 | function parseInfo (data) { 29 | const result = reInfo.exec(data) 30 | 31 | if (result === null) { 32 | throw new Error('Alsa Mixer Error: failed to parse output') 33 | } 34 | 35 | return { volume: parseInt(result[1], 10), muted: (result[2] === 'off') } 36 | } 37 | 38 | async function getInfo () { 39 | return parseInfo(await amixer('get', await getDefaultDevice())) 40 | } 41 | 42 | exports.getVolume = async function getVolume () { 43 | return (await getInfo()).volume 44 | } 45 | 46 | exports.setVolume = async function setVolume (val) { 47 | await amixer('set', await getDefaultDevice(), val + '%') 48 | } 49 | 50 | exports.getMuted = async function getMuted () { 51 | return (await getInfo()).muted 52 | } 53 | 54 | exports.setMuted = async function setMuted (val) { 55 | await amixer('set', await getDefaultDevice(), val ? 'mute' : 'unmute') 56 | } 57 | -------------------------------------------------------------------------------- /impl/windows/adjust_get_current_system_volume_vista_plus.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinusU/node-loudness/9bdad3ab64b47c90a0e7a42279111e2bd3e5acd5/impl/windows/adjust_get_current_system_volume_vista_plus.exe -------------------------------------------------------------------------------- /impl/windows/index.js: -------------------------------------------------------------------------------- 1 | const childProcess = require('child_process') 2 | const path = require('path') 3 | const util = require('util') 4 | 5 | const execFile = util.promisify(childProcess.execFile) 6 | const executablePath = path.join(__dirname, 'adjust_get_current_system_volume_vista_plus.exe') 7 | 8 | async function runProgram (...args) { 9 | return (await execFile(executablePath, args)).stdout 10 | } 11 | 12 | async function getVolumeInfo () { 13 | const data = await runProgram() 14 | const args = data.split(' ') 15 | 16 | return { volume: parseInt(args[0], 10), muted: Boolean(parseInt(args[1], 10)) } 17 | } 18 | 19 | exports.getVolume = async function getVolume () { 20 | return (await getVolumeInfo()).volume 21 | } 22 | 23 | exports.setVolume = async function setVolume (val) { 24 | await runProgram(String(val)) 25 | } 26 | 27 | exports.getMuted = async function getMuted () { 28 | return (await getVolumeInfo()).muted 29 | } 30 | 31 | exports.setMuted = async function setMuted (val) { 32 | await runProgram(val ? 'mute' : 'unmute') 33 | } 34 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare interface Loudness { 2 | getMuted(): Promise 3 | getVolume(): Promise 4 | setMuted(muted: boolean): Promise 5 | setVolume(volume: number): Promise 6 | } 7 | 8 | declare const loudness: Loudness 9 | 10 | export = loudness 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | let impl = null 3 | 4 | switch (os.type()) { 5 | case 'Darwin': 6 | impl = require('./impl/darwin') 7 | break 8 | case 'Linux': 9 | impl = require('./impl/linux') 10 | break 11 | case 'Windows_NT': 12 | impl = require('./impl/windows') 13 | break 14 | default: 15 | throw new Error('Your OS is currently not supported by node-loudness.') 16 | } 17 | 18 | module.exports = { 19 | setVolume (volume) { 20 | return impl.setVolume(volume) 21 | }, 22 | getVolume () { 23 | return impl.getVolume() 24 | }, 25 | setMuted (muted) { 26 | return impl.setMuted(muted) 27 | }, 28 | getMuted () { 29 | return impl.getMuted() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "loudness", 3 | "version": "0.4.2", 4 | "license": "MIT", 5 | "repository": "LinusU/node-loudness", 6 | "scripts": { 7 | "test": "standard && mocha" 8 | }, 9 | "dependencies": { 10 | "execa": "^4.0.3" 11 | }, 12 | "devDependencies": { 13 | "mocha": "^8.1.1", 14 | "standard": "^14.3.4" 15 | }, 16 | "engines": { 17 | "node": ">=10.13.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/basics.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | 3 | const loudness = require('../') 4 | 5 | const assert = require('assert') 6 | 7 | describe('loudness', () => { 8 | let systemVolume, isMuted 9 | 10 | before(async () => { 11 | await Promise.all([ 12 | loudness.getVolume().then(v => { systemVolume = v }), 13 | loudness.getMuted().then(m => { isMuted = m }) 14 | ]) 15 | }) 16 | 17 | after(async () => { 18 | await Promise.all([ 19 | loudness.setVolume(systemVolume), 20 | loudness.setMuted(isMuted) 21 | ]) 22 | }) 23 | 24 | it('should set and get the volume', async () => { 25 | await loudness.setVolume(15) 26 | const vol = await loudness.getVolume() 27 | assert.strictEqual(vol, 15) 28 | }) 29 | 30 | it('should set and get the mute state', async () => { 31 | await loudness.setMuted(true) 32 | const mute = await loudness.getMuted() 33 | assert.strictEqual(mute, true) 34 | }) 35 | }) 36 | --------------------------------------------------------------------------------