Changeset - 1156d3531327
[Not reviewed]
default
0 0 6
drewp@bigasterisk.com - 15 years ago 2010-06-11 07:14:18
drewp@bigasterisk.com
new ascoltami2, using gstreamer
Ignore-this: 77e59ba6ec17b86343c93c24ac38aa44
6 files changed with 324 insertions and 0 deletions:
0 comments (0 inline, 0 general)
bin/ascoltami2
Show inline comments
 
new file 100644
 
#!/usr/bin/python
 
import web, thread, gobject, sys, optparse, logging
 
from rdflib import URIRef
 
sys.path.append(".")
 
from light9.ascoltami.player import Player
 
from light9.ascoltami.webapp import makeApp
 
from light9 import networking, showconfig
 

	
 
log = logging.getLogger()
 
logging.basicConfig()
 
gobject.threads_init()
 

	
 
parser = optparse.OptionParser()
 
parser.add_option('--show',
 
    help='show URI, like http://light9.bigasterisk.com/show/dance2008')
 
parser.add_option("-v", "--verbose", action="store_true",
 
                  help="logging.DEBUG")
 
graph = showconfig.getGraph()
 
(options, args) = parser.parse_args()
 

	
 

	
 
log.setLevel(logging.DEBUG if options.verbose else logging.INFO)
 

	
 
graph = showconfig.getGraph()
 
if not options.show:
 
    raise ValueError("missing --show http://...")
 
        
 
player = Player()
 

	
 
# the cherrypy server would wedge when vidref pounds on it; this
 
# one seems to run
 
thread.start_new(web.httpserver.runbasic,
 
                 (makeApp(player, graph, URIRef(options.show)).wsgifunc(),
 
                  ('0.0.0.0', networking.musicPort())))
 

	
 
mainloop = gobject.MainLoop()
 
mainloop.run()
light9/ascoltami/__init__.py
Show inline comments
 
new file 100644
light9/ascoltami/index.html
Show inline comments
 
new file 100644
 
<?xml version="1.0" encoding="iso-8859-1"?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
 
  <head>
 
    <title>ascoltami</title>
 
    <script type="text/javascript" src="static/jquery-1.4.2.min.js"></script>
 
      <script type="text/javascript" src="static/jquery-ui-1.8.2.custom/js/jquery-ui-1.8.2.custom.min.js"></script>
 
      <link rel="Stylesheet" type="text/css" href="static/jquery-ui-1.8.2.custom/css/smoothness/jquery-ui-1.8.2.custom.css"/>
 
      <link rel="Stylesheet" type="text/css" href="static/style.css"/>
 
  </head>
 
  <body>
 

	
 

	
 
    <div class="songs">
 
    </div>
 

	
 

	
 
    <div>Song: <span id="currentSong"/></div>
 
    <div>Time: <span id="currentTime"/></div>
 
    <div>Left: <span id="leftTime"/></div>
 
    <div>
 
      <div id="timeSlider"/>
 
    </div>
 

	
 
    <div class="commands">
 
      <button id="cmd-stop">Stop C-s</button>
 
      <button id="cmd-play">Play C-p</button>
 
      <button id="cmd-intro">Skip intro C-i</button>
 
      <button id="cmd-post">Skip to Post C-t</button>
 
      <button id="cmd-go">Go  space</button>
 
    </div>
 

	
 
bind keys, spacebar, css work
 

	
 
<script type="text/javascript">
 
// <![CDATA[
 
