rendered paste bodyIndex: __init__.py
===================================================================
--- __init__.py (revision 78)
+++ __init__.py (working copy)
@@ -12,106 +12,20 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
-from xl import event
-from xl import providers
-from xl import xdg
+
+import os, signal, socket, subprocess
import pygst
pygst.require('0.10')
import gst
-import socket,os
-from threading import Thread
-import signal
-import time
-import array
-import struct
-import subprocess
+from xl import common, event, providers, xdg
-plugin_name = "projectM"
-pcm_socket_path = os.path.join(xdg.get_plugin_data_dir(), '.projectM-exaile')
-if not os.path.exists(pcm_socket_path):
- open(pcm_socket_path, 'a')
-projectM_bin = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'projectM-exaile')
+import logging
+logger = logging.getLogger(__name__)
-ENABLED=0
-AUDIO_SINK=None
-CONNECTED=0
-PCM_DATA_SIZE=1024
-PCM_DATA=None
-projectM_proc=None
+PROJECTM = None
+AUDIO_SINK = None
-def run_projectM(arg):
-
- global projectM_proc
- global projectM_bin
-
- cmd = [projectM_bin, arg]
- try:
- projectM_proc = subprocess.Popen(cmd,shell=False)
- if projectM_proc.pid:
- print "projectM-exaile: Spawned projectM Process ID: %s" % projectM_proc.pid
- else:
- print "projectM-exaile: Failed to spawn projectM Process"
- except:
- print "projectM-exaile: Failed to spawn projectM Process"
-
-def kill_projectM():
- global projectM_proc
- print "projectM-exaile: Trying to Kill projectM PID: %i" % projectM_proc.pid
- try:
- if(projectM_proc.pid):
- os.kill(projectM_proc.pid,signal.SIGKILL)
- print "projectM-exaile: Killed"
- except:
- return
-
-class pcm_sock_thread ( Thread ):
- def __init__ (self):
- Thread.__init__(self)
- def run ( self ):
- create_pcm_socket()
-
-def destroy_pcm_socket():
- global conn
- global CONNECTED
- conn.close()
- CONNECTED=0
-
-def create_pcm_socket():
- global conn
- global CONNECTED,PCM_DATA_SIZE,pcm_socket_path
- try:
- os.remove(pcm_socket_path)
- except OSError:
- pass
- #Bind Unix Socket for connection from projectM-exaile
- s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- s.bind(pcm_socket_path)
- print "projectM-exaile: Bound to %s" % pcm_socket_path
- s.listen(1)
- #Wait for projectM-exaile to connect
- print "projectM-exaile: Waiting for connection"
- conn = s.accept()[0]
- CONNECTED=1
- print "projectM-exaile: projectM Connected"
-
-def write_pcm_socket(data):
- global conn
- global CONNECTED
- global pcm_socket_path
- if(CONNECTED==0):
- return
- try:
- #Send Data
- print "START WRITE", len(data)
- conn.send(data)
- print "END WRITE"
- except:
- print "projectM-exaile: ProjectM Disconnected"
- kill_projectM()
- destroy_pcm_socket()
- return
-
def enable(exaile):
if (exaile.loading):
event.add_callback(_enable, 'exaile_loaded')
@@ -119,46 +33,102 @@
_enable(None, exaile, None)
def disable(exaile):
- global ENABLED
- ENABLED=0
- kill_projectM()
- destroy_pcm_socket()
- print('%s Disabled' % plugin_name)
+ teardown(exaile)
def _enable(eventname, exaile, nothing):
- global ENABLED
- global AUDIO_SINK, pcm_socket_path
- ENABLED = 1
- AUDIO_SINK = AudioSink(exaile)
+ global PROJECTM, AUDIO_SINK
+ PROJECTM = ProjectM()
+ AUDIO_SINK = AudioSink(PROJECTM)
providers.register('playback_audio_sink', AUDIO_SINK)
- sck_thrd = pcm_sock_thread()
- sck_thrd.start()
- run_projectM(pcm_socket_path)
- print('%s Enabled' % plugin_name)
+ PROJECTM.spawn()
def teardown(exaile):
- global ENABLED
- ENABLED=0
- print "projectM-exaile: Shutting down"
- kill_projectM()
- destroy_pcm_socket()
- print "projectM-exaile: Shutdown"
+ global PROJECTM, AUDIO_SINK
+ PROJECTM.kill()
+class ProjectM(object):
+ pcm_socket_path = os.path.join(xdg.get_plugin_data_dir(), 'projectM', 'projectM-exaile.sock')
+ projectm_binary = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'projectM-exaile')
+ def __init__(self):
+ self.connected = False
+ self.pid = None
+ self._sock = None
+ self._conn = None
+
+ def spawn(self):
+ self._make_socket()
+
+ command = [self.projectm_binary, self.pcm_socket_path]
+ try:
+ proc = subprocess.Popen(command)
+ if not proc.pid:
+ raise ValueError # TODO: get a better exception type here
+ except:
+ logger.error("Failed to spawn projectM process.")
+ common.log_exception()
+ else:
+ self.pid = proc.pid
+ logger.debug("Spawned projectM process, pid %s."%self.pid)
+
+ def kill(self):
+ if not self.pid:
+ return
+ try:
+ os.kill(self.pid, signal.SIGKILL)
+ logger.debug("projectM process killed.")
+ except:
+ logger.warning("Failed to kill projectM process, pid %s."%self.pid)
+ else:
+ self.pid = None
+ finally:
+ self._close_socket()
+
+ def send_pcm(self, data):
+ if not self.connected:
+ return
+ try:
+ self._conn.send(data)
+ except:
+ logger.warning("Disconnected from projectM")
+ self.kill()
+
+ @common.threaded
+ def _make_socket(self):
+ try:
+ os.makedirs(os.path.dirname(self.pcm_socket_path))
+ except OSError:
+ pass
+ try:
+ os.remove(self.pcm_socket_path)
+ except OSError:
+ pass
+ self._sock = sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.bind(self.pcm_socket_path)
+ sock.listen(1)
+ self._conn = sock.accept()[0]
+ self.connected = True
+
+ def _close_socket(self):
+ self._conn.close()
+ self._conn = None
+ self._sock = None
+ self.connected = False
+
+
+
class AudioSink(gst.Bin):
- def __init__(self, exaile):
+ def __init__(self, projectm):
gst.Bin.__init__(self)
self.name = 'projectm-audiosink'
- self.arr = None
- self.exaile = exaile
+ self.projectm = projectm
+
elems = []
self.convert = gst.element_factory_make("audioconvert")
elems.append(self.convert)
self.caps = gst.Caps("audio/x-raw-float, width=32, depth=32")
- self.filter = gst.element_factory_make("capsfilter")
- self.filter.props.caps = self.caps
- elems.append(self.filter)
self.sink = gst.element_factory_make("appsink", "projectm-audiosink")
self.sink.set_property('emit-signals', True)
+ self.sink.set_property('caps', self.caps)
self.sink.connect('new-preroll', self.new_preroll)
self.sink.connect('new-buffer', self.new_buffer)
elems.append(self.sink)
@@ -168,12 +138,8 @@
self.add_pad(gst.GhostPad('sink', self.sinkpad))
def new_preroll(self, sink):
- print "PREROLL"
buf = sink.emit('pull-preroll')
def new_buffer(self, sink):
- print "BUFFER"
- global PCM_DATA,CONNECTED
buf = sink.emit('pull-buffer')
- PCM_DATA = buf.data
- write_pcm_socket(PCM_DATA)
+ self.projectm.send_pcm(buf.data)