audio.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // audio.js
  5. // ----------------------------------------------------------------------------------
  6. // Description: System Information - library
  7. // for Node.js
  8. // Copyright: (c) 2014 - 2022
  9. // Author: Sebastian Hildebrandt
  10. // ----------------------------------------------------------------------------------
  11. // License: MIT
  12. // ==================================================================================
  13. // 16. audio
  14. // ----------------------------------------------------------------------------------
  15. const exec = require('child_process').exec;
  16. const execSync = require('child_process').execSync;
  17. const util = require('./util');
  18. // const fs = require('fs');
  19. let _platform = process.platform;
  20. const _linux = (_platform === 'linux' || _platform === 'android');
  21. const _darwin = (_platform === 'darwin');
  22. const _windows = (_platform === 'win32');
  23. const _freebsd = (_platform === 'freebsd');
  24. const _openbsd = (_platform === 'openbsd');
  25. const _netbsd = (_platform === 'netbsd');
  26. const _sunos = (_platform === 'sunos');
  27. function parseAudioType(str, input, output) {
  28. let result = '';
  29. if (str.indexOf('speak') >= 0) { result = 'Speaker'; }
  30. if (str.indexOf('laut') >= 0) { result = 'Speaker'; }
  31. if (str.indexOf('loud') >= 0) { result = 'Speaker'; }
  32. if (str.indexOf('head') >= 0) { result = 'Headset'; }
  33. if (str.indexOf('mic') >= 0) { result = 'Microphone'; }
  34. if (str.indexOf('mikr') >= 0) { result = 'Microphone'; }
  35. if (str.indexOf('phone') >= 0) { result = 'Phone'; }
  36. if (str.indexOf('controll') >= 0) { result = 'Controller'; }
  37. if (str.indexOf('line o') >= 0) { result = 'Line Out'; }
  38. if (str.indexOf('digital o') >= 0) { result = 'Digital Out'; }
  39. if (!result && output) {
  40. result = 'Speaker';
  41. } else if (!result && input) {
  42. result = 'Microphone';
  43. }
  44. return result;
  45. }
  46. function getLinuxAudioPci() {
  47. let cmd = 'lspci -v 2>/dev/null';
  48. let result = [];
  49. try {
  50. const parts = execSync(cmd).toString().split('\n\n');
  51. for (let i = 0; i < parts.length; i++) {
  52. const lines = parts[i].split('\n');
  53. if (lines && lines.length && lines[0].toLowerCase().indexOf('audio') >= 0) {
  54. const audio = {};
  55. audio.slotId = lines[0].split(' ')[0];
  56. audio.driver = util.getValue(lines, 'Kernel driver in use', ':', true) || util.getValue(lines, 'Kernel modules', ':', true);
  57. result.push(audio);
  58. }
  59. }
  60. return result;
  61. } catch (e) {
  62. return result;
  63. }
  64. }
  65. function parseLinuxAudioPciMM(lines, audioPCI) {
  66. const result = {};
  67. const slotId = util.getValue(lines, 'Slot');
  68. const pciMatch = audioPCI.filter(function (item) { return item.slotId === slotId; });
  69. result.id = slotId;
  70. result.name = util.getValue(lines, 'SDevice');
  71. // result.type = util.getValue(lines, 'Class');
  72. result.manufacturer = util.getValue(lines, 'SVendor');
  73. result.revision = util.getValue(lines, 'Rev');
  74. result.driver = pciMatch && pciMatch.length === 1 && pciMatch[0].driver ? pciMatch[0].driver : '';
  75. result.default = null;
  76. result.channel = 'PCIe';
  77. result.type = parseAudioType(result.name, null, null);
  78. result.in = null;
  79. result.out = null;
  80. result.status = 'online';
  81. return result;
  82. }
  83. function parseDarwinChannel(str) {
  84. let result = '';
  85. if (str.indexOf('builtin') >= 0) { result = 'Built-In'; }
  86. if (str.indexOf('extern') >= 0) { result = 'Audio-Jack'; }
  87. if (str.indexOf('hdmi') >= 0) { result = 'HDMI'; }
  88. if (str.indexOf('displayport') >= 0) { result = 'Display-Port'; }
  89. if (str.indexOf('usb') >= 0) { result = 'USB'; }
  90. if (str.indexOf('pci') >= 0) { result = 'PCIe'; }
  91. return result;
  92. }
  93. function parseDarwinAudio(audioObject, id) {
  94. const result = {};
  95. const channelStr = ((audioObject.coreaudio_device_transport || '') + ' ' + (audioObject._name || '')).toLowerCase();
  96. result.id = id;
  97. result.name = audioObject._name;
  98. result.manufacturer = audioObject.coreaudio_device_manufacturer;
  99. result.revision = null;
  100. result.driver = null;
  101. result.default = !!(audioObject.coreaudio_default_audio_input_device || '') || !!(audioObject.coreaudio_default_audio_output_device || '');
  102. result.channel = parseDarwinChannel(channelStr);
  103. result.type = parseAudioType(result.name, !!(audioObject.coreaudio_device_input || ''), !!(audioObject.coreaudio_device_output || ''));
  104. result.in = !!(audioObject.coreaudio_device_input || '');
  105. result.out = !!(audioObject.coreaudio_device_output || '');
  106. result.status = 'online';
  107. return result;
  108. }
  109. function parseWindowsAudio(lines) {
  110. const result = {};
  111. const status = util.getValue(lines, 'StatusInfo', ':');
  112. // const description = util.getValue(lines, 'Description', ':');
  113. result.id = util.getValue(lines, 'DeviceID', ':'); // PNPDeviceID??
  114. result.name = util.getValue(lines, 'name', ':');
  115. result.manufacturer = util.getValue(lines, 'manufacturer', ':');
  116. result.revision = null;
  117. result.driver = null;
  118. result.default = null;
  119. result.channel = null;
  120. result.type = parseAudioType(result.name, null, null);
  121. result.in = null;
  122. result.out = null;
  123. result.status = status;
  124. return result;
  125. }
  126. function audio(callback) {
  127. return new Promise((resolve) => {
  128. process.nextTick(() => {
  129. let result = [];
  130. if (_linux || _freebsd || _openbsd || _netbsd) {
  131. let cmd = 'lspci -vmm 2>/dev/null';
  132. exec(cmd, function (error, stdout) {
  133. // PCI
  134. if (!error) {
  135. const audioPCI = getLinuxAudioPci();
  136. const parts = stdout.toString().split('\n\n');
  137. for (let i = 0; i < parts.length; i++) {
  138. const lines = parts[i].split('\n');
  139. if (util.getValue(lines, 'class', ':', true).toLowerCase().indexOf('audio') >= 0) {
  140. const audio = parseLinuxAudioPciMM(lines, audioPCI);
  141. result.push(audio);
  142. }
  143. }
  144. }
  145. if (callback) {
  146. callback(result);
  147. }
  148. resolve(result);
  149. });
  150. }
  151. if (_darwin) {
  152. let cmd = 'system_profiler SPAudioDataType -json';
  153. exec(cmd, function (error, stdout) {
  154. if (!error) {
  155. try {
  156. const outObj = JSON.parse(stdout.toString());
  157. if (outObj.SPAudioDataType && outObj.SPAudioDataType.length && outObj.SPAudioDataType[0] && outObj.SPAudioDataType[0]['_items'] && outObj.SPAudioDataType[0]['_items'].length) {
  158. for (let i = 0; i < outObj.SPAudioDataType[0]['_items'].length; i++) {
  159. const audio = parseDarwinAudio(outObj.SPAudioDataType[0]['_items'][i], i);
  160. result.push(audio);
  161. }
  162. }
  163. } catch (e) {
  164. util.noop();
  165. }
  166. }
  167. if (callback) {
  168. callback(result);
  169. }
  170. resolve(result);
  171. });
  172. }
  173. if (_windows) {
  174. util.powerShell('Get-WmiObject Win32_SoundDevice | select DeviceID,StatusInfo,Name,Manufacturer | fl').then((stdout, error) => {
  175. if (!error) {
  176. const parts = stdout.toString().split(/\n\s*\n/);
  177. for (let i = 0; i < parts.length; i++) {
  178. if (util.getValue(parts[i].split('\n'), 'name', ':')) {
  179. result.push(parseWindowsAudio(parts[i].split('\n')));
  180. }
  181. }
  182. }
  183. if (callback) {
  184. callback(result);
  185. }
  186. resolve(result);
  187. });
  188. }
  189. if (_sunos) {
  190. resolve(null);
  191. }
  192. });
  193. });
  194. }
  195. exports.audio = audio;