#!/usr/bin/env python from optparse import OptionParser import sys, urllib, os, time, threading import Timeparser class Error(Exception): pass class TryAgain(Error): pass blkSize = 1024 _knownStreams = { 'dlf': "http://www.dradio.de/streaming/dlf.m3u", 'dradio': "http://www.dradio.de/streaming/dlr.m3u", 'dlfogg': "http://www.dradio.de/streaming/dlf_mq_ogg.m3u", 'dradioogg': "http://www.dradio.de/streaming/dkultur_mq_ogg.m3u", } class Encoder(threading.Thread): def __init__(self, bitrate, destFName, dataSource): threading.Thread.__init__(self, name="Encoder") self.encStream = os.popen("/usr/bin/lame --quiet --mp3input " "-m m -h -b %d - %s > /tmp/lame.msgs 2>&1"%(bitrate, destFName), "w") self.dataSource = dataSource self.wakeupCondition = threading.Condition() def getWakeupCondition(self): return self.wakeupCondition def run(self): self.wakeupCondition.acquire() try: streamClosed = False while not streamClosed: self.wakeupCondition.wait() while not streamClosed: newData = self.dataSource.read() if newData is None: streamClosed = True elif newData==0: break else: self.encStream.write(newData) finally: self.wakeupCondition.release() def shutdownEncoder(self): """Has to be called from the main thread. Sigh. """ try: self.encStream.flush() return self.encStream.close() except IOError, msg: sys.stderr.write("Lame process close crashed: %s\n"%str(msg)) class EncoderFromOgg(Encoder): def __init__(self, bitrate, destFName, dataSource): threading.Thread.__init__(self, name="EncoderFromOgg") self.encStream = os.popen("oggdec -Q -R -b16 -o- - |" " sox -t raw -r32 -s -w -c 2 - -t raw -c 1 - |" ' lame --quiet -r -x -s32 -b %d -mm -h - "%s" ' " > /tmp/lame.msgs 2>&1"%(bitrate, destFName), "w") self.dataSource = dataSource self.wakeupCondition = threading.Condition() def getMp3Url(m3uUrl): m3uUrl = _knownStreams.get(m3uUrl, m3uUrl) return urllib.urlopen(m3uUrl).read().strip() class FiFo: def __init__(self): self.data = [] self.lock = threading.RLock() self.consumerCondition = None def read(self): self.lock.acquire() if self.data: readData = self.data.pop(0) else: readData = 0 self.lock.release() return readData def write(self, newData): self.lock.acquire() self.data.append(newData) self.lock.release() self.wakeupConsumer() def close(self): self.write(None) def wakeupConsumer(self): self.consumerCondition.acquire() if self.consumerCondition: self.consumerCondition.notify() self.consumerCondition.release() def setNotify(self, consumerCondition): self.consumerCondition = consumerCondition def doEncoding(opts, args): srcStream = urllib.urlopen(getMp3Url(args[1])) encodingClass = { "mp3": Encoder, "ogg": EncoderFromOgg, "x-mp3": Encoder, "mpeg": Encoder, }[srcStream.info().getsubtype()] fifo = FiFo() endTime = time.time()+timeToRec firstblock = srcStream.read(blkSize) # if not firstblock.startswith("\xff\xf3"): # # Gruesome hack to catch bad stream # if firstblock.startswith("