Example #1
0
        def __init__(self):

            print("Init GStreamer...")

            # This is used to keep track of time between callbacks.
            self.player_timer = Timer()

            # Store the track object that is currently playing
            self.loaded_track = None

            # This is used to keep note of what state of playing we should be in
            self.play_state = 0  # 0 is stopped, 1 is playing, 2 is paused

            # Initiate GSteamer
            Gst.init([])
            self.mainloop = GLib.MainLoop()

            # Populate list of output devices with defaults
            outputs = {}
            devices = [
                "PulseAudio",
                "ALSA",
                "JACK",
            ]
            if tauon.snap_mode:  # Snap permissions don't support these by default
                devices.remove("JACK")
                devices.remove("ALSA")

            # Get list of available audio device
            self.dm = Gst.DeviceMonitor()
            self.dm.start()
            for device in self.dm.get_devices():
                if device.get_device_class() == "Audio/Sink":
                    element = device.create_element(None)
                    type_name = element.get_factory().get_name()
                    if hasattr(element.props, "device"):
                        device_name = element.props.device
                        display_name = device.get_display_name()

                        # This is used by the UI to present list of options to the user in audio settings
                        outputs[display_name] = (type_name, device_name)
                        devices.append(display_name)

            # dm.stop()  # Causes a segfault sometimes
            pctl.gst_outputs = outputs
            pctl.gst_devices = devices

            # Create main "playbin" pipeline for playback
            self.playbin = Gst.ElementFactory.make("playbin", "player")

            # Create custom output bin from user preferences
            if not prefs.gst_use_custom_output:
                prefs.gst_output = prefs.gen_gst_out()

            self._output = Gst.parse_bin_from_description(
                prefs.gst_output, ghost_unlinked_pads=True)

            # Create a bin for the audio pipeline
            self._sink = Gst.ElementFactory.make("bin", "sink")
            self._sink.add(self._output)

            # Spectrum -------------------------
            # Cant seem to figure out how to process these magnitudes in a way that looks good

            # self.spectrum = Gst.ElementFactory.make("spectrum", "spectrum")
            # self.spectrum.set_property('bands', 20)
            # self.spectrum.set_property('interval', 10000000)
            # self.spectrum.set_property('threshold', -100)
            # self.spectrum.set_property('post-messages', True)
            # self.spectrum.set_property('message-magnitude', True)
            #
            # self.playbin.set_property('audio-filter', self.spectrum)
            # # ------------------------------------

            # # Level Meter -------------------------
            self.level = Gst.ElementFactory.make("level", "level")
            self.level.set_property('interval', 20000000)
            self.playbin.set_property('audio-filter', self.level)
            # # ------------------------------------

            self._eq = Gst.ElementFactory.make("equalizer-nbands", "eq")
            self._vol = Gst.ElementFactory.make("volume", "volume")

            self._sink.add(self._eq)
            self._sink.add(self._vol)

            self._eq.link(self._vol)
            self._vol.link(self._output)

            self._eq.set_property("num-bands", 10 + 2)

            # Set the equalizer based on user preferences

            # Using workaround for "inverted slider" bug.
            # Thanks to Lollypop and Clementine for discovering this.
            # Ref https://github.com/Taiko2k/TauonMusicBox/issues/414

            for i in range(10 + 2):
                band = self._eq.get_child_by_index(i)
                band.set_property("freq", 0)
                band.set_property("bandwidth", 0)
                band.set_property("gain", 0)

            self.set_eq()
            # if prefs.use_eq:
            #     self._eq.set_property("band" + str(i), level * -1)
            # else:
            #     self._eq.set_property("band" + str(i), 0.0)

            # Set up sink pad for the intermediate bin via the
            # first element (volume)
            ghost = Gst.GhostPad.new("sink", self._eq.get_static_pad("sink"))
            self._sink.add_pad(ghost)

            # Connect the playback bin to to the intermediate bin sink pad
            self.playbin.set_property("audio-sink", self._sink)

            # The pipeline should look something like this -
            # (player) -> [(eq) -> (volume) -> (output)]

            # Create controller for pause/resume volume fading
            self.c_source = GstController.InterpolationControlSource()
            self.c_source.set_property('mode',
                                       GstController.InterpolationMode.LINEAR)
            self.c_binding = GstController.DirectControlBinding.new(
                self._vol, "volume", self.c_source)
            self._vol.add_control_binding(self.c_binding)

            # Set callback for the main callback loop
            GLib.timeout_add(50, self.main_callback)

            self.playbin.connect("about-to-finish",
                                 self.about_to_finish)  # Not used

            # Setup bus and select what types of messages we want to listen for
            bus = self.playbin.get_bus()
            bus.add_signal_watch()
            bus.connect('message::element', self.on_message)
            bus.connect('message::buffering', self.on_message)
            bus.connect('message::error', self.on_message)
            bus.connect('message::tag', self.on_message)
            bus.connect('message::warning', self.on_message)
            # bus.connect('message::eos', self.on_message)

            # Variables used with network downloading
            self.temp_id = "a"
            self.url = None
            self.dl_ready = True
            self.using_cache = False
            self.temp_path = ""  # Full path + filename
            # self.level_train = []
            self.seek_timer = Timer()
            self.seek_timer.force_set(10)
            self.buffering = False
            # Other
            self.end_timer = Timer()

            # Start GLib mainloop
            self.mainloop.run()
        def __init__(self):

            # This is used to keep track of time between callbacks to progress the seek bar
            self.player_timer = Timer()

            # This is used to keep note of what state of playing we should be in
            self.play_state = 0  # 0 is stopped, 1 is playing, 2 is paused

            # Initiate GSteamer
            Gst.init([])
            self.mainloop = GLib.MainLoop()

            # Get list of available audio device
            pctl.gst_devices = ["Auto", "PulseAudio", "ALSA", "JACK"]
            if tauon.snap_mode:
                pctl.gst_devices.remove("JACK")
                pctl.gst_devices.remove("ALSA")
            pctl.gst_outputs.clear()
            dm = Gst.DeviceMonitor()
            dm.start()
            for device in dm.get_devices():
                if device.get_device_class() == "Audio/Sink":
                    element = device.create_element(None)
                    type_name = element.get_factory().get_name()
                    device_name = element.props.device
                    display_name = device.get_display_name()

                    # This is used by the UI to present list of options to the user in audio settings
                    pctl.gst_outputs[display_name] = (type_name, device_name)
                    pctl.gst_devices.append(display_name)

            dm.stop()

            # Create main "playbin" pipeline for playback
            self.playbin = Gst.ElementFactory.make("playbin", "player")

            # Create output bin
            if not prefs.gst_use_custom_output:
                prefs.gst_output = prefs.gen_gst_out()

            self._output = Gst.parse_bin_from_description(
                prefs.gst_output, ghost_unlinked_pads=True)

            # Create a bin for the audio pipeline
            self._sink = Gst.ElementFactory.make("bin", "sink")
            self._sink.add(self._output)

            # # Spectrum -------------------------
            # # This kind of works, but is a different result to that of the bass backend.
            # # This seems linear and also less visually appealing.
            #
            # self.spectrum = Gst.ElementFactory.make("spectrum", "spectrum")
            # self.spectrum.set_property('bands', 280)
            # self.spectrum.set_property('interval', 10000000)
            # self.spectrum.set_property('post-messages', True)
            # self.spectrum.set_property('message-magnitude', True)
            #
            # self.playbin.set_property('audio-filter', self.spectrum)
            # # ------------------------------------

            # Create volume element
            self._vol = Gst.ElementFactory.make("volume", "volume")
            self._sink.add(self._vol)
            self._vol.link(self._output)

            # Set up sink pad for the intermediate bin via the
            #  first element (volume)
            ghost = Gst.GhostPad.new("sink", self._vol.get_static_pad("sink"))

            self._sink.add_pad(ghost)

            # Connect the playback bin to to the intermediate bin sink pad
            self.playbin.set_property("audio-sink", self._sink)

            # The pipeline should look something like this -
            # (player) -> [(volume) -> (output)]

            # Set callback for the main callback loop
            GLib.timeout_add(50, self.main_callback)

            # self.playbin.connect("about-to-finish", self.about_to_finish)  # Not used by anything

            # # Enable bus to get spectrum messages
            bus = self.playbin.get_bus()
            bus.add_signal_watch()
            bus.connect('message::element', self.on_message)
            bus.connect('message::buffering', self.on_message)
            bus.connect('message::error', self.on_message)
            bus.connect('message::tag', self.on_message)
            # bus.connect('message::warning', self.on_message)
            # bus.connect('message::eos', self.on_message)

            # Variables used with network downloading
            self.temp_id = "a"
            self.url = None
            self.dl_ready = False
            self.temp_path = ""  # Full path + filename

            # # Broadcasting pipeline ------------
            #
            # # This works, but only for one track, switching tracks seems to be a more complicated process.
            #
            # self.b_playbin = Gst.ElementFactory.make("playbin", "player")
            #
            # # Create output bin
            # # Using tcpserversink seems to mostly work with the html5 player, though an HTTP server may be preferred.
            # self._b_output = Gst.parse_bin_from_description(
            #    "audioconvert ! vorbisenc ! oggmux ! tcpserversink port=8000", ghost_unlinked_pads=True)
            #    #"autoaudiosink", ghost_unlinked_pads=True)
            #
            # # Connect the playback bin to to the output bin
            # self.b_playbin.set_property("audio-sink", self._b_output)
            # # ----------------------------------------

            # Start GLib mainloop
            self.mainloop.run()