From: Kristoffer Grönlund Date: Tue, 29 Dec 2009 15:06:46 +0000 (+0100) Subject: Initial UI hacking X-Git-Url: http://git.maemo.org/git/?p=jamaendo;a=commitdiff_plain;h=ce920257cd6f037d25493b865c294b3c0edd2838 Initial UI hacking --- diff --git a/jamaui/__init__.py b/jamaui/__init__.py index e69de29..40fb3e8 100644 --- a/jamaui/__init__.py +++ b/jamaui/__init__.py @@ -0,0 +1,3 @@ +import logging + +logging.basicConfig(level=logging.DEBUG, format="%(name)-15s: [%(lineno)4d] %(levelname)-8s %(message)s") diff --git a/jamaui/dbus.py b/jamaui/dbus.py new file mode 100644 index 0000000..196e250 --- /dev/null +++ b/jamaui/dbus.py @@ -0,0 +1,5 @@ +# Media player controls +#dbus-send --print-reply --dest=com.nokia.mediaplayer /com/nokia/mediaplayer com.nokia.mediaplayer.mime_open string:"file:///$1" +#dbus-send --dest=com.nokia.osso_media_server /com/nokia/osso_media_server com.nokia.osso_media_server.music.pause +import dbus + diff --git a/jamaui/player.py b/jamaui/player.py new file mode 100644 index 0000000..07b89b4 --- /dev/null +++ b/jamaui/player.py @@ -0,0 +1,221 @@ +# Implements playback controls +# Gstreamer stuff mostly snibbed from Panucci +# +# This file is part of Panucci. +# Copyright (c) 2008-2009 The Panucci Audiobook and Podcast Player Project +# +# Panucci is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Panucci is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Panucci. If not, see . +# + +import logging +import pygst +pygst.require('0.10') +import gst +import util + +log = logging.getLogger(__name__) + + +class GStreamer(object): + """Wraps GStreamer""" + STATES = { gst.STATE_NULL : 'stopped', + gst.STATE_PAUSED : 'paused', + gst.STATE_PLAYING : 'playing' } + + def __init__(self): + self.time_format = gst.Format(gst.FORMAT_TIME) + self.player = None + self.filesrc = None + self.filesrc_property = None + self.volume_control = None + self.volume_multiplier = 1 + self.volume_property = None + self.eos_callback = lambda: self.stop() + + def setup(self, filetype, uri): + if None in (filetype, uri): + self.player = None + return False + + # On maemo use software decoding to workaround some bugs their gst: + # 1. Weird volume bugs in playbin when playing ogg or wma files + # 2. When seeking the DSPs sometimes lie about the real position info + if util.platform == 'maemo': + if not self._maemo_setup_hardware_player(filetype): + self._maemo_setup_software_player() + log.debug( 'Using software decoding (maemo)' ) + else: + log.debug( 'Using hardware decoding (maemo)' ) + else: + # This is for *ahem* "normal" versions of gstreamer + self._setup_playbin_player() + log.debug( 'Using playbin (non-maemo)' ) + + self._set_uri_to_be_played(uri) + + bus = self._player.get_bus() + bus.add_signal_watch() + bus.connect('message', self._on_message) + return True + + def get_state(self): + if self.player: + state = self._player.get_state()[1] + return self.STATES.get(state, 'none') + return 'none' + + def playing(self): + return self.get_state() == 'playing' + + def play(self): + if self.player: + self.player.set_state(gst.STATE_PLAYING) + + def pause(self): + if self.player: + self.player.set_state(gst.STATE_PAUSED) + + def play_pause_toggle(self): + self.pause() if self.playing() else self.play() + + def stop(self): + if self.player: + self.player.set_state(gst.STATE_NULL) + self.player = None + + def _maemo_setup_hardware_player( self, filetype ): + """ Setup a hardware player for mp3 or aac audio using + dspaacsink or dspmp3sink """ + + if filetype in [ 'mp3', 'aac', 'mp4', 'm4a' ]: + self.player = gst.element_factory_make('playbin', 'player') + self.filesrc = self.player + self.filesrc_property = 'uri' + self.volume_control = self.player + self.volume_multiplier = 10. + self.volume_property = 'volume' + return True + else: + return False + + def _maemo_setup_software_player( self ): + """ + Setup a software decoding player for maemo, this is the only choice + for decoding wma and ogg or if audio is to be piped to a bluetooth + headset (this is because the audio must first be decoded only to be + re-encoded using sbcenc. + """ + + self.player = gst.Pipeline('player') + src = gst.element_factory_make('gnomevfssrc', 'src') + decoder = gst.element_factory_make('decodebin', 'decoder') + convert = gst.element_factory_make('audioconvert', 'convert') + resample = gst.element_factory_make('audioresample', 'resample') + sink = gst.element_factory_make('dsppcmsink', 'sink') + + self.filesrc = src # pointer to the main source element + self.filesrc_property = 'location' + self.volume_control = sink + self.volume_multiplier = 1 + self.volume_property = 'fvolume' + + # Add the various elements to the player pipeline + self.player.add( src, decoder, convert, resample, sink ) + + # Link what can be linked now, the decoder->convert happens later + gst.element_link_many( src, decoder ) + gst.element_link_many( convert, resample, sink ) + + # We can't link the two halves of the pipeline until it comes + # time to start playing, this singal lets us know when it's time. + # This is because the output from decoder can't be determined until + # decoder knows what it's decoding. + decoder.connect('pad-added', + self._on_decoder_pad_added, + convert.get_pad('sink') ) + + def _setup_playbin_player( self ): + """ This is for situations where we have a normal (read: non-maemo) + version of gstreamer like on a regular linux distro. """ + self.player = gst.element_factory_make('playbin2', 'player') + self.filesrc = self.player + self.filesrc_property = 'uri' + self.volume_control = self.player + self.volume_multiplier = 1. + self.volume_property = 'volume' + + def _on_decoder_pad_added(self, decoder, src_pad, sink_pad): + # link the decoder's new "src_pad" to "sink_pad" + src_pad.link( sink_pad ) + + def _get_volume_level(self): + if self.volume_control is not None: + vol = self.volume_control.get_property( self.volume_property ) + return vol / float(self.volume_multiplier) + + def _set_volume_level(self, value): + assert 0 <= value <= 1 + + if self.volume_control is not None: + vol = value * self.volume_multiplier + self.volume_control.set_property( self.volume_property, vol ) + + def _set_uri_to_be_played(self, uri): + # Sets the right property depending on the platform of self.filesrc + if self.player is not None: + self.filesrc.set_property(self.filesrc_property, uri) + + def _on_message(self, bus, message): + t = message.type + + if t == gst.MESSAGE_EOS: + self.eos_callback() + + elif t == gst.MESSAGE_ERROR: + err, debug = message.parse_error() + log.critical( 'Error: %s %s', err, debug ) + self.stop() + + def set_eos_callback(self, cb): + self.eos_callback = cb + +class Playlist(object): + def __init__(self): + self.items = [] + + def add(self, item): + self.items.append(item) + +class Player(Playlist): + def __init__(self): + self.gstreamer = GStreamer() + self.gstreamer.set_eos_callback(self._on_eos) + + def play(self, item=None): + pass + + def pause(self): + pass + + def stop(self): + pass + + def next(self): + pass + + def prev(self): + pass + + def _on_eos(self): + pass diff --git a/jamaui/ui.py b/jamaui/ui.py new file mode 100644 index 0000000..e0bb84b --- /dev/null +++ b/jamaui/ui.py @@ -0,0 +1,28 @@ +import gtk +import gobject +import util + +log = logging.getLogger(__name__) + +try: + import hildon +except: + if util.platform == 'maemo': + log.critical( 'Using GTK widgets, install "python2.5-hildon" ' + 'for this to work properly.' ) + +class Jamaui(object): + def __init__(self): + self.app = None + self.window = None + if util.platform == 'maemo': + self.app = hildon.Program() + self.window = hildon.Window() + self.app.add_window(window) + else: + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + + def run(self): + self.window.show() + gtk.main() + diff --git a/jamaui/util.py b/jamaui/util.py new file mode 100644 index 0000000..6bff67f --- /dev/null +++ b/jamaui/util.py @@ -0,0 +1,21 @@ +import os + +def string_in_file( filepath, string ): + try: + f = open( filepath, 'r' ) + found = f.read().find( string ) != -1 + f.close() + except: + found = False + + return found + +def get_platform(): + if ( os.path.exists('/etc/osso_software_version') or + os.path.exists('/proc/component_version') or + string_in_file('/etc/issue', 'maemo') ): + return 'maemo' + else: + return 'linux' + +platform = get_platform() diff --git a/scripts/player b/scripts/player new file mode 100644 index 0000000..706819f --- /dev/null +++ b/scripts/player @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +# debugging hack - add . to path +import os, sys +local_module_dir = os.path.join(os.path.dirname(sys.argv[0]), '..') +if os.path.isdir(local_module_dir): + sys.path.append(local_module_dir) + +def main(): + from jamaui.ui import JamaUI + player = JamaUI() + player.run() + +if __name__=="__main__": + main() diff --git a/scripts/query b/scripts/query index ebf97d6..a8e94cf 100755 --- a/scripts/query +++ b/scripts/query @@ -1,6 +1,13 @@ #!/usr/bin/env python + +# debugging hack - add . to path +import os, sys +local_module_dir = os.path.join(os.path.dirname(sys.argv[0]), '..') +if os.path.isdir(local_module_dir): + sys.path.append(local_module_dir) + from jamaendo.api import LocalDB, Queries, refresh_dump -import sys, time +import time class Refresher(object): def __init__(self):