utilaudio.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. Copyright (C) 2015 Borsato Ivano
  3. The JavaScript code in this page is free software: you can
  4. redistribute it and/or modify it under the terms of the GNU
  5. General Public License (GNU GPL) as published by the Free Software
  6. Foundation, either version 3 of the License, or (at your option)
  7. any later version. The code is distributed WITHOUT ANY WARRANTY;
  8. without even the implied warranty of MERCHANTABILITY or FITNESS
  9. FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
  10. */
  11. 'use strict';
  12. import GObject from 'gi://GObject';
  13. import GIRepository from 'gi://GIRepository';
  14. GIRepository.Repository.prepend_search_path('/usr/lib/gnome-shell');
  15. GIRepository.Repository.prepend_library_path('/usr/lib/gnome-shell');
  16. GIRepository.Repository.prepend_search_path('/usr/lib64/gnome-shell');
  17. GIRepository.Repository.prepend_library_path('/usr/lib64/gnome-shell');
  18. import Gvc from 'gi://Gvc';
  19. import * as Lib from './convenience.js';
  20. import * as Settings from './settings.js';
  21. import * as Ext from './extension.js';
  22. /**
  23. * @type {MixerAudio}
  24. */
  25. export const MixerAudio = GObject.registerClass({
  26. GTypeName: 'EasyScreenCast_MixerAudio',
  27. }, class MixerAudio extends GObject.Object {
  28. constructor() {
  29. super();
  30. Lib.TalkativeLog('-#-mixer constructor');
  31. this._mixerControl = this._createMixerControl();
  32. this._isConnected = true;
  33. this._mixerControl.connect('state-changed', () =>
  34. this._onChangeStatePAC()
  35. );
  36. // more log for debug
  37. if (Lib.debugEnabled) {
  38. this._mixerControl.connect('stream_added', (control, id) => {
  39. this._onStreamAdd(control, id);
  40. });
  41. this._mixerControl.connect('stream_removed', (control, id) => {
  42. this._onStreamRemove(control, id);
  43. });
  44. }
  45. }
  46. /**
  47. * @returns {Gvc.MixerControl}
  48. * @private
  49. */
  50. _createMixerControl() {
  51. Lib.TalkativeLog('-#-mixer create');
  52. // https://gitlab.gnome.org/GNOME/libgnome-volume-control
  53. var _mixerTmp = new Gvc.MixerControl({
  54. name: 'ESC Mixer Control',
  55. });
  56. _mixerTmp.open();
  57. return _mixerTmp;
  58. }
  59. _onChangeStatePAC() {
  60. Lib.TalkativeLog('-#-mixer state changed');
  61. switch (this._mixerControl.get_state()) {
  62. case Gvc.MixerControlState.CLOSED:
  63. Lib.TalkativeLog('-#-Mixer close');
  64. this._isConnected = false;
  65. break;
  66. case Gvc.MixerControlState.CONNECTING:
  67. Lib.TalkativeLog('-#-Mixer connecting');
  68. this._isConnected = false;
  69. break;
  70. case Gvc.MixerControlState.FAILED:
  71. Lib.TalkativeLog('-#-Mixer failed');
  72. this._isConnected = false;
  73. break;
  74. case Gvc.MixerControlState.READY:
  75. Lib.TalkativeLog('-#-Mixer ready');
  76. this._isConnected = true;
  77. // more log for debug
  78. if (Lib.debugEnabled)
  79. this._getInfoPA();
  80. break;
  81. default:
  82. Lib.TalkativeLog('-#-Mixer UNK');
  83. this._isConnected = false;
  84. break;
  85. }
  86. }
  87. /**
  88. * Gets a list of input audio sources.
  89. *
  90. * @returns {Array}
  91. */
  92. getListInputAudio() {
  93. Lib.TalkativeLog('-#-get list input audio');
  94. if (this._isConnected) {
  95. var arrayTmp = [];
  96. var tmpSinks = this._mixerControl.get_sinks();
  97. Lib.TalkativeLog(`-#-Mixer sink -> ${tmpSinks.length}`);
  98. for (let x in tmpSinks) {
  99. Lib.TalkativeLog(`-#-sink index: ${tmpSinks[x].index}`);
  100. Lib.TalkativeLog(`-#-sink name: ${tmpSinks[x].name}`);
  101. Lib.TalkativeLog(
  102. `-#-sink description: ${tmpSinks[x].description}`
  103. );
  104. Lib.TalkativeLog(`-#-sink port: ${tmpSinks[x].port}`);
  105. arrayTmp.push({
  106. desc: tmpSinks[x].description,
  107. name: tmpSinks[x].name,
  108. port: tmpSinks[x].port,
  109. sortable: true,
  110. resizeable: true,
  111. });
  112. }
  113. var tmpSources = this._mixerControl.get_sources();
  114. Lib.TalkativeLog(`-#-Mixer sources -> ${tmpSources.length}`);
  115. for (let x in tmpSources) {
  116. Lib.TalkativeLog(`-#-source index: ${tmpSources[x].index}`);
  117. Lib.TalkativeLog(`-#-source name: ${tmpSources[x].name}`);
  118. Lib.TalkativeLog(
  119. `-#-source description: ${tmpSources[x].description}`
  120. );
  121. Lib.TalkativeLog(`-#-source port: ${tmpSources[x].port}`);
  122. arrayTmp.push({
  123. desc: tmpSources[x].description,
  124. name: tmpSources[x].name,
  125. port: tmpSources[x].port,
  126. sortable: true,
  127. resizeable: true,
  128. });
  129. }
  130. Lib.TalkativeLog(`-#-MIXER SOURCE TOT -> ${arrayTmp.length}`);
  131. return arrayTmp;
  132. } else {
  133. Lib.TalkativeLog('-#-Error lib pulse NOT present or NOT respond');
  134. }
  135. return [];
  136. }
  137. /**
  138. * @returns {string}
  139. */
  140. getAudioSource() {
  141. Lib.TalkativeLog('-#-get source audio choosen');
  142. var arrtmp = this.getListInputAudio();
  143. var index = Ext.Indicator.getSettings().getOption('i', Settings.INPUT_AUDIO_SOURCE_SETTING_KEY) - 2;
  144. if (index >= 0 && index < arrtmp.length) {
  145. return arrtmp[index].name;
  146. } else {
  147. Lib.TalkativeLog('-#-ERROR, audio source missing');
  148. Ext.Indicator.getSettings().setOption(Settings.INPUT_AUDIO_SOURCE_SETTING_KEY, 0);
  149. return '';
  150. }
  151. }
  152. /**
  153. * @param {Gvc.MixerControl} control the mixer control to which the stream was added
  154. * @param {number} id the stream id
  155. * @private
  156. */
  157. _onStreamAdd(control, id) {
  158. Lib.TalkativeLog(`-#-mixer stream add - ID: ${id}`);
  159. var streamTmp = control.lookup_stream_id(id);
  160. if (
  161. streamTmp.name === 'GNOME Shell' &&
  162. streamTmp.description === 'Record Stream'
  163. ) {
  164. Lib.TalkativeLog('-#-stream gnome recorder captured');
  165. Lib.TalkativeLog(`-#-stream index: ${streamTmp.index}`);
  166. Lib.TalkativeLog(`-#-stream card index: ${streamTmp.card_index}`);
  167. Lib.TalkativeLog(`-#-application_ID: ${streamTmp.application_id}`);
  168. Lib.TalkativeLog(`-#-stream name: ${streamTmp.name}`);
  169. Lib.TalkativeLog(`-#-stream icon: ${streamTmp.icon_name}`);
  170. Lib.TalkativeLog(`-#-stream description: ${streamTmp.description}`);
  171. Lib.TalkativeLog(`-#-stream port: ${streamTmp.port}`);
  172. }
  173. }
  174. /**
  175. * @param {Gvc.MixerControl} control the mixer control from where the stream was removed
  176. * @param {number} id stream id
  177. * @private
  178. */
  179. _onStreamRemove(control, id) {
  180. Lib.TalkativeLog(`-#-mixer stream remove - ID: ${id}`);
  181. // note: the stream has been already removed, so
  182. // control.lookup_stream_id(id) won't return anything
  183. }
  184. /**
  185. * @private
  186. */
  187. _getInfoPA() {
  188. var tmp = this._mixerControl.get_cards();
  189. Lib.TalkativeLog(`#-# mixer cards -> ${tmp.length}`);
  190. for (let x in tmp) {
  191. Lib.TalkativeLog(`-#-card index: ${tmp[x].index}`);
  192. Lib.TalkativeLog(`-#-card name: ${tmp[x].name}`);
  193. Lib.TalkativeLog(`-#-card icon: ${tmp[x].icon_name}`);
  194. Lib.TalkativeLog(`-#-card profile: ${tmp[x].profile}`);
  195. Lib.TalkativeLog(`-#-card human profile: ${tmp[x].human_profile}`);
  196. }
  197. tmp = this._mixerControl.get_sources();
  198. Lib.TalkativeLog(`#-# mixer sources -> ${tmp.length}`);
  199. for (let x in tmp) {
  200. Lib.TalkativeLog(`-#-source index: ${tmp[x].index}`);
  201. Lib.TalkativeLog(`-#-application_ID: ${tmp[x].application_id}`);
  202. Lib.TalkativeLog(`-#-source name: ${tmp[x].name}`);
  203. Lib.TalkativeLog(`-#-source icon: ${tmp[x].icon_name}`);
  204. Lib.TalkativeLog(`-#-source description: ${tmp[x].description}`);
  205. Lib.TalkativeLog(`-#-source port: ${tmp[x].port}`);
  206. }
  207. tmp = this._mixerControl.get_source_outputs();
  208. Lib.TalkativeLog(`#-# mixer source output -> ${tmp.length}`);
  209. for (let x in tmp) {
  210. Lib.TalkativeLog(`-#-sourceouput index: ${tmp[x].index}`);
  211. Lib.TalkativeLog(`-#-application_ID: ${tmp[x].application_id}`);
  212. Lib.TalkativeLog(`-#-sourceouput name: ${tmp[x].name}`);
  213. Lib.TalkativeLog(`-#-sourceoutput icon: ${tmp[x].icon_name}`);
  214. Lib.TalkativeLog(
  215. `-#-sourceoutput description: ${tmp[x].description}`
  216. );
  217. Lib.TalkativeLog(`-#-sourceoutput port: ${tmp[x].port}`);
  218. }
  219. tmp = this._mixerControl.get_sinks();
  220. Lib.TalkativeLog(`#-# mixer sink -> ${tmp.length}`);
  221. for (let x in tmp) {
  222. Lib.TalkativeLog(`-#-sink index: ${tmp[x].index}`);
  223. Lib.TalkativeLog(`-#-application_ID: ${tmp[x].application_id}`);
  224. Lib.TalkativeLog(`-#-sink name: ${tmp[x].name}`);
  225. Lib.TalkativeLog(`-#-sink icon: ${tmp[x].icon_name}`);
  226. Lib.TalkativeLog(`-#-sink description: ${tmp[x].description}`);
  227. Lib.TalkativeLog(`-#-sink port: ${tmp[x].port}`);
  228. }
  229. tmp = this._mixerControl.get_sink_inputs();
  230. Lib.TalkativeLog(`#-# mixer sink input -> ${tmp.length}`);
  231. for (let x in tmp) {
  232. Lib.TalkativeLog(`-#-sink input index: ${tmp[x].index}`);
  233. Lib.TalkativeLog(`-#-application_ID: ${tmp[x].application_id}`);
  234. Lib.TalkativeLog(`-#-sink input name: ${tmp[x].name}`);
  235. Lib.TalkativeLog(`-#-sink input icon: ${tmp[x].icon_name}`);
  236. Lib.TalkativeLog(
  237. `-#-sink input description: ${tmp[x].description}`
  238. );
  239. Lib.TalkativeLog(`-#-sink input port: ${tmp[x].port}`);
  240. }
  241. tmp = this._mixerControl.get_streams();
  242. Lib.TalkativeLog(`#-# mixer stream -> ${tmp.length}`);
  243. for (let x in tmp) {
  244. Lib.TalkativeLog(`-#-STREAM index: ${tmp[x].index}`);
  245. Lib.TalkativeLog(`-#-application_ID: ${tmp[x].application_id}`);
  246. Lib.TalkativeLog(`-#-stream name: ${tmp[x].name}`);
  247. Lib.TalkativeLog(`-#-stream icon: ${tmp[x].icon_name}`);
  248. Lib.TalkativeLog(`-#-stream description: ${tmp[x].description}`);
  249. var tmp1 = tmp[x].get_ports();
  250. for (let y in tmp1) {
  251. Lib.TalkativeLog(`-##-stream port number: ${y}`);
  252. Lib.TalkativeLog(`-##-stream port name: ${tmp1[y].port}`);
  253. Lib.TalkativeLog(
  254. `-##-stream port human name: ${tmp1[y].human_port}`
  255. );
  256. Lib.TalkativeLog(
  257. `-##-stream port priority: ${tmp1[y].priority}`
  258. );
  259. }
  260. }
  261. }
  262. /**
  263. * @returns {boolean}
  264. */
  265. checkAudio() {
  266. Lib.TalkativeLog(`-#-check GVC lib presence: ${this._isConnected}`);
  267. return this._isConnected;
  268. }
  269. /**
  270. * Destroy mixer control
  271. */
  272. destroy() {
  273. if (this._mixerControl) {
  274. this._mixerControl.close();
  275. this._mixerControl = null;
  276. }
  277. }
  278. });