diff options
author | MaZderMind <git@mazdermind.de> | 2016-09-26 20:42:07 +0200 |
---|---|---|
committer | MaZderMind <git@mazdermind.de> | 2016-09-26 20:42:07 +0200 |
commit | 6e846c7081e242213cd70ceacfcff319e221942c (patch) | |
tree | 9d037e9272e65aea06c74775b2af1eae2f50a46e /example-scripts/gstreamer/source-nostream-music-from-folder.py | |
parent | fbcbc3743e9179738244a96be54aa588e44314cb (diff) | |
parent | 1972da7f6aa60d3cb3b68808d0381e37898665f3 (diff) |
Merge branch 'pep8'
Diffstat (limited to 'example-scripts/gstreamer/source-nostream-music-from-folder.py')
-rwxr-xr-x | example-scripts/gstreamer/source-nostream-music-from-folder.py | 363 |
1 files changed, 193 insertions, 170 deletions
diff --git a/example-scripts/gstreamer/source-nostream-music-from-folder.py b/example-scripts/gstreamer/source-nostream-music-from-folder.py index a176a7d..c804182 100755 --- a/example-scripts/gstreamer/source-nostream-music-from-folder.py +++ b/example-scripts/gstreamer/source-nostream-music-from-folder.py @@ -1,6 +1,12 @@ #!/usr/bin/env python3 -import os, sys, gi, signal, random -import argparse, logging, pyinotify +import os +import sys +import gi +import signal +import random +import argparse +import logging +import pyinotify gi.require_version('Gst', '1.0') from gi.repository import Gst, GObject, GLib @@ -9,189 +15,206 @@ from gi.repository import Gst, GObject, GLib GObject.threads_init() Gst.init([]) -class Directory(object): - def __init__(self, path): - self.log = logging.getLogger('Directory') - self.path = path - self.scheduled = False - self.rescan() - - self.log.debug('setting up inotify watch for %s', self.path) - wm = pyinotify.WatchManager() - notifier = pyinotify.Notifier(wm, - timeout=10, - default_proc_fun=self.inotify_callback) - - wm.add_watch( - self.path, - #pyinotify.ALL_EVENTS, - pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY, - rec=True) - - GLib.io_add_watch( - notifier._fd, - GLib.IO_IN, - self.io_callback, - notifier) - - def inotify_callback(self, notifier): - self.log.info('inotify callback %s: %s', notifier.maskname, notifier.pathname) - if not self.scheduled: - self.scheduled = True - GLib.timeout_add(100, self.rescan) - return True - - def io_callback(self, source, condition, notifier): - notifier.process_events() - while notifier.check_events(): - notifier.read_events() - notifier.process_events() - - return True - def is_playable_file(self, filepath): - root, ext = os.path.splitext(filepath) - return ext in ['.mp3', '.ogg', '.oga', '.wav', '.m4a', '.flac', 'self.opus'] - - def rescan(self): - self.log.info('scanning directory %s', self.path) - self.scheduled = False - - all_files = [] - - for root, dirs, files in os.walk(self.path): - files = filter(self.is_playable_file, files) - files = map(lambda f: os.path.join(root, f), files) - files = list(files) - - self.log.debug('found directory %s: %u playable file(s)', root, len(files)) - all_files.extend(files) +class Directory(object): - self.log.info('found %u playable files', len(all_files)) - self.files = all_files + def __init__(self, path): + self.log = logging.getLogger('Directory') + self.path = path + self.scheduled = False + self.rescan() + + self.log.debug('setting up inotify watch for %s', self.path) + wm = pyinotify.WatchManager() + notifier = pyinotify.Notifier( + wm, + timeout=10, + default_proc_fun=self.inotify_callback + ) + + wm.add_watch( + self.path, + # pyinotify.ALL_EVENTS, + pyinotify.IN_DELETE | pyinotify.IN_CREATE | pyinotify.IN_MODIFY, + rec=True + ) + + GLib.io_add_watch( + notifier._fd, + GLib.IO_IN, + self.io_callback, + notifier + ) + + def inotify_callback(self, notifier): + self.log.info('inotify callback %s: %s', + notifier.maskname, notifier.pathname) + if not self.scheduled: + self.scheduled = True + GLib.timeout_add(100, self.rescan) + return True + + def io_callback(self, source, condition, notifier): + notifier.process_events() + while notifier.check_events(): + notifier.read_events() + notifier.process_events() + + return True + + def is_playable_file(self, filepath): + root, ext = os.path.splitext(filepath) + return ext in ['.mp3', '.ogg', '.oga', '.wav', '.m4a', + '.flac', 'self.opus'] + + def rescan(self): + self.log.info('scanning directory %s', self.path) + self.scheduled = False + + all_files = [] + + for root, dirs, files in os.walk(self.path): + files = filter(self.is_playable_file, files) + files = map(lambda f: os.path.join(root, f), files) + files = list(files) + + self.log.debug('found directory %s: %u playable file(s)', + root, len(files)) + all_files.extend(files) + + self.log.info('found %u playable files', len(all_files)) + self.files = all_files + + def get_random_file(self): + return random.choice(self.files) + + def get_random_uri(self): + return 'file://' + self.get_random_file() - def get_random_file(self): - return random.choice(self.files) - def get_random_uri(self): - return 'file://'+self.get_random_file() +class LoopSource(object): + def __init__(self, directory): + self.log = logging.getLogger('LoopSource') + self.directory = directory + + pipeline = """ + audioresample name=join ! + audioconvert ! + audio/x-raw,format=S16LE,channels=2,rate=48000, + layout=interleaved ! + matroskamux ! + tcpclientsink host=localhost port=18000 + """ + + # Parsing Pipeline + self.log.debug('creating pipeline\n%s', pipeline) + self.pipeline = Gst.parse_launch(pipeline) + + # Selecting inital URI + inital_uri = self.directory.get_random_uri() + self.log.info('initial track %s', inital_uri) + + # Create decoder-element + self.src = Gst.ElementFactory.make('uridecodebin', None) + self.src.set_property('uri', inital_uri) + self.src.connect('pad-added', self.on_pad_added) + self.pipeline.add(self.src) + + # Save pad on the Join-Element + self.joinpad = self.pipeline.get_by_name('join').get_static_pad('sink') + + # Binding End-of-Stream-Signal on Source-Pipeline + self.pipeline.bus.add_signal_watch() + self.pipeline.bus.connect("message::eos", self.on_eos) + self.pipeline.bus.connect("message::error", self.on_error) + + self.log.debug('setting pipeline to playing') + self.pipeline.set_state(Gst.State.PLAYING) + + def on_pad_added(self, src, pad): + self.log.debug('new pad on decoder, setting pad-probe') + pad.add_probe( + Gst.PadProbeType.EVENT_DOWNSTREAM | Gst.PadProbeType.BLOCK, + self.on_pad_event + ) + if self.joinpad.is_linked(): + self.log.debug('unlinking with joinpad') + self.joinpad.unlink(self.joinpad.get_peer()) + + clock = self.pipeline.get_clock() + if clock: + runtime = clock.get_time() - self.pipeline.get_base_time() + self.log.debug('setting pad offset to pipeline runtime: %sns', + runtime) + pad.set_offset(runtime) + + self.log.debug('linking with joinpad') + pad.link(self.joinpad) + + def on_pad_event(self, pad, info): + event = info.get_event() + self.log.debug('event %s on pad %s', event.type, pad) + + if event.type == Gst.EventType.EOS: + self.log.debug('scheduling next track and dropping EOS-Event') + GObject.idle_add(self.next_track) + return Gst.PadProbeReturn.DROP + + return Gst.PadProbeReturn.PASS + + def next_track(self): + next_uri = self.directory.get_random_uri() + self.log.info('next track %s', next_uri) + + self.src.set_state(Gst.State.READY) + self.src.set_property('uri', next_uri) + self.src.set_state(Gst.State.PLAYING) + return False + + def on_eos(self, bus, message): + self.log.info('received EOS-Event on bus, exiting') + sys.exit(1) + + def on_error(self, bus, message): + self.log.warning('received Error-Event on bus, exiting') + (error, debug) = message.parse_error() + self.log.warning('Error-Details: #%u: %s', error.code, debug) + sys.exit(1) -class LoopSource(object): - def __init__(self, directory): - self.log = logging.getLogger('LoopSource') - self.directory = directory - - pipeline = """ - audioresample name=join ! - audioconvert ! - audio/x-raw,format=S16LE,channels=2,layout=interleaved,rate=48000 ! - matroskamux ! - tcpclientsink host=localhost port=18000 - """ - - # Parsing Pipeline - self.log.debug('creating pipeline\n%s', pipeline) - self.pipeline = Gst.parse_launch(pipeline) - - # Selecting inital URI - inital_uri = self.directory.get_random_uri() - self.log.info('initial track %s', inital_uri) - - # Create decoder-element - self.src = Gst.ElementFactory.make('uridecodebin', None) - self.src.set_property('uri', inital_uri); - self.src.connect('pad-added', self.on_pad_added) - self.pipeline.add(self.src) - - # Save pad on the Join-Element - self.joinpad = self.pipeline.get_by_name('join').get_static_pad('sink') - - # Binding End-of-Stream-Signal on Source-Pipeline - self.pipeline.bus.add_signal_watch() - self.pipeline.bus.connect("message::eos", self.on_eos) - self.pipeline.bus.connect("message::error", self.on_error) - - self.log.debug('setting pipeline to playing') - self.pipeline.set_state(Gst.State.PLAYING) - - def on_pad_added(self, src, pad): - self.log.debug('new pad on decoder, setting pad-probe') - pad.add_probe(Gst.PadProbeType.EVENT_DOWNSTREAM | Gst.PadProbeType.BLOCK, self.on_pad_event) - if self.joinpad.is_linked(): - self.log.debug('unlinking with joinpad') - self.joinpad.unlink(self.joinpad.get_peer()) - - clock = self.pipeline.get_clock() - if clock: - runtime = clock.get_time() - self.pipeline.get_base_time() - self.log.debug('setting pad offset to pipeline runtime: %sns', runtime) - pad.set_offset(runtime) - - self.log.debug('linking with joinpad') - pad.link(self.joinpad) - - def on_pad_event(self, pad, info): - event = info.get_event() - self.log.debug('event %s on pad %s', event.type, pad) - - if event.type == Gst.EventType.EOS: - self.log.debug('scheduling next track and dropping EOS-Event') - GObject.idle_add(self.next_track) - return Gst.PadProbeReturn.DROP - - return Gst.PadProbeReturn.PASS - - def next_track(self): - next_uri = self.directory.get_random_uri() - self.log.info('next track %s', next_uri) - - self.src.set_state(Gst.State.READY) - self.src.set_property('uri', next_uri); - self.src.set_state(Gst.State.PLAYING) - return False - - def on_eos(self, bus, message): - self.log.info('received EOS-Event on bus, exiting') - sys.exit(1) - - def on_error(self, bus, message): - self.log.warning('received Error-Event on bus, exiting') - (error, debug) = message.parse_error() - self.log.warning('Error-Details: #%u: %s', error.code, debug) - sys.exit(1) def main(): - signal.signal(signal.SIGINT, signal.SIG_DFL) + signal.signal(signal.SIGINT, signal.SIG_DFL) - parser = argparse.ArgumentParser(description='Voctocore Music-Source') - parser.add_argument('directory') + parser = argparse.ArgumentParser(description='Voctocore Music-Source') + parser.add_argument('directory') - parser.add_argument('-v|-vv', '--verbose', action='count', default=0, - help="Also print INFO and DEBUG messages.") + parser.add_argument('-v|-vv', '--verbose', action='count', default=0, + help="Also print INFO and DEBUG messages.") - args = parser.parse_args() + args = parser.parse_args() - if args.verbose >= 2: - level = logging.DEBUG - elif args.verbose == 1: - level = logging.INFO - else: - level = logging.WARNING + if args.verbose >= 2: + level = logging.DEBUG + elif args.verbose == 1: + level = logging.INFO + else: + level = logging.WARNING - logging.basicConfig( - level=level, - format='%(levelname)8s %(name)s: %(message)s') + logging.basicConfig( + level=level, + format='%(levelname)8s %(name)s: %(message)s' + ) - directory = Directory(args.directory) - src = LoopSource(directory) + directory = Directory(args.directory) + src = LoopSource(directory) - mainloop = GObject.MainLoop() - try: - mainloop.run() - except KeyboardInterrupt: - print('Terminated via Ctrl-C') + mainloop = GObject.MainLoop() + try: + mainloop.run() + except KeyboardInterrupt: + print('Terminated via Ctrl-C') if __name__ == '__main__': - main() + main() |