From: kinta Date: Fri, 12 Dec 2008 12:34:00 +0000 (+0000) Subject: Added initial code X-Git-Url: http://git.maemo.org/git/?p=qice;a=commitdiff_plain;h=HEAD Added initial code git-svn-id: file:///svnroot/qice/trunk@3 e9839b59-6115-4633-8823-be5c8faaf4ff --- 439d49cf04c8b67b3202581783a94f1cfda7fc51 diff --git a/READMEPKG b/READMEPKG new file mode 100644 index 0000000..0677ae2 --- /dev/null +++ b/READMEPKG @@ -0,0 +1 @@ +you do "python setup.py bdist_debian" and it creates the .deb file in the "dist" subdirectory. That's it! You're done! diff --git a/bdist_debian.py b/bdist_debian.py new file mode 100644 index 0000000..16fb890 --- /dev/null +++ b/bdist_debian.py @@ -0,0 +1,149 @@ +# bdist_debian.py +# +# Add 'bdist_debian' Debian binary package distribution support to 'distutils'. +# +# This command builds '.deb' packages and supports the "Maemo" extensions for the Nokia N770/N800/N810. +# +# Written by: Gene Cash 16-NOV-2007 + +import os, base64 +from distutils.core import Command, Distribution +from distutils.dir_util import remove_tree +from distutils.util import byte_compile + +# make these legal keywords for setup() +Distribution.icon=None +Distribution.section=None +Distribution.depends=None + +class ControlFile(object): + def __init__(self, Installed_Size=0, Long_Description='', Description='', Icon='', **kwargs): + self.options=kwargs + self.description=Description + self.long_description=Long_Description + self.icon=Icon + self.installed_size=Installed_Size + + def getContent(self): + content=['%s: %s' % (k, v) for k,v in self.options.iteritems()] + + content.append('Installed-Size: %d' % self.installed_size) + if self.description != 'UNKNOWN': + content.append('Description: %s' % self.description.strip()) + if self.long_description != 'UNKNOWN': + self.long_description=self.long_description.replace('\n', '\n ') + content.append(' '+self.long_description.strip()) + + if self.icon: + # generate Base64-encoded icon + s=file(self.icon, 'rb').read() + x=base64.b64encode(s) + # wrap width MUST be 76 characters to make application manager happy after install + lw=76 + # trailing blank is important, and the XB- is NOT legal + content.append('XB-Maemo-Icon-26: ') + for i in range(0, len(x), lw): + content.append(' '+x[i:i+lw]) + + # must have two returns + return '\n'.join(content)+'\n\n' + +class bdist_debian(Command): + description='' + # List of option tuples: long name, short name (None if no short name), and help string. + user_options=[('name=', None, 'Package name'), + ('section=', None, 'Section (Only "user/*" will display in App Mgr usually)'), + ('priority=', None, 'Priority'), + ('depends=', None, 'Other Debian package dependencies (comma separated)'), + ('icon=', None, 'Name of icon file to be displayed by App Mgr')] + + def initialize_options(self): + self.section=None + self.priority=None + self.depends=None + self.icon=None + + def finalize_options(self): + if self.section is None: + self.section='user/other' + + if self.priority is None: + self.priority='optional' + + self.maintainer='%s <%s>' % (self.distribution.get_maintainer(), self.distribution.get_maintainer_email()) + + if self.depends is None: + self.depends='python2.5' + + self.name=self.distribution.get_name() + self.description=self.distribution.get_description() + self.long_description=self.distribution.get_long_description() + self.version=self.distribution.get_version() + + # process new keywords + if self.distribution.icon != None: + self.icon=self.distribution.icon + if self.distribution.section != None: + self.section=self.distribution.section + if self.distribution.depends != None: + self.depends=self.distribution.depends + + def run(self): + build_dir=os.path.join(self.get_finalized_command('build').build_base, 'nokia') + dist_dir='dist' + binary_fn='debian-binary' + control_fn='control' + data_fn='data' + tgz_ext='.tar.gz' + + # build everything locally + self.run_command('build') + install=self.reinitialize_command('install', reinit_subcommands=1) + install.root=build_dir + self.run_command('install') + + # find out how much space it takes + installed_size=0 + for root, dirs, files in os.walk('build'): + installed_size+=sum(os.path.getsize(os.path.join(root, name)) for name in files) + + # make compressed tarball + self.make_archive(os.path.join(dist_dir, data_fn), 'gztar', root_dir=build_dir) + + # remove all the stuff we just built + remove_tree(build_dir) + + # create control file contents + ctl=ControlFile(Package=self.name, Version=self.version, Section=self.section, Priority=self.priority, + Installed_Size=installed_size/1024+1, Architecture='all', Maintainer=self.maintainer, + Depends=self.depends, Description=self.description, Long_Description=self.long_description, + Icon=self.icon).getContent() + + # grab scripts + scripts={} + for fn in ('postinst', 'preinst', 'postrm', 'prerm', 'config'): + if os.path.exists(fn): + scripts[fn]=file(fn, 'rb').read() + + # now to create the deb package + os.chdir(dist_dir) + + # write control file + file(control_fn, 'wb').write(ctl) + + # write any scripts and chmod a+rx them + files=[control_fn] + for fn in scripts: + files.append(fn) + file(fn, 'wb').write(scripts[fn]) + os.chmod(fn, 0555) + + # make "control" compressed tarball with control file and any scripts + self.spawn(['tar', '-czf', control_fn+tgz_ext]+files) + + # make debian-binary file + file(binary_fn, 'wb').write('2.0\n') + + # make final archive + package_filename='%s_%s_all.deb' % (self.name, self.version) + self.spawn(['ar', '-cr', package_filename, binary_fn, control_fn+tgz_ext, data_fn+tgz_ext]) diff --git a/build/scripts-2.5/qice.py b/build/scripts-2.5/qice.py new file mode 100755 index 0000000..0e05fff --- /dev/null +++ b/build/scripts-2.5/qice.py @@ -0,0 +1,256 @@ +#!/usr/bin/python +# qice.py +# Copyright 2008 kinta +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# deps= libshout shout2send aumix osso-xterm mplayer +import sys +from PyQt4 import QtCore +from PyQt4 import QtGui +import os +import subprocess +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import ConfigParser +# +import gobject +# + +stream=["host", "port", "mountpoint", "user", "pw"] +sndarch="dsppcmsrc"#"alsasrc" +sndarchsink="dsppcmsink"#"alsasink" +term="osso-xterm"#"xterm" +home_directory = os.popen("echo $HOME").readline()[0:-1] +config_directory = home_directory + '/.qice' +if os.path.isdir(config_directory): + pass +else: + os.popen("mkdir "+config_directory) +config_file = config_directory + '/server.cfg' +config = ConfigParser.ConfigParser() +config.read(config_file) +if config.has_section("server"): + print("configuracio trobada") +else: + print("no te lopcio per tant escribim") + config.add_section("server") + for index,item in enumerate(stream): + config.set("server",item,item) + targetwrite=file(config_file,'w') + config.write(targetwrite) + targetwrite.close() + + +class MainWindow(QtGui.QMainWindow): + def __init__(self, * args): + apply(QtGui.QMainWindow.__init__, (self, ) + args) + gobject.threads_init() + self.vlayout = QtGui.QGridLayout() + + self.fileMenu = QtGui.QMenu(self.tr("&File"), self) + self.quitAction = self.fileMenu.addAction(self.tr("E&xit")) + self.editServer = self.fileMenu.addAction(self.tr("Edit c&onnection")) + self.mixer = self.fileMenu.addAction(self.tr("&Mixer")) + self.menuBar().addMenu(self.fileMenu) + + self.stream = QtGui.QPushButton("Stream", self) + self.dump = QtGui.QPushButton("dump", self) + self.monitor = QtGui.QPushButton("Monitor", self) + self.record = QtGui.QPushButton("Record", self) + self.label = QtGui.QTextEdit("",self) + + self.label.setReadOnly(True) + self.label.setGeometry(10, 100, 361, 141) + self.stream.setCheckable(1) + self.dump.setCheckable(1) + self.monitor.setCheckable(1) + self.record.setCheckable(1) + + self.dump.setEnabled(False) + + self.vlayout.addWidget(self.stream,0,0,1,1) + self.vlayout.addWidget(self.dump,1,0,1,1) + #self.vlayout.addSpacing(20) + self.vlayout.addWidget(self.monitor,0,1,1,1) + self.vlayout.addWidget(self.record,0,2,1,1) + self.vlayout.addWidget(self.label,2,0,1,3) + + self.connect(self.stream, QtCore.SIGNAL("clicked()"), self.streamcon) + self.connect(self.dump, QtCore.SIGNAL("clicked()"), self.dumpstream) + self.connect(self.monitor, QtCore.SIGNAL("clicked()"), self.monstr) + self.connect(self.record, QtCore.SIGNAL("clicked()"), self.recordstr) + self.connect(self.quitAction, QtCore.SIGNAL("triggered()"), self.quito) + self.connect(self.editServer, QtCore.SIGNAL("triggered()"), self.setserver) + self.connect(self.mixer, QtCore.SIGNAL("triggered()"), self.aumixer) + central = QtGui.QWidget(self) + central.setLayout(self.vlayout) + self.setCentralWidget(central) + + def streamcon(self): + if self.stream.isChecked(): + try: + self.label.append("connecting") + self.server=config.get("server","host") + self.port=config.get("server","port") + self.mount=config.get("server","mountpoint") + self.pw=config.get("server","pw") + self.user=config.get("server","user") + self.audio_pipeline = gst.parse_launch(sndarch+" ! audioconvert ! vorbisenc name=\"enc\" quality=0.10 ! queue ! oggmux name=mux ! queue ! shout2send ip="+self.server+" port="+self.port+" password="+self.pw+" mount=/"+self.mount) + self.audio_pipeline.get_bus().add_watch(self.connectEventos) + self.audio_pipeline.set_state(gst.STATE_PLAYING) + self.label.append("connected") + self.record.setEnabled(False) + self.monitor.setEnabled(False) + self.dump.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.stream.setChecked(0) + return -1 + else: + self.label.append("disconnecting") + try: + self.dump.setChecked(False) + self.dumpstream() + self.audio_pipeline.set_state(gst.STATE_NULL) + self.label.append("disconnected") + self.record.setEnabled(True) + self.monitor.setEnabled(True) + self.dump.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + + def monstr(self): + if self.monitor.isChecked(): + try: + self.label.append("monitoring") + self.mon_pipeline = gst.parse_launch(sndarch+" !"+sndarchsink) + self.mon_pipeline.get_bus().add_watch(self.eventos) + self.mon_pipeline.set_state(gst.STATE_PLAYING) + self.record.setEnabled(False) + self.stream.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.monitor.setChecked(0) + return -1 + else: + self.label.append("disabling monitor") + try: + self.mon_pipeline.set_state(gst.STATE_NULL) + self.label.append("unmonitoring") + self.record.setEnabled(True) + self.stream.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + def recordstr(self): + if self.record.isChecked(): + filename = QtGui.QFileDialog.getSaveFileName(self, 'Where?',home_directory) + filename = str(filename) + try: + self.label.append("recording") + self.rec_pipeline = gst.parse_launch(sndarch+" ! audioconvert ! vorbisenc name=\"enc\" quality=0.10 ! queue ! oggmux name=mux ! queue ! filesink location="+filename) + self.rec_pipeline.get_bus().add_watch(self.eventos) + self.rec_pipeline.set_state(gst.STATE_PLAYING) + self.stream.setEnabled(False) + self.monitor.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.record.setChecked(0) + return -1 + else: + self.label.append("stop recording") + try: + self.rec_pipeline.set_state(gst.STATE_NULL) + self.label.append("stoped") + self.stream.setEnabled(True) + self.monitor.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + + + def alert(self, msg): + QtGui.QMessageBox.critical(self, 'CRITICAL', msg, QtGui.QMessageBox.Ok) + def pregunta(self, msg): + pregunta=QtGui.QMessageBox.question(self, 'ATENCIO', msg, QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + #resposta=pregunta.exec() + if pregunta == 1024: + return "OK" + else : + return "Cancel" + def quito(self,**kwargs): + self.close() + def setserver(self,**kwargs): + os.popen2(term+" -e \"nano ~/.qice/server.cfg\"") + config.read(config_file) + def aumixer(self,**kwargs): + os.popen2("aumix") + def eventos(self, bus, msg): + #DEBUG = print(str(msg)+" "+str(msg.type)) + t = msg.type + if t == gst.MESSAGE_UNKNOWN: + e, d = msg.parse_error() + self.label.append("CONNECT ERROR: "+e) + if t == gst.MESSAGE_ERROR: + e, d = msg.parse_error() + self.label.append("ERROR: "+e) + return True + def connectEventos(self, bus, msg): + #DEBUG = print(str(msg)+" "+str(msg.type)) + t = msg.type + if t == gst.MESSAGE_UNKNOWN: + e, d = msg.parse_error() + self.label.append("CONNECT ERROR: "+e) + if t == gst.MESSAGE_ERROR: + e, d = msg.parse_error() + self.label.append("ERROR: "+e) + self.stream.setChecked(False) + self.streamcon() + return True + def dumpstream(self): + if self.dump.isChecked(): + self.server=config.get("server","host") + self.port=config.get("server","port") + self.mount=config.get("server","mountpoint") + self.pw=config.get("server","pw") + self.user=config.get("server","user") + filename = QtGui.QFileDialog.getSaveFileName(self, 'Where?',home_directory) + self.filename = str(filename) + self.label.append("dumping") + mplayer=os.popen2( term+" -e \"mplayer http://"+self.server+":"+self.port+"/"+self.mount+" -dumpstream -dumpfile "+self.filename+" && sleep 2\"")[1].readline() + + else: + pidofmp=os.popen2("pidof mplayer")[1].readline() + if pidofmp!="": + os.popen2("kill -15 `pidof mplayer`") + + +def main(args): + app=QtGui.QApplication(args) + win=MainWindow() + win.show() + win.setWindowTitle("Qice") + app.connect(app, QtCore.SIGNAL("lastWindowClosed()") + , app + , QtCore.SLOT("quit()") + ) + app.exec_() + +if __name__=="__main__": + main(sys.argv) diff --git a/copyright b/copyright new file mode 100644 index 0000000..e2fb8a3 --- /dev/null +++ b/copyright @@ -0,0 +1,14 @@ +qice.py + +Copyright: Aleix Quintana Alsius + +2008-12-07 + +The entire code qice.py may be distributed under the terms of the GNU General +Public License (GPL), which appears immediately below. Alternatively, all +of the source code as any code derived from that code may instead be +distributed under the GNU Lesser General Public License (LGPL), at the +choice of the distributor. The complete text of the LGPL appears at the +bottom of this file. + +See /usr/share/common-licenses/(GPL|LGPL) \ No newline at end of file diff --git a/dist/control b/dist/control new file mode 100644 index 0000000..ae9e486 --- /dev/null +++ b/dist/control @@ -0,0 +1,44 @@ +Maintainer: UNKNOWN +Package: qice-maemo +Section: user/extras +Priority: optional +Depends: libshout3, aumix-gtk, python2.5-qt4-common, python2.5-gstreamer, mplayer +Version: 1.0.0 +Architecture: all +Installed-Size: 271 +Description: Client to Icecast, and ogg recorder + Client to Icecast, using the microphone to stream directly to an icecast server. You can also use it to record in ogg +XB-Maemo-Icon-26: + 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 + diff --git a/dist/control.tar.gz b/dist/control.tar.gz new file mode 100644 index 0000000..84d2d27 Binary files /dev/null and b/dist/control.tar.gz differ diff --git a/dist/data.tar.gz b/dist/data.tar.gz new file mode 100644 index 0000000..794ad8f Binary files /dev/null and b/dist/data.tar.gz differ diff --git a/dist/debian-binary b/dist/debian-binary new file mode 100644 index 0000000..cd5ac03 --- /dev/null +++ b/dist/debian-binary @@ -0,0 +1 @@ +2.0 diff --git a/dist/qice-maemo_1.0.0_all.deb b/dist/qice-maemo_1.0.0_all.deb new file mode 100644 index 0000000..c024bbf Binary files /dev/null and b/dist/qice-maemo_1.0.0_all.deb differ diff --git a/qice.desktop b/qice.desktop new file mode 100644 index 0000000..1a4ae49 --- /dev/null +++ b/qice.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Version=1.0.0 +Encoding=UTF-8 +Name=qice-maemo +Exec=/usr/bin/qice.py +Icon=qice +Type=Application diff --git a/qice.png b/qice.png new file mode 100644 index 0000000..d0ea312 Binary files /dev/null and b/qice.png differ diff --git a/qice.py b/qice.py new file mode 100644 index 0000000..bef012e --- /dev/null +++ b/qice.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# qice.py +# Copyright 2008 kinta +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# deps= libshout shout2send aumix osso-xterm mplayer +import sys +from PyQt4 import QtCore +from PyQt4 import QtGui +import os +import subprocess +import pygst +pygst.require('0.10') +import gst +import gst.interfaces +import ConfigParser +# +import gobject +# + +stream=["host", "port", "mountpoint", "user", "pw"] +sndarch="dsppcmsrc"#"alsasrc" +sndarchsink="dsppcmsink"#"alsasink" +term="osso-xterm"#"xterm" +home_directory = os.popen("echo $HOME").readline()[0:-1] +config_directory = home_directory + '/.qice' +if os.path.isdir(config_directory): + pass +else: + os.popen("mkdir "+config_directory) +config_file = config_directory + '/server.cfg' +config = ConfigParser.ConfigParser() +config.read(config_file) +if config.has_section("server"): + print("configuracio trobada") +else: + print("no te lopcio per tant escribim") + config.add_section("server") + for index,item in enumerate(stream): + config.set("server",item,item) + targetwrite=file(config_file,'w') + config.write(targetwrite) + targetwrite.close() + + +class MainWindow(QtGui.QMainWindow): + def __init__(self, * args): + apply(QtGui.QMainWindow.__init__, (self, ) + args) + gobject.threads_init() + self.vlayout = QtGui.QGridLayout() + + self.fileMenu = QtGui.QMenu(self.tr("&File"), self) + self.quitAction = self.fileMenu.addAction(self.tr("E&xit")) + self.editServer = self.fileMenu.addAction(self.tr("Edit c&onnection")) + self.mixer = self.fileMenu.addAction(self.tr("&Mixer")) + self.menuBar().addMenu(self.fileMenu) + + self.stream = QtGui.QPushButton("Stream", self) + self.dump = QtGui.QPushButton("dump", self) + self.monitor = QtGui.QPushButton("Monitor", self) + self.record = QtGui.QPushButton("Record", self) + self.label = QtGui.QTextEdit("",self) + + self.label.setReadOnly(True) + self.label.setGeometry(10, 100, 361, 141) + self.stream.setCheckable(1) + self.dump.setCheckable(1) + self.monitor.setCheckable(1) + self.record.setCheckable(1) + + self.dump.setEnabled(False) + + self.vlayout.addWidget(self.stream,0,0,1,1) + self.vlayout.addWidget(self.dump,1,0,1,1) + #self.vlayout.addSpacing(20) + self.vlayout.addWidget(self.monitor,0,1,1,1) + self.vlayout.addWidget(self.record,0,2,1,1) + self.vlayout.addWidget(self.label,2,0,1,3) + + self.connect(self.stream, QtCore.SIGNAL("clicked()"), self.streamcon) + self.connect(self.dump, QtCore.SIGNAL("clicked()"), self.dumpstream) + self.connect(self.monitor, QtCore.SIGNAL("clicked()"), self.monstr) + self.connect(self.record, QtCore.SIGNAL("clicked()"), self.recordstr) + self.connect(self.quitAction, QtCore.SIGNAL("triggered()"), self.quito) + self.connect(self.editServer, QtCore.SIGNAL("triggered()"), self.setserver) + self.connect(self.mixer, QtCore.SIGNAL("triggered()"), self.aumixer) + central = QtGui.QWidget(self) + central.setLayout(self.vlayout) + self.setCentralWidget(central) + + def streamcon(self): + if self.stream.isChecked(): + try: + self.label.append("connecting") + self.server=config.get("server","host") + self.port=config.get("server","port") + self.mount=config.get("server","mountpoint") + self.pw=config.get("server","pw") + self.user=config.get("server","user") + self.audio_pipeline = gst.parse_launch(sndarch+" ! audioconvert ! vorbisenc name=\"enc\" quality=0.10 ! queue ! oggmux name=mux ! queue ! shout2send ip="+self.server+" port="+self.port+" password="+self.pw+" mount=/"+self.mount) + self.audio_pipeline.get_bus().add_watch(self.connectEventos) + self.audio_pipeline.set_state(gst.STATE_PLAYING) + self.label.append("connected") + self.record.setEnabled(False) + self.monitor.setEnabled(False) + self.dump.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.stream.setChecked(0) + return -1 + else: + self.label.append("disconnecting") + try: + self.dump.setChecked(False) + self.dumpstream() + self.audio_pipeline.set_state(gst.STATE_NULL) + self.label.append("disconnected") + self.record.setEnabled(True) + self.monitor.setEnabled(True) + self.dump.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + + def monstr(self): + if self.monitor.isChecked(): + try: + self.label.append("monitoring") + self.mon_pipeline = gst.parse_launch(sndarch+" !"+sndarchsink) + self.mon_pipeline.get_bus().add_watch(self.eventos) + self.mon_pipeline.set_state(gst.STATE_PLAYING) + self.record.setEnabled(False) + self.stream.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.monitor.setChecked(0) + return -1 + else: + self.label.append("disabling monitor") + try: + self.mon_pipeline.set_state(gst.STATE_NULL) + self.label.append("unmonitoring") + self.record.setEnabled(True) + self.stream.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + def recordstr(self): + if self.record.isChecked(): + filename = QtGui.QFileDialog.getSaveFileName(self, 'Where?',home_directory) + filename = str(filename) + try: + self.label.append("recording") + self.rec_pipeline = gst.parse_launch(sndarch+" ! audioconvert ! vorbisenc name=\"enc\" quality=0.10 ! queue ! oggmux name=mux ! queue ! filesink location="+filename) + self.rec_pipeline.get_bus().add_watch(self.eventos) + self.rec_pipeline.set_state(gst.STATE_PLAYING) + self.stream.setEnabled(False) + self.monitor.setEnabled(False) + except gobject.GError, e: + self.label.append("No es posible crear la tuberia, " + str(e)) + self.record.setChecked(0) + return -1 + else: + self.label.append("stop recording") + try: + self.rec_pipeline.set_state(gst.STATE_NULL) + self.label.append("stoped") + self.stream.setEnabled(True) + self.monitor.setEnabled(True) + except gobject.GError, e: + self.label.append("No es posible canviar a estat nul la tuberia, " + str(e)) + return -1 + + + def alert(self, msg): + QtGui.QMessageBox.critical(self, 'CRITICAL', msg, QtGui.QMessageBox.Ok) + def pregunta(self, msg): + pregunta=QtGui.QMessageBox.question(self, 'ATENCIO', msg, QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) + #resposta=pregunta.exec() + if pregunta == 1024: + return "OK" + else : + return "Cancel" + def quito(self,**kwargs): + self.close() + def setserver(self,**kwargs): + os.popen2(term+" -e \"nano ~/.qice/server.cfg\"") + config.read(config_file) + def aumixer(self,**kwargs): + os.popen2("aumix") + def eventos(self, bus, msg): + #DEBUG = print(str(msg)+" "+str(msg.type)) + t = msg.type + if t == gst.MESSAGE_UNKNOWN: + e, d = msg.parse_error() + self.label.append("CONNECT ERROR: "+e) + if t == gst.MESSAGE_ERROR: + e, d = msg.parse_error() + self.label.append("ERROR: "+e) + return True + def connectEventos(self, bus, msg): + #DEBUG = print(str(msg)+" "+str(msg.type)) + t = msg.type + if t == gst.MESSAGE_UNKNOWN: + e, d = msg.parse_error() + self.label.append("CONNECT ERROR: "+e) + if t == gst.MESSAGE_ERROR: + e, d = msg.parse_error() + self.label.append("ERROR: "+e) + self.stream.setChecked(False) + self.streamcon() + return True + def dumpstream(self): + if self.dump.isChecked(): + self.server=config.get("server","host") + self.port=config.get("server","port") + self.mount=config.get("server","mountpoint") + self.pw=config.get("server","pw") + self.user=config.get("server","user") + filename = QtGui.QFileDialog.getSaveFileName(self, 'Where?',home_directory) + self.filename = str(filename) + self.label.append("dumping") + mplayer=os.popen2( term+" -e \"mplayer http://"+self.server+":"+self.port+"/"+self.mount+" -dumpstream -dumpfile "+self.filename+" && sleep 2\"")[1].readline() + + else: + pidofmp=os.popen2("pidof mplayer")[1].readline() + if pidofmp!="": + os.popen2("kill -15 `pidof mplayer`") + + +def main(args): + app=QtGui.QApplication(args) + win=MainWindow() + win.show() + win.setWindowTitle("Qice") + app.connect(app, QtCore.SIGNAL("lastWindowClosed()") + , app + , QtCore.SLOT("quit()") + ) + app.exec_() + +if __name__=="__main__": + main(sys.argv) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..39c718d --- /dev/null +++ b/setup.py @@ -0,0 +1,21 @@ +import bdist_debian +from distutils.core import setup + +setup(name='qice-maemo', + version='1.0.0', + scripts=['qice.py'], + section='user/extras', + mantainer='Aleix Quintana', + mantainer_email='kinta@communia.org', + depends='libshout3, aumix-gtk, python2.5-qt4-common, python2.5-gstreamer, mplayer', + description='Client to Icecast, and ogg recorder', + long_description='Client to Icecast, using the microphone to stream directly to an icecast server. You can also use it to record in ogg', + data_files = [ + ('share/pixmaps', ['qice.png']), + ('share/applications/hildon', ['qice.desktop']), + ('share/doc/qice-maemo', ['copyright']), + ('lib/gstreamer-0.10', ['libgstshout2.so']), + ('lib/gstreamer-0.10', ['libgstvorbis.so']), + ], + icon='qice.png', + cmdclass={'bdist_debian': bdist_debian.bdist_debian})