Skip to content

Instantly share code, notes, and snippets.

@simonesestito
Last active March 25, 2024 08:58
Show Gist options
  • Save simonesestito/ef4ea0c1af420d474d29a9a20d375d80 to your computer and use it in GitHub Desktop.
Save simonesestito/ef4ea0c1af420d474d29a9a20d375d80 to your computer and use it in GitHub Desktop.
Fix noisy microphone's left channel
/**
* Gnome Extension (tested on Gnome 46 and with previous exact configuration).
*/
import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
const { GLib } = imports.gi;
const DEBUG_LOG_TAG = 'mic-hider';
function log(message) {
console.log(`[${DEBUG_LOG_TAG}] ${message}`);
}
export default class MicHiderExtension extends Extension {
enable() {
log('Starting');
// Adapted from: https://discourse.gnome.org/t/main-panel-statusarea-quicksettings-system-is-undefined/16827/2
if (Main.panel.statusArea.quickSettings._volumeInput) {
this._initMicControllers();
} else {
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
if (!Main.panel.statusArea.quickSettings._volumeInput)
return GLib.SOURCE_CONTINUE;
this._initMicControllers();
return GLib.SOURCE_REMOVE;
});
}
}
_initMicControllers() {
this.micIndicator = Main.panel.statusArea.quickSettings._volumeInput;
log(`micIndicator: ${this.micIndicator}`);
this.controlHandlerIds = [];
this.controlHandlerIds.push(this.micIndicator._control.connect('stream-added', () => this.updateVisibility()));
this.controlHandlerIds.push(this.micIndicator._control.connect('stream-removed', () => this.updateVisibility()));
this.controlHandlerIds.push(this.micIndicator._control.connect('input-added', () => this.updateVisibility()));
this.controlHandlerIds.push(this.micIndicator._control.connect('input-removed', () => this.updateVisibility()));
log(`controlHandlerIds: ${this.controlHandlerIds.join(', ')}`);
this.inputHandlerId = this.micIndicator._input.connect('notify::visible', () => this.updateVisibility());
log(`inputHandlerId: ${this.inputHandlerId}`);
this.updateVisibility();
}
disable() {
// Revert whatever we did in enable()
for (const handlerId of this.controlHandlerIds) {
this.micIndicator._control.disconnect(handlerId);
}
this.micIndicator._input.disconnect(this.inputHandlerId);
this.micIndicator.visible = this.micIndicator._input._shouldBeVisible();
}
isMicActive() {
const allOutputs = this.micIndicator._control.get_source_outputs();
log('Listing all outputs:');
for (const output of allOutputs) {
log(` Application ID: ${output.get_application_id()}`);
log(` Description: ${output.get_description()}`);
log(` ID: ${output.get_id()}`);
log(` Name: ${output.get_name()}`);
log(` State: ${output.get_state()}`);
log(` ------------------------ `);
}
// Return true if there is an input that doesn't match the pattern of our virtual mic
// However, this may be a security risk, as it could be possible to spoof the name of the virtual mic!
for (const output of allOutputs) {
const expectedDescription = 'Remapped alsa_input.pci-0000_03_00.6.analog-stereo source input';
const expectedName = null;
const expectedApplicationId = null;
// In general, none of our virtual sinks have a name or application ID
if (output.get_name() !== expectedName || output.get_application_id() !== expectedApplicationId) {
log(`Showing mic (name: ${output.get_name()}, application ID: ${output.get_application_id()})`);
return true;
}
// Check for all of our virtual sinks, based on the description
const isVirtualMic = output.get_description() === expectedDescription;
const loopbackSinkRegex = /^loopback-1[0-9]{3}-1[0-9] input$/g;
const isLoopbackSink = loopbackSinkRegex.test(output.get_description());
if (!isVirtualMic && !isLoopbackSink) {
log(`Showing mic (description: ${output.get_description()})`);
return true;
}
}
return false;
}
updateVisibility() {
const expectedVisibility = this.micIndicator._input._shouldBeVisible() && this.isMicActive();
if (this.micIndicator.visible != expectedVisibility) {
this.micIndicator.visible = expectedVisibility;
}
}
}
{
"name": "Hide useless Mic indicator",
"description": "Hide the Mic indicator from Gnome status bar if it is useless at the moment",
"uuid": "1297f1ec-e681-491c-93d2-3da7bb487e90",
"shell-version": [
"46"
],
"url": "https://gist.github.com/simonesestito/ef4ea0c1af420d474d29a9a20d375d80"
}
DEFAULT_MIC_ID=alsa_input.pci-0000_03_00.6.analog-stereo
[Unit]
Description=Mic Noise Fix
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/home/simone/.config/systemd/user/mic_noise_fix_start.sh
ExecStop=/home/simone/.config/systemd/user/mic_noise_fix_stop.sh
[Install]
WantedBy=default.target
#!/bin/sh --
set -e
set -x
source /home/simone/.config/systemd/user/mic_noise_fix.env
# Create the new virtual microphone, with correct noise suppression and ignoring the broken channel
pactl load-module module-switch-on-connect
pactl load-module module-remap-source \
source_name=virtual_mic_remapped \
master=${DEFAULT_MIC_ID} \
channels=1 \
master_channel_map=front-right \
channel_map=mono
pactl set-default-source virtual_mic_remapped
pactl set-source-volume ${DEFAULT_MIC_ID} '32%'
pactl set-source-volume virtual_mic_remapped '75%'
#!/bin/sh --
set -e
set -x
source /home/simone/.config/systemd/user/mic_noise_fix.env
# Revert the modifications made in mic_noise_fix_start.sh
pactl unload-module module-remap-source
pactl unload-module module-switch-on-connect
pactl set-default-source "${DEFAULT_MIC_ID}"
/* Add your custom extension styling here */
#panel .microphone-indicator {
display: none;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment