Skip to content

Commit

Permalink
Simplify playing sounds
Browse files Browse the repository at this point in the history
Uses a different sound player that doesn't require extra libraries
installed. Breaks out audio player into a separate class.

Fixes wbolster#71
  • Loading branch information
BenignBeppe committed Nov 3, 2024
1 parent 2f4a66e commit ef10653
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 78 deletions.
16 changes: 0 additions & 16 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,6 @@ put a clone of this repository (or a symlink) in this directory::
note that the files must be directly in this directory, not in a
subdirectory thereof.

starting with version 14, the new sound notification feature is available and enabled by default.
it requires the gobject introspection data for the gstreamer plugins base library installed in your system.
having no sound, check your system logs for:

Unable to import sound module. Playing sound is not available. Is GStreamer package installed?

Requiring GstAudio, version none: Typelib file for namespace 'GstAudio' (any version) not found

and eventually install it. for ubuntu::

sudo apt install gir1.2-gst-plugins-base-1.0

for fedora::

sudo dnf install gstreamer1-plugins-base

why?
====

Expand Down
78 changes: 31 additions & 47 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@ import Meta from "gi://Meta";
import Shell from "gi://Shell";
import Gvc from "gi://Gvc";
import GObject from "gi://GObject";
import Gst from "gi://Gst";
import GstAudio from "gi://GstAudio";

import * as Main from "resource:///org/gnome/shell/ui/main.js";
import * as PanelMenu from "resource:///org/gnome/shell/ui/panelMenu.js";
import { Extension } from "resource:///org/gnome/shell/extensions/extension.js";

import * as Signals from "resource:///org/gnome/shell/misc/signals.js";

const isPlayingSoundSupported = Gst != null && GstAudio != null;

const EXCLUDED_APPLICATION_IDS = [
"org.gnome.VolumeControl",
"org.PulseAudio.pavucontrol",
Expand All @@ -28,10 +24,11 @@ const MICROPHONE_ACTIVE_STYLE_CLASS = "screencast-indicator";
let initialised = false; // flag to avoid notifications on startup
let settings = null;
let microphone;
let audio_player;
let panel_button;

class Microphone extends Signals.EventEmitter {
constructor(dir) {
constructor() {
super();
this.active = null;
this.stream = null;
Expand All @@ -44,11 +41,6 @@ class Microphone extends Signals.EventEmitter {
this.mixer_control.connect("default-source-changed", refresh_cb);
this.mixer_control.connect("stream-added", refresh_cb);
this.mixer_control.connect("stream-removed", refresh_cb);
if (isPlayingSoundSupported) {
Gst.init(null);
this.on_sound = init_sound(dir, "on");
this.off_sound = init_sound(dir, "off");
}
this.refresh();
}

Expand Down Expand Up @@ -102,6 +94,29 @@ class Microphone extends Signals.EventEmitter {
}
}

class AudioPlayer {
#sound_on;
#sound_off;

constructor(dir) {
this.#sound_on = dir.get_child("sounds/on.ogg");
this.#sound_off = dir.get_child("sounds/off.ogg");
}

#play_sound(sound_file) {
let player = global.display.get_sound_player();
player.play_from_file(sound_file, "Toggle mute", null);
}

play_on() {
this.#play_sound(this.#sound_on);
}

play_off() {
this.#play_sound(this.#sound_off);
}
}

const MicrophonePanelButton = GObject.registerClass(
{ GTypeName: "MicrophonePanelButton" },
class extends PanelMenu.Button {
Expand All @@ -119,26 +134,6 @@ const MicrophonePanelButton = GObject.registerClass(
},
);

function init_sound(dir, name) {
const playbin = Gst.ElementFactory.make("playbin", null);
const path = dir.get_child(`sounds/${name}.ogg`).get_path();
const uri = Gst.filename_to_uri(path);
playbin.set_property("uri", uri);
const sink = Gst.ElementFactory.make("pulsesink", "sink");
playbin.set_property("audio-sink", sink);
playbin.set_volume(GstAudio.StreamVolumeFormat.LINEAR, 0.5);

// Fix audio node suspend-on-idle; stop playback at end-of-stream
const bus = playbin.get_bus();
bus.add_signal_watch();
bus.connect('message', (_bus, msg) => {
if (msg.type === Gst.MessageType.EOS)
playbin.set_state(Gst.State.NULL);
});

return playbin;
}

function get_icon_name(muted) {
// TODO: use -low and -medium icons based on .level
return muted
Expand Down Expand Up @@ -172,11 +167,8 @@ function on_activate({ give_feedback }) {
if (give_feedback) {
show_osd(null, false, microphone.level);
}
if (
isPlayingSoundSupported &&
settings.get_boolean("play-feedback-sounds")
) {
play_sound(microphone.on_sound);
if (settings.get_boolean("play-feedback-sounds")) {
audio_player.play_on();
}
} else {
// use a delay before muting; this makes push-to-talk work
Expand All @@ -193,26 +185,18 @@ function on_activate({ give_feedback }) {
if (give_feedback) {
show_osd(null, true, 0);
}
if (
isPlayingSoundSupported &&
settings.get_boolean("play-feedback-sounds")
) {
play_sound(microphone.off_sound);
if (settings.get_boolean("play-feedback-sounds")) {
audio_player.play_off();
}
});
}
}

function play_sound(sound) {
// Rewind in case the sound has played already.
sound.set_state(Gst.State.NULL);
sound.set_state(Gst.State.PLAYING);
}

export default class extends Extension {
enable() {
settings = this.getSettings();
microphone = new Microphone(this.dir);
microphone = new Microphone();
audio_player = new AudioPlayer(this.dir);
panel_button = new MicrophonePanelButton(this.metadata);
panel_button.visible = icon_should_be_visible(microphone.active);
const indicatorName = `${this.metadata.name} indicator`;
Expand Down
15 changes: 0 additions & 15 deletions prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import Gio from "gi://Gio";
import Gtk from "gi://Gtk";
import GObject from "gi://GObject";
import Adw from "gi://Adw";
import Gst from "gi://Gst";
import GstAudio from "gi://GstAudio";

import { ExtensionPreferences } from "resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js";

Expand Down Expand Up @@ -144,18 +142,5 @@ export default class extends ExtensionPreferences {
Gio.SettingsBindFlags.DEFAULT,
);
group.add(feedbackSoundsSwitch);

// no sound alert row
const isPlayingSoundSupported = Gst != null && GstAudio != null;
if (!isPlayingSoundSupported) {
const playingSoundNotSupportedLabel = new Gtk.Label({
halign: Gtk.Align.START,
});
playingSoundNotSupportedLabel.set_markup(
"<span foreground='red'>WARNING. Playing sound is not supported on this system. Is GStreamer package installed?</span>",
);
playingSoundNotSupportedLabel.set_wrap(true);
group.add(playingSoundNotSupportedLabel);
}
}
}

0 comments on commit ef10653

Please sign in to comment.