Skip to content

Commit

Permalink
Add support for asynchronous audiosinks. With playlists working as th…
Browse files Browse the repository at this point in the history
…ey should
  • Loading branch information
wuurrd committed Jan 11, 2012
1 parent e2991f9 commit b08d4e4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
30 changes: 24 additions & 6 deletions examples/jukebox.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
#!/usr/bin/env python

import os
import sys
import cmd
import traceback
import time
import traceback
import threading
import os

from spotify import ArtistBrowser, Link, ToplistBrowser
from spotify.audiosink import import_audio_sink
from spotify.manager import (SpotifySessionManager, SpotifyPlaylistManager,
SpotifyContainerManager)

AudioSink = import_audio_sink()
container_loaded = threading.Event()

class JukeboxUI(cmd.Cmd, threading.Thread):

Expand All @@ -26,6 +27,7 @@ def __init__(self, jukebox):
self.results = False

def run(self):
container_loaded.wait()
try:
self.cmdloop()
except Exception, e:
Expand Down Expand Up @@ -264,7 +266,8 @@ def tracks_removed(self, p, t, u):
## container calllbacks ##
class JukeboxContainerManager(SpotifyContainerManager):
def container_loaded(self, c, u):
print 'Container loaded !'
container_loaded.set()
container_loaded.clear()

def playlist_added(self, c, p, i, u):
print 'Container: playlist "%s" added.' % p.name()
Expand All @@ -285,14 +288,20 @@ class Jukebox(SpotifySessionManager):
def __init__(self, *a, **kw):
SpotifySessionManager.__init__(self, *a, **kw)
self.audio = AudioSink()
if self.audio.async:
self.audio.backend = self
self.audio.setup()
self.ui = JukeboxUI(self)
self.ctr = None
self.playing = False
self._queue = []
self.playlist_manager = JukeboxPlaylistManager()
self.container_manager = JukeboxContainerManager()
self.track_playing = None
print "Logging in, please wait..."

def new_track_playing(self, track):
self.track_playing = track

def logged_in(self, session, error):
if error:
Expand All @@ -313,6 +322,7 @@ def logged_out(self, session):
def load_track(self, track):
if self.playing:
self.stop()
self.new_track_playing(track)
self.session.load(track)
print "Loading %s" % track.name()

Expand All @@ -323,8 +333,10 @@ def load(self, playlist, track):
pl = self.ctr[playlist]
elif playlist == len(self.ctr):
pl = self.starred
self.session.load(pl[track])
print "Loading %s from %s" % (pl[track].name(), pl.name())
spot_track = pl[track]
self.new_track_playing(spot_track)
self.session.load(spot_track)
print "Loading %s from %s" % (spot_track.name(), pl.name())

def load_playlist(self, playlist):
if self.playing:
Expand All @@ -335,6 +347,8 @@ def load_playlist(self, playlist):
pl = self.starred
print "Loading playlist %s" % pl.name()
if len(pl):
print "Loading %s from %s" % (pl[0].name(), pl.name())
self.new_track_playing(pl[0])
self.session.load(pl[0])
for i, track in enumerate(pl):
if i == 0:
Expand All @@ -345,6 +359,7 @@ def queue(self, playlist, track):
if self.playing:
self._queue.append((playlist, track))
else:
print 'Loading %s', track.name()
self.load(playlist, track)
self.play()

Expand Down Expand Up @@ -373,6 +388,9 @@ def next(self):
self.stop()

def end_of_track(self, sess):
if self.audio.async:
self.audio.emit_EOS()
return
print "track ends."
self.next()

Expand Down
1 change: 1 addition & 0 deletions spotify/audiosink/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class BaseAudioSink(object):

def __init__(self):
self._call_cache = {}
self.async = False

def music_delivery(self, session, frames, frame_size, num_frames,
sample_type, sample_rate, channels):
Expand Down
34 changes: 33 additions & 1 deletion spotify/audiosink/gstreamer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import threading
import gobject
import gst
import sys
Expand Down Expand Up @@ -35,12 +36,41 @@ def __init__(self):
}
caps = gst.caps_from_string(caps_string)
self._pipeline = gst.parse_launch(' ! '.join([
'appsrc name="application_src"',
'appsrc name="application_src" block=true',
'audioconvert',
'autoaudiosink',
]))
self._source = self._pipeline.get_by_name('application_src')
self._source.set_property('caps', caps)
self.async = True
self.backend = None
self.mainloop = None
self.mainloop_thread = threading.Thread(target=self.start_glib)
self.mainloop_thread.setDaemon(True)
self.mainloop_thread.start()


def start_glib(self):
self.mainloop = gobject.MainLoop()
self.mainloop.run()
print 'Mainloop running'

def setup(self):
self._setup_message_processor()

def _setup_message_processor(self):
bus = self._pipeline.get_bus()
bus.add_signal_watch()
bus.connect('message', self._on_message)

def _on_message(self, bus, message):
if message.type == gst.MESSAGE_EOS:
print 'track ended'
self._pipeline.set_state(gst.STATE_NULL)
self.backend.next()

def emit_EOS(self):
self._source.emit('end-of-stream')

def music_delivery(self, session, frames, frame_size, num_frames,
sample_type, sample_rate, channels):
Expand All @@ -58,9 +88,11 @@ def music_delivery(self, session, frames, frame_size, num_frames,
return num_frames

def start(self):
self._pipeline.set_state(gst.STATE_READY)
self._pipeline.set_state(gst.STATE_PLAYING)

def stop(self):
self._pipeline.set_state(gst.STATE_READY)
self._pipeline.set_state(gst.STATE_NULL)

def pause(self):
Expand Down

0 comments on commit b08d4e4

Please sign in to comment.