$(function () {
 

	
 
    var times = {
 
	intro: 4,
 
	post: 10
 
    };
 
    var currentDuration = 0;
 

	
 
    function updateCurrent() {
 
	$.getJSON("time", {}, function (data, status) {
 
	    $("#currentSong").text(data.song);
 
	    $("#currentTime").text(data.t);
 
	    $("#leftTime").text(data.duration - data.t);
 
	    currentDuration = data.duration;
 
	    $("#timeSlider").slider({value: data.t,
 
				     max: data.duration});
 

	
 
	});
 
    }
 

	
 
    $.getJSON("songs", {}, function (data, status) {
 
	$.each(data.songs, function (i, song) {
 
	    var button = $("<button>");
 
	    button.text(song.label);
 
	    button.data(song);
 
	    button.click(function () {
 
		$.post("song", button.data("path"), 
 
		       function (data, textStatus, xhr) {
 
		    
 
		       });
 
	    });
 
	    $(".songs").append($("<div>").append(button));
 
	});
 
    });
 

	
 
    var tojs = JSON.stringify;
 

	
 
    $("#cmd-stop").click(function () { $.post("time", tojs({pause: true})); });
 
    $("#cmd-play").click(function () { $.post("time", tojs({resume: true})); });
 
    $("#cmd-intro").click(function () { $.post("time", tojs({t: times.intro}))});
 
    $("#cmd-post").click(function () { 
 
	$.post("time", tojs({t: currentDuration - times.post}))
 
    });
 
    $("#cmd-go").click(function () {
 
	
 
    });
 

	
 
    var pendingSlide = false;
 
    $("#timeSlider").slider({
 
	step: .01,
 
	slide: function (event, ui) {
 
	    if (pendingSlide) {
 
		return;
 
	    }
 
	    pendingSlide = true;
 
	    $.post("time", '{"t" : '+ui.value+'}', 
 
		   function (data, status, xhr) {
 
		       pendingSlide = false;
 
		   });
 
	},
 
});
 
    
 
    function updateLoop() {
 
	updateCurrent();
 
	setTimeout(updateLoop, 300);
 
    }
 
    updateLoop();
 
});
 
// ]]>
 
</script>
 

	
 

	
 
  </body>
 
</html>
 
\ No newline at end of file
light9/ascoltami/player.py
Show inline comments
 
new file 100644
 
#!/usr/bin/python
 

	
 
"""
 
alternate to the mpd music player, for ascoltami
 
"""
 
from __future__ import division
 
import time, logging
 
import gst
 
log = logging.getLogger()
 

	
 
class Player(object):
 
    def __init__(self):
 

	
 
        self.playbin = self.pipeline = gst.parse_launch("playbin2 name=b")
 
        self.playStartTime = 0
 
        self._duration = 0
 
        self.pauseTime = 0
 

	
 
        self.setSong("file:///my/proj/light9/show/dance2010/music/07-jacksonmix-complete.wav")
 
        
 
        #self.pipeline = gst.parse_launch("filesrc name=file location=%s ! wavparse name=src ! audioconvert ! alsasink name=out" % songFile)
 

	
 
        def on_any(bus, msg):
 
            print bus, msg
 

	
 
        bus = self.pipeline.get_bus()
 
        bus.add_signal_watch()
 
        #bus.connect('message', on_any)
 

	
 
        def onStreamStatus(bus, message):
 
            (statusType, _elem) = message.parse_stream_status()
 
            if statusType == gst.STREAM_STATUS_TYPE_ENTER:
 
                self.setupAutostop()
 

	
 
            # we should run our own poller looking for crosses over the autostop threshold and pausing. When i used the pipeline.seek end-time, it caused lots of unwanted other pausing and was hard to turn off.
 
                
 
            #print message, bus
 
        bus.connect('message::stream-status', onStreamStatus)
 

	
 
    def seek(self, t):
 
        assert self.playbin.seek_simple(
 
            gst.FORMAT_TIME,
 
            gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE | gst.SEEK_FLAG_SKIP,
 
            t * gst.SECOND)
 
        self.playStartTime = time.time()
 

	
 
    def setSong(self, songUri):
 
        """
 
        uri like file:///my/proj/light9/show/dance2010/music/07.wav
 
        """
 
        log.info("set song to %r" % songUri)
 
        self.pipeline.set_state(gst.STATE_READY)
 
        self.pipeline.set_property("uri", songUri)
 
        self.pipeline.set_state(gst.STATE_PLAYING)
 
        self.playStartTime = time.time()
 

	
 

	
 

	
 
#        GST_MESSAGE_DURATION
 
        
 

	
 
    def currentTime(self):
 
        cur, _format = self.playbin.query_position(gst.FORMAT_TIME)
 
        return cur / gst.SECOND
 

	
 
    def duration(self):
 
        return self.playbin.query_duration(gst.FORMAT_TIME)[0] / gst.SECOND
 
        
 
    def pause(self):
 
        self.pipeline.set_state(gst.STATE_PAUSED)
 

	
 
    def resume(self):
 
        self.pipeline.set_state(gst.STATE_PLAYING)
 
        pos = self.currentTime()
 
        autoStop = self.duration() - 10
 
        if abs(pos - autoStop) < .01:
 
            self.releaseAutostop()
 

	
 

	
 
    def setupAutostop(self):
 
        return
 
        dur = self.duration()
 
        autoStop = (dur - 10.0)
 
        log.info("autostop will be at %s", autoStop)
 
        print "seek", self.pipeline.seek(1.0, gst.FORMAT_TIME,
 
                           gst.SEEK_FLAG_ACCURATE,
 
                           gst.SEEK_TYPE_NONE, 0,
 
                           gst.SEEK_TYPE_SET, autoStop * gst.SECOND)
 

	
 
    def releaseAutostop(self):
 
        log.info("release autostop")
 
        
 
        print "seek", self.pipeline.seek(
 
            1.0, gst.FORMAT_TIME,
 
            gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE | gst.SEEK_FLAG_SKIP,
 
            gst.SEEK_TYPE_NONE, 0,
 
            gst.SEEK_TYPE_END, 0)
 
        print self.pipeline.get_state()
 
        self.pipeline.set_state(gst.STATE_PLAYING)
 

	
 
                           
 
                           
 
        
light9/ascoltami/webapp.py
Show inline comments
 
new file 100644
 
import web, jsonlib
 
from twisted.python.util import sibpath
 
from light9.namespaces import L9, MUS
 

	
 
player = None
 
graph = None
 
show = None
 

	
 
class root(object):
 
    def GET(self):
 
        web.header("Content-type", "application/xhtml+xml")
 
        return open(sibpath(__file__, "index.html")).read()
 

	
 
class timeResource(object):
 
    def GET(self):
 
        return jsonlib.write({"song" : player.playbin.get_property("uri"),
 
                              "started" : player.playStartTime,
 
                              "duration" : player.duration(),
 
                              "t" : player.currentTime()})
 

	
 
    def POST(self):
 
        params = jsonlib.read(web.data(), use_float=True)
 
        if params.get('pause', False):
 
            player.pause()
 
        if params.get('resume', False):
 
            player.resume()
 
        if 't' in params:
 
            player.seek(params['t'])
 
        return "ok"
 

	
 
class songs(object):
 
    def GET(self):
 

	
 
        playList = graph.value(show, L9['playList'])
 
        if not playList:
 
            raise ValueError("%r has no l9:playList" % show)
 
        songs = list(graph.items(playList))
 

	
 
        
 
        web.header("Content-type", "application/json")
 
        return jsonlib.write({"songs" : [
 
            {"uri" : s,
 
             "path" : graph.value(s, L9['showPath']),
 
             "label" : graph.label(s)} for s in songs]})
 

	
 
class songResource(object):
 
    def POST(self):
 
        """post a uri of song to switch to (and start playing)"""
 
        player.setSong(web.data())
 
        return "ok"
 

	
 
def makeApp(thePlayer, theGraph, theShow):
 
    global player, graph, show
 
    player, graph, show = thePlayer, theGraph, theShow
 

	
 
    urls = ("/", "root",
 
            "/time", "timeResource",
 
            "/song", "songResource",
 
            "/songs", "songs",
 
            "/api/position", "timeResource", # old
 
            )
 

	
 
    app = web.application(urls, globals(), autoreload=False)
 
    return app
static/style.css
Show inline comments
 
new file 100644
 
.songs button {
 
  display: inline-block;
 
  width: 300px;
 
height: 30px;
 
  text-align: left;
 
}
 
.songs button:hover {
 
  background: yellow;
 
}
 
\ No newline at end of file
0 comments (0 inline, 0 general)