diff options
author | Paul W. Frields <stickster@gmail.com> | 2010-12-21 15:29:25 -0500 |
---|---|---|
committer | Paul W. Frields <stickster@gmail.com> | 2010-12-21 15:29:25 -0500 |
commit | e56837e1f657d327eec5f9d12ceb45da4c871dd0 (patch) | |
tree | b070e56fa71acd4c35e7b9c129b7cc1324506bc7 | |
parent | af5fafca22e10bfa61ea78242b47fc2c1fd4c0c9 (diff) | |
download | pulsecaster-e56837e1f657d327eec5f9d12ceb45da4c871dd0.tar.gz pulsecaster-e56837e1f657d327eec5f9d12ceb45da4c871dd0.tar.xz pulsecaster-e56837e1f657d327eec5f9d12ceb45da4c871dd0.zip |
More verbose tempfile debugging message
-rw-r--r-- | pulsecaster/ui.py | 3 | ||||
-rw-r--r-- | pulsecaster/ui.py.orig | 327 |
2 files changed, 329 insertions, 1 deletions
diff --git a/pulsecaster/ui.py b/pulsecaster/ui.py index 5cfe8e6..bc0f772 100644 --- a/pulsecaster/ui.py +++ b/pulsecaster/ui.py @@ -171,7 +171,7 @@ class PulseCasterUI: # Create temporary file (self.tempfd, self.temppath) = tempfile.mkstemp(prefix='%s-tmp.' % (NAME)) self.tempfile = os.fdopen(self.tempfd) - _debugPrint('%s (%s)' % (self.temppath, self.tempfd)) + _debugPrint('tempfile: %s (fd %s)' % (self.temppath, self.tempfd)) # Adjust UI self.user_vox.set_sensitive(False) self.subject_vox.set_sensitive(False) @@ -322,6 +322,7 @@ class PulseCasterUI: def _remove_tempfile(self, tempfile, temppath): tempfile.close() os.remove(temppath) + if __name__ == '__main__': pulseCaster = PulseCasterUI() gtk.main() diff --git a/pulsecaster/ui.py.orig b/pulsecaster/ui.py.orig new file mode 100644 index 0000000..5cfe8e6 --- /dev/null +++ b/pulsecaster/ui.py.orig @@ -0,0 +1,327 @@ +# Copyright (C) 2009, 2010 Paul W. Frields and others. +# -*- coding: utf-8 -*- +# +# 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 3 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, see <http://www.gnu.org/licenses/>. +# +# +# Author: Paul W. Frields <stickster@gmail.com> +# Jürgen Geuter <tante@the-gay-bar.com> + + +from config import * +import gconfig +from pulseaudio.PulseObj import PulseObj +from listener import * +from eggtrayicon import * +import gtk +import os +import sys +import tempfile +import gobject +import pygst +pygst.require('0.10') +import gst +from datetime import datetime + +import gettext +_ = lambda x: gettext.ldgettext(NAME, x) + +try: + _debug = os.environ['PULSECASTER_DEBUG'] +except: + _debug = False + +def _debugPrint(text): + if _debug: + print (text) + +class PulseCasterUI: + def __init__(self): + self.builder = gtk.Builder() + try: + self.builder.add_from_file(os.path.join(os.getcwd(),'data','pulsecaster.glade') +) + _debugPrint(_("loading glade file from current subdir")) + except: + try: + self.builder.add_from_file(os.path.join(sys.prefix,'share','pulsecaster','pulsecaster.glade')) + except Exception,e: + print(e) + raise SystemExit(_("Cannot load resources")) + + self.icontheme = gtk.icon_theme_get_default() + # Convenience for developers + self.icontheme.append_search_path(os.path.join(os.getcwd(),'data','icons','scalable')) + self.logo = self.icontheme.load_icon('pulsecaster', -1, + gtk.ICON_LOOKUP_FORCE_SVG) + gtk.window_set_default_icon(self.logo) + self.gconfig = gconfig.PulseCasterGconf() + + self.warning = self.builder.get_object('warning') + self.dismiss = self.builder.get_object('dismiss_warning') + self.swckbox = self.builder.get_object('skip_warn_checkbox') + self.swckbox.set_active(int(self.gconfig.skip_warn)) + self.dismiss.connect('clicked', self.hideWarn) + self.warning.connect('destroy', self.on_close) + self.warning.set_title(NAME) + + # Main dialog basics + self.main = self.builder.get_object('main_dialog') + self.main.set_title(NAME) + self.main_title = self.builder.get_object('main_title') + self.main_title.set_label('<big><big><big><b><i>' + + NAME + '</i></b></big></big></big>') + self.main.connect('delete_event', self.on_close) + self.about_button = self.builder.get_object('about_button') + self.about_button.connect('clicked', self.showAbout) + self.close = self.builder.get_object('close_button') + self.close.connect('clicked', self.on_close) + self.record = self.builder.get_object('record_button') + self.record_id = self.record.connect('clicked', self.on_record) + self.record.set_sensitive(True) + self.main_logo = self.builder.get_object('logo') + self.main_logo.set_from_icon_name('pulsecaster', gtk.ICON_SIZE_DIALOG) + self.main.set_icon_list(self.logo) + # About dialog basics + self.about = self.builder.get_object('about_dialog') + self.about.connect('delete_event', self.hideAbout) + self.about.connect('response', self.hideAbout) + self.about.set_name(NAME) + self.about.set_version(VERSION) + self.about.set_copyright(COPYRIGHT) + self.about.set_comments(DESCRIPTION) + self.about.set_license(LICENSE_TEXT) + self.about.set_website(URL) + self.about.set_website_label(URL) + self.authors = [AUTHOR + ' <' + AUTHOR_EMAIL + '>'] + for contrib in CONTRIBUTORS: + self.authors.append(contrib) + self.about.set_authors(self.authors) + self.about.set_program_name(NAME) + self.about.set_logo(self.icontheme.load_icon('pulsecaster', 96, gtk.ICON_LOOKUP_FORCE_SVG)) + + self.file_chooser = self.builder.get_object('file_chooser') + self.file_chooser_cancel_button = self.builder.get_object('file_chooser_cancel_button') + self.file_chooser_cancel_button.connect('clicked', self.hideFileChooser) + self.file_chooser_save_button = self.builder.get_object('file_chooser_save_button') + self.file_chooser_save_button.connect('clicked', self.updateFileSinkPath) + self.file_chooser.set_do_overwrite_confirmation(True) + self.file_chooser.connect('confirm-overwrite', self._confirm_overwrite) + + # Create PulseAudio backing + self.pa = PulseObj(clientName=NAME) + + # Create and populate combo boxes + self.table = self.builder.get_object('table1') + self.user_vox = gtk.combo_box_new_text() + self.subject_vox = gtk.combo_box_new_text() + self.table.attach(self.user_vox, 1, 2, 0, 1, + xoptions=gtk.EXPAND|gtk.FILL) + self.table.attach(self.subject_vox, 1, 2, 1, 2, + xoptions=gtk.EXPAND|gtk.FILL) + self.user_vox.connect('button-press-event', self.repop_sources) + self.subject_vox.connect('button-press-event', self.repop_sources) + + # Fill the combo boxes initially + self.repop_sources() + self.listener = PulseCasterListener(self) + + self.filesinkpath = '' + + self.trayicon = gtk.StatusIcon() + self.trayicon.set_visible(False) + self.trayicon.set_from_icon_name('pulsecaster') + + def repop_sources(self, *args): + self.sources = self.pa.pulse_source_list() + l = self.user_vox.get_model() + l.clear() + l = self.subject_vox.get_model() + l.clear() + self.uservoxes = [] + self.subjectvoxes = [] + for source in self.sources: + if source.monitor_of_sink_name == None: + self.uservoxes.append((source.name, source.description)) + self.user_vox.append_text(source.description) + else: + self.subjectvoxes.append((source.name, source.description)) + self.subject_vox.append_text(source.description) + self.user_vox.set_active(0) + self.subject_vox.set_active(0) + self.table.show_all() + + if self.gconfig.skip_warn is False: + self.warning.show() + else: + self.hideWarn() + + def on_record(self, *args): + # Create temporary file + (self.tempfd, self.temppath) = tempfile.mkstemp(prefix='%s-tmp.' % (NAME)) + self.tempfile = os.fdopen(self.tempfd) + _debugPrint('%s (%s)' % (self.temppath, self.tempfd)) + # Adjust UI + self.user_vox.set_sensitive(False) + self.subject_vox.set_sensitive(False) + self.close.set_sensitive(False) + + self.combiner = gst.Pipeline('PulseCasterCombinePipe') + self.lsource = gst.element_factory_make('pulsesrc', 'lsrc') + self.lsource.set_property('device', + self.uservoxes[self.user_vox.get_active()][0]) + self.rsource = gst.element_factory_make('pulsesrc', 'rsrc') + self.rsource.set_property('device', + self.subjectvoxes[self.subject_vox.get_active()][0]) + + self.adder = gst.element_factory_make('adder', 'mix') + self.encoder = gst.element_factory_make(self.gconfig.codec + 'enc', 'enc') + if self.gconfig.codec == 'vorbis': + self.muxer = gst.element_factory_make('oggmux', 'mux') + self.filesink = gst.element_factory_make('filesink', 'fsink') + self.filesink.set_property('location', self.temppath) + + self.combiner.add(self.lsource, + self.rsource, + self.adder, + self.encoder, + self.filesink) + if self.gconfig.codec == 'vorbis': + self.combiner.add(self.muxer) + gst.element_link_many(self.lsource, + self.adder, + self.encoder) + if self.gconfig.codec == 'vorbis': + self.encoder.link(self.muxer) + self.muxer.link(self.filesink) + else: # flac + self.encoder.link(self.filesink) + gst.element_link_many(self.rsource, self.adder) + + # FIXME: Dim elements other than the 'record' widget + self.record.set_label(gtk.STOCK_MEDIA_STOP) + self.record.disconnect(self.record_id) + self.stop_id = self.record.connect('clicked', self.on_stop) + self.record.show() + self.combiner.set_state(gst.STATE_PLAYING) + # Start timer + self.starttime = datetime.now() + self._update_time() + self.timeout = 1000 + gobject.timeout_add(self.timeout, self._update_time) + self.trayicon.set_visible(True) + + def on_stop(self, *args): + self.combiner.set_state(gst.STATE_NULL) + self.showFileChooser() + self.record.set_label(gtk.STOCK_MEDIA_RECORD) + self.record.disconnect(self.stop_id) + self.record_id = self.record.connect('clicked', self.on_record) + self.user_vox.set_sensitive(True) + self.subject_vox.set_sensitive(True) + self.close.set_sensitive(True) + self.record.show() + + def on_close(self, *args): + try: + self.pa.disconnect() + except: + pass + gtk.main_quit() + + def hideWarn(self, *args): + self.gconfig.change_warn(self.swckbox.get_active()) + self.warning.hide() + self.main.show() + + def showAbout(self, *args): + self.about.show() + + def hideAbout(self, *args): + self.about.hide() + + def showFileChooser(self, *args): + self.file_chooser.show() + + def hideFileChooser(self, *args): + if not self.filesinkpath: + confirm = gtk.MessageDialog(type=gtk.MESSAGE_WARNING, + buttons=gtk.BUTTONS_YES_NO, + message_format=_('Are you sure you want to cancel ' + + 'saving your work? If you choose "Yes" ' + + 'your audio recording will be erased ' + + 'permanently.')) + response = confirm.run() + confirm.destroy() + if response == gtk.RESPONSE_YES: + self._remove_tempfile(self.tempfile, self.temppath) + else: + return + self.file_chooser.hide() + + def updateFileSinkPath(self, *args): + self.filesinkpath = self.file_chooser.get_filename() + if not self.filesinkpath: + return + self.hideFileChooser() + if os.path.lexists(self.filesinkpath): + if not self._confirm_overwrite(): + self.showFileChooser() + return + # Copy the temporary file to its new home + self.permfile = open(self.filesinkpath, 'w') + self._copy_temp_to_perm(self.tempfile, self.permfile) + self.permfile.close() + self._remove_tempfile(self.tempfile, self.temppath) + self.record.set_sensitive(True) + + def _update_time(self, *args): + if self.combiner.get_state()[1] == gst.STATE_NULL: + self.trayicon.set_tooltip(None) + self.trayicon.set_visible(False) + return False + delta = datetime.now() - self.starttime + deltamin = delta.seconds // 60 + deltasec = delta.seconds - (deltamin * 60) + self.trayicon.set_tooltip('Recording: %d:%02d' % + (deltamin, deltasec)) + return True + + def _confirm_overwrite(self, *args): + confirm = gtk.MessageDialog(type=gtk.MESSAGE_QUESTION, + buttons=gtk.BUTTONS_YES_NO, + message_format=_('File exists. OK to overwrite?')) + response = confirm.run() + if response == gtk.RESPONSE_YES: + retval = True + else: + retval = False + confirm.destroy() + return retval + + def _copy_temp_to_perm(self, src, dest): + src.seek(0) + while True: + buf = src.read(1024*1024) + if buf: + dest.write(buf) + else: + break + + def _remove_tempfile(self, tempfile, temppath): + tempfile.close() + os.remove(temppath) +if __name__ == '__main__': + pulseCaster = PulseCasterUI() + gtk.main() |