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()