Ticket #2794: crashed grecord-10.py

File crashed grecord-10.py, 24.7 KB (added by tonyforster, 13 years ago)
Line 
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE abiword PUBLIC "-//ABISOURCE//DTD AWML 1.0 Strict//EN" "http://www.abisource.com/awml.dtd">
3<abiword template="false" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" xid-max="229" xmlns:dc="http://purl.org/dc/elements/1.1/" fileformat="1.1" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:awml="http://www.abisource.com/awml.dtd" xmlns="http://www.abisource.com/awml.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" version="2.8.4" xml:space="preserve" props="dom-dir:ltr; document-footnote-restart-section:0; document-endnote-type:numeric; document-endnote-place-enddoc:1; document-endnote-initial:1; lang:en-US; document-endnote-restart-section:0; document-footnote-restart-page:0; document-footnote-type:numeric; document-footnote-initial:1; document-endnote-place-endsection:0">
4<!-- ======================================================================== -->
5<!-- This file is an AbiWord document.                                        -->
6<!-- AbiWord is a free, Open Source word processor.                           -->
7<!-- More information about AbiWord is available at http://www.abisource.com/ -->
8<!-- You should not edit this file by hand.                                   -->
9<!-- ======================================================================== -->
10
11<metadata>
12<m key="dc.format">application/x-abiword</m>
13<m key="abiword.generator">AbiWord</m>
14</metadata>
15<styles>
16<s type="P" name="Normal" followedby="Current Settings" props="font-family:Liberation Serif; margin-top:0pt; color:000000; margin-left:0pt; bgcolor:transparent; widows:2; font-style:normal; text-indent:0in; text-position:normal; margin-bottom:0pt; font-weight:normal; line-height:1.0; text-align:left; font-variant:normal; text-decoration:none; margin-right:0pt; font-size:12pt; font-stretch:normal"/>
17</styles>
18<pagesize pagetype="A4" orientation="portrait" width="210.000000" height="297.000000" units="mm" page-scale="1.000000"/>
19<section xid="1">
20<p style="Normal" xid="2" props="text-align:left; dom-dir:ltr">#Copyright (c) 2008, Media Modifications Ltd.</p>
21<p style="Normal" xid="3" props="text-align:left; dom-dir:ltr">#Copyright (c) 2011, Walter Bender</p>
22<p style="Normal" xid="4"><c></c></p>
23<p style="Normal" xid="5" props="text-align:left; dom-dir:ltr"># This procedure is invoked when the user-definable block on the</p>
24<p style="Normal" xid="6" props="text-align:left; dom-dir:ltr"># "extras" palette is selected.</p>
25<p style="Normal" xid="7"><c></c></p>
26<p style="Normal" xid="8" props="text-align:left; dom-dir:ltr"># Usage: Import this code into a Python (user-definable) block; Pass</p>
27<p style="Normal" xid="9" props="text-align:left; dom-dir:ltr"># it 'start' to start recording; 'stop' to stop recording; 'play' to</p>
28<p style="Normal" xid="10" props="text-align:left; dom-dir:ltr"># play back your recording; or 'save' to save your recording to the</p>
29<p style="Normal" xid="11" props="text-align:left; dom-dir:ltr"># Sugar Journal.</p>
30<p style="Normal" xid="12"><c></c></p>
31<p style="Normal" xid="13"><c></c></p>
32<p style="Normal" xid="14" props="text-align:left; dom-dir:ltr">def myblock(tw, arg):</p>
33<p style="Normal" xid="15" props="text-align:left; dom-dir:ltr">    ''' Record and playback a sound (Sugar only) '''</p>
34<p style="Normal" xid="16" props="text-align:left; dom-dir:ltr">    import os</p>
35<p style="Normal" xid="17" props="text-align:left; dom-dir:ltr">    import time</p>
36<p style="Normal" xid="18"><c></c></p>
37<p style="Normal" xid="19" props="text-align:left; dom-dir:ltr">    import gtk</p>
38<p style="Normal" xid="20" props="text-align:left; dom-dir:ltr">    import gst</p>
39<p style="Normal" xid="21"><c></c></p>
40<p style="Normal" xid="22" props="text-align:left; dom-dir:ltr">    import gobject</p>
41<p style="Normal" xid="23" props="text-align:left; dom-dir:ltr">    gobject.threads_init()</p>
42<p style="Normal" xid="24"><c></c></p>
43<p style="Normal" xid="25" props="text-align:left; dom-dir:ltr">    from TurtleArt.tautils import get_path</p>
44<p style="Normal" xid="26" props="text-align:left; dom-dir:ltr">    from TurtleArt.tagplay import play_audio_from_file</p>
45<p style="Normal" xid="27" props="text-align:left; dom-dir:ltr">    from sugar.datastore import datastore</p>
46<p style="Normal" xid="28" props="text-align:left; dom-dir:ltr">    from sugar import profile</p>
47<p style="Normal" xid="29"><c></c></p>
48<p style="Normal" xid="30" props="text-align:left; dom-dir:ltr">    from gettext import gettext as _</p>
49<p style="Normal" xid="31"><c></c></p>
50<p style="Normal" xid="32" props="text-align:left; dom-dir:ltr">    class Grecord:</p>
51<p style="Normal" xid="33" props="text-align:left; dom-dir:ltr">        ''' A class for creating a gstreamer session for recording audio. '''</p>
52<p style="Normal" xid="34"><c></c></p>
53<p style="Normal" xid="35" props="text-align:left; dom-dir:ltr">        def __init__(self, tw):</p>
54<p style="Normal" xid="36" props="text-align:left; dom-dir:ltr">            ''' Set up the stream. We save to a raw .wav file and then</p>
55<p style="Normal" xid="37" props="text-align:left; dom-dir:ltr">            convert the sound to .ogg for saving. '''</p>
56<p style="Normal" xid="38" props="text-align:left; dom-dir:ltr">            datapath = get_path(tw.parent, 'instance')</p>
57<p style="Normal" xid="39" props="text-align:left; dom-dir:ltr">            self.capture_file = os.path.join(datapath, 'output.wav')</p>
58<p style="Normal" xid="40" props="text-align:left; dom-dir:ltr">            self.save_file = os.path.join(datapath, 'output.ogg')</p>
59<p style="Normal" xid="41" props="text-align:left; dom-dir:ltr">            self._eos_cb = None</p>
60<p style="Normal" xid="42"><c></c></p>
61<p style="Normal" xid="43" props="text-align:left; dom-dir:ltr">            self._can_limit_framerate = False</p>
62<p style="Normal" xid="44" props="text-align:left; dom-dir:ltr">            self._recording = False</p>
63<p style="Normal" xid="45"><c></c></p>
64<p style="Normal" xid="46" props="text-align:left; dom-dir:ltr">            self._audio_transcode_handler = None</p>
65<p style="Normal" xid="47" props="text-align:left; dom-dir:ltr">            self._transcode_id = None</p>
66<p style="Normal" xid="48"><c></c></p>
67<p style="Normal" xid="49" props="text-align:left; dom-dir:ltr">            self._pipeline = gst.Pipeline("Record")</p>
68<p style="Normal" xid="50" props="text-align:left; dom-dir:ltr">            self._create_audiobin()</p>
69<p style="Normal" xid="51" props="text-align:left; dom-dir:ltr">            self._pipeline.add(self._audiobin)</p>
70<p style="Normal" xid="52"><c></c></p>
71<p style="Normal" xid="53" props="text-align:left; dom-dir:ltr">            bus = self._pipeline.get_bus()</p>
72<p style="Normal" xid="54" props="text-align:left; dom-dir:ltr">            bus.add_signal_watch()</p>
73<p style="Normal" xid="55" props="text-align:left; dom-dir:ltr">            bus.connect('message', self._bus_message_handler)</p>
74<p style="Normal" xid="56"><c></c></p>
75<p style="Normal" xid="57" props="text-align:left; dom-dir:ltr">        def _create_audiobin(self):</p>
76<p style="Normal" xid="58" props="text-align:left; dom-dir:ltr">            ''' Assemble all the pieces we need. '''</p>
77<p style="Normal" xid="59" props="text-align:left; dom-dir:ltr">            src = gst.element_factory_make("alsasrc", "absrc")</p>
78<p style="Normal" xid="60"><c></c></p>
79<p style="Normal" xid="61" props="text-align:left; dom-dir:ltr">            # attempt to use direct access to the 0,0 device, solving some A/V</p>
80<p style="Normal" xid="62" props="text-align:left; dom-dir:ltr">            # sync issues</p>
81<p style="Normal" xid="63" props="text-align:left; dom-dir:ltr">            src.set_property("device", "plughw:0,0")</p>
82<p style="Normal" xid="64" props="text-align:left; dom-dir:ltr">            hwdev_available = src.set_state(gst.STATE_PAUSED) != \</p>
83<p style="Normal" xid="65" props="text-align:left; dom-dir:ltr">                              gst.STATE_CHANGE_FAILURE</p>
84<p style="Normal" xid="66" props="text-align:left; dom-dir:ltr">            src.set_state(gst.STATE_NULL)</p>
85<p style="Normal" xid="67" props="text-align:left; dom-dir:ltr">            if not hwdev_available:</p>
86<p style="Normal" xid="68" props="text-align:left; dom-dir:ltr">                src.set_property("device", "default")</p>
87<p style="Normal" xid="69"><c></c></p>
88<p style="Normal" xid="70" props="text-align:left; dom-dir:ltr">            srccaps = gst.Caps("audio/x-raw-int,rate=16000,channels=1,depth=16")</p>
89<p style="Normal" xid="71"><c></c></p>
90<p style="Normal" xid="72" props="text-align:left; dom-dir:ltr">            # guarantee perfect stream, important for A/V sync</p>
91<p style="Normal" xid="73" props="text-align:left; dom-dir:ltr">            rate = gst.element_factory_make("audiorate")</p>
92<p style="Normal" xid="74"><c></c></p>
93<p style="Normal" xid="75" props="text-align:left; dom-dir:ltr">            # without a buffer here, gstreamer struggles at the start of the</p>
94<p style="Normal" xid="76" props="text-align:left; dom-dir:ltr">            # recording and then the A/V sync is bad for the whole video</p>
95<p style="Normal" xid="77" props="text-align:left; dom-dir:ltr">            # (possibly a gstreamer/ALSA bug -- even if it gets caught up, it</p>
96<p style="Normal" xid="78" props="text-align:left; dom-dir:ltr">            # should be able to resync without problem)</p>
97<p style="Normal" xid="79" props="text-align:left; dom-dir:ltr">            queue = gst.element_factory_make("queue", "audioqueue")</p>
98<p style="Normal" xid="80" props="text-align:left; dom-dir:ltr">            queue.set_property("leaky", True) # prefer fresh data</p>
99<p style="Normal" xid="81" props="text-align:left; dom-dir:ltr">            queue.set_property("max-size-time", 5000000000) # 5 seconds</p>
100<p style="Normal" xid="82" props="text-align:left; dom-dir:ltr">            queue.set_property("max-size-buffers", 500)</p>
101<p style="Normal" xid="83" props="text-align:left; dom-dir:ltr">            queue.connect("overrun", self._log_queue_overrun)</p>
102<p style="Normal" xid="84"><c></c></p>
103<p style="Normal" xid="85" props="text-align:left; dom-dir:ltr">            enc = gst.element_factory_make("wavenc", "abenc")</p>
104<p style="Normal" xid="86"><c></c></p>
105<p style="Normal" xid="87" props="text-align:left; dom-dir:ltr">            sink = gst.element_factory_make("filesink", "absink")</p>
106<p style="Normal" xid="88" props="text-align:left; dom-dir:ltr">            sink.set_property("location", self.capture_file)</p>
107<p style="Normal" xid="89"><c></c></p>
108<p style="Normal" xid="90" props="text-align:left; dom-dir:ltr">            self._audiobin = gst.Bin("audiobin")</p>
109<p style="Normal" xid="91" props="text-align:left; dom-dir:ltr">            self._audiobin.add(src, rate, queue, enc, sink)</p>
110<p style="Normal" xid="92"><c></c></p>
111<p style="Normal" xid="93" props="text-align:left; dom-dir:ltr">            src.link(rate, srccaps)</p>
112<p style="Normal" xid="94" props="text-align:left; dom-dir:ltr">            gst.element_link_many(rate, queue, enc, sink)</p>
113<p style="Normal" xid="95"><c></c></p>
114<p style="Normal" xid="96" props="text-align:left; dom-dir:ltr">        def _log_queue_overrun(self, queue):</p>
115<p style="Normal" xid="97" props="text-align:left; dom-dir:ltr">            ''' We use a buffer, which may overflow. '''</p>
116<p style="Normal" xid="98" props="text-align:left; dom-dir:ltr">            cbuffers = queue.get_property("current-level-buffers")</p>
117<p style="Normal" xid="99" props="text-align:left; dom-dir:ltr">            cbytes = queue.get_property("current-level-bytes")</p>
118<p style="Normal" xid="100" props="text-align:left; dom-dir:ltr">            ctime = queue.get_property("current-level-time")</p>
119<p style="Normal" xid="101"> </p>
120<p style="Normal" xid="102" props="text-align:left; dom-dir:ltr">        def is_recording(self):</p>
121<p style="Normal" xid="103" props="text-align:left; dom-dir:ltr">            ''' Are we recording? '''</p>
122<p style="Normal" xid="104" props="text-align:left; dom-dir:ltr">            return self._recording</p>
123<p style="Normal" xid="105"><c></c></p>
124<p style="Normal" xid="106" props="text-align:left; dom-dir:ltr">        def _get_state(self):</p>
125<p style="Normal" xid="107" props="text-align:left; dom-dir:ltr">            ''' What is the state of our gstreamer pipeline? '''</p>
126<p style="Normal" xid="108" props="text-align:left; dom-dir:ltr">            return self._pipeline.get_state()[1]</p>
127<p style="Normal" xid="109"><c></c></p>
128<p style="Normal" xid="110" props="text-align:left; dom-dir:ltr">        def start_recording_audio(self):</p>
129<p style="Normal" xid="111" props="text-align:left; dom-dir:ltr">            ''' Start the stream in order to start recording. '''</p>
130<p style="Normal" xid="112" props="text-align:left; dom-dir:ltr">            if self._get_state() == gst.STATE_PLAYING:</p>
131<p style="Normal" xid="113" props="text-align:left; dom-dir:ltr">                return</p>
132<p style="Normal" xid="114" props="text-align:left; dom-dir:ltr">            self._pipeline.set_state(gst.STATE_PLAYING)</p>
133<p style="Normal" xid="115" props="text-align:left; dom-dir:ltr">            self._recording = True</p>
134<p style="Normal" xid="116"><c></c></p>
135<p style="Normal" xid="117" props="text-align:left; dom-dir:ltr">        def stop_recording_audio(self):</p>
136<p style="Normal" xid="118" props="text-align:left; dom-dir:ltr">            ''' Stop recording and then convert the results into a</p>
137<p style="Normal" xid="119" props="text-align:left; dom-dir:ltr">            .ogg file using a new stream. '''</p>
138<p style="Normal" xid="120" props="text-align:left; dom-dir:ltr">            self._pipeline.set_state(gst.STATE_NULL)</p>
139<p style="Normal" xid="121" props="text-align:left; dom-dir:ltr">            self._recording = False</p>
140<p style="Normal" xid="122"><c></c></p>
141<p style="Normal" xid="123" props="text-align:left; dom-dir:ltr">            if not os.path.exists(self.capture_file) or \</p>
142<p style="Normal" xid="124" props="text-align:left; dom-dir:ltr">                   os.path.getsize(self.capture_file) &lt;= 0:</p>
143<p style="Normal" xid="125" props="text-align:left; dom-dir:ltr">                return</p>
144<p style="Normal" xid="126"><c></c></p>
145<p style="Normal" xid="127" props="text-align:left; dom-dir:ltr">            # Remove previous transcoding results.</p>
146<p style="Normal" xid="128" props="text-align:left; dom-dir:ltr">            if os.path.exists(self.save_file):</p>
147<p style="Normal" xid="129" props="text-align:left; dom-dir:ltr">                os.remove(self.save_file)</p>
148<p style="Normal" xid="130"><c></c></p>
149<p style="Normal" xid="131" props="text-align:left; dom-dir:ltr">            line = 'filesrc location=' + self.capture_file + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'</p>
150<p style="Normal" xid="132" props="text-align:left; dom-dir:ltr">            audioline = gst.parse_launch(line)</p>
151<p style="Normal" xid="133"><c></c></p>
152<p style="Normal" xid="134" props="text-align:left; dom-dir:ltr">            vorbis_enc = audioline.get_by_name('audioVorbisenc')</p>
153<p style="Normal" xid="135"><c></c></p>
154<p style="Normal" xid="136" props="text-align:left; dom-dir:ltr">            audioFilesink = audioline.get_by_name('audioFilesink')</p>
155<p style="Normal" xid="137" props="text-align:left; dom-dir:ltr">            audioFilesink.set_property("location", self.save_file)</p>
156<p style="Normal" xid="138"><c></c></p>
157<p style="Normal" xid="139" props="text-align:left; dom-dir:ltr">            audioBus = audioline.get_bus()</p>
158<p style="Normal" xid="140" props="text-align:left; dom-dir:ltr">            audioBus.add_signal_watch()</p>
159<p style="Normal" xid="141" props="text-align:left; dom-dir:ltr">            self._audio_transcode_handler = audioBus.connect(</p>
160<p style="Normal" xid="142" props="text-align:left; dom-dir:ltr">                'message', self._onMuxedAudioMessageCb, audioline)</p>
161<p style="Normal" xid="143" props="text-align:left; dom-dir:ltr">            self._transcode_id = gobject.timeout_add(</p>
162<p style="Normal" xid="144" props="text-align:left; dom-dir:ltr">                200, self._transcodeUpdateCb, audioline)</p>
163<p style="Normal" xid="145" props="text-align:left; dom-dir:ltr">            audioline.set_state(gst.STATE_PLAYING)</p>
164<p style="Normal" xid="146"><c></c></p>
165<p style="Normal" xid="147" props="text-align:left; dom-dir:ltr">        def _transcodeUpdateCb(self, pipe):</p>
166<p style="Normal" xid="148" props="text-align:left; dom-dir:ltr">            ''' Where are we in the transcoding process? '''</p>
167<p style="Normal" xid="149" props="text-align:left; dom-dir:ltr">            position, duration = self._query_position(pipe)</p>
168<p style="Normal" xid="150" props="text-align:left; dom-dir:ltr">            if position != gst.CLOCK_TIME_NONE:</p>
169<p style="Normal" xid="151" props="text-align:left; dom-dir:ltr">                value = position * 100.0 / duration</p>
170<p style="Normal" xid="152" props="text-align:left; dom-dir:ltr">                value = value/100.0</p>
171<p style="Normal" xid="153" props="text-align:left; dom-dir:ltr">            return True</p>
172<p style="Normal" xid="154"><c></c></p>
173<p style="Normal" xid="155" props="text-align:left; dom-dir:ltr">        def _query_position(self, pipe):</p>
174<p style="Normal" xid="156" props="text-align:left; dom-dir:ltr">            ''' Where are we in the stream? '''</p>
175<p style="Normal" xid="157" props="text-align:left; dom-dir:ltr">            try:</p>
176<p style="Normal" xid="158" props="text-align:left; dom-dir:ltr">                position, format = pipe.query_position(gst.FORMAT_TIME)</p>
177<p style="Normal" xid="159" props="text-align:left; dom-dir:ltr">            except:</p>
178<p style="Normal" xid="160" props="text-align:left; dom-dir:ltr">                position = gst.CLOCK_TIME_NONE</p>
179<p style="Normal" xid="161"><c></c></p>
180<p style="Normal" xid="162" props="text-align:left; dom-dir:ltr">            try:</p>
181<p style="Normal" xid="163" props="text-align:left; dom-dir:ltr">                duration, format = pipe.query_duration(gst.FORMAT_TIME)</p>
182<p style="Normal" xid="164" props="text-align:left; dom-dir:ltr">            except:</p>
183<p style="Normal" xid="165" props="text-align:left; dom-dir:ltr">                duration = gst.CLOCK_TIME_NONE</p>
184<p style="Normal" xid="166"><c></c></p>
185<p style="Normal" xid="167" props="text-align:left; dom-dir:ltr">            return (position, duration)</p>
186<p style="Normal" xid="168"><c></c></p>
187<p style="Normal" xid="169" props="text-align:left; dom-dir:ltr">        def _onMuxedAudioMessageCb(self, bus, message, pipe):</p>
188<p style="Normal" xid="170" props="text-align:left; dom-dir:ltr">            ''' Clean up at end of stream.'''</p>
189<p style="Normal" xid="171" props="text-align:left; dom-dir:ltr">            if message.type != gst.MESSAGE_EOS:</p>
190<p style="Normal" xid="172" props="text-align:left; dom-dir:ltr">                return True</p>
191<p style="Normal" xid="173"><c></c></p>
192<p style="Normal" xid="174" props="text-align:left; dom-dir:ltr">            gobject.source_remove(self._audio_transcode_handler)</p>
193<p style="Normal" xid="175" props="text-align:left; dom-dir:ltr">            self._audio_transcode_handler = None</p>
194<p style="Normal" xid="176" props="text-align:left; dom-dir:ltr">            gobject.source_remove(self._transcode_id)</p>
195<p style="Normal" xid="177" props="text-align:left; dom-dir:ltr">            self._transcode_id = None</p>
196<p style="Normal" xid="178" props="text-align:left; dom-dir:ltr">            pipe.set_state(gst.STATE_NULL)</p>
197<p style="Normal" xid="179" props="text-align:left; dom-dir:ltr">            pipe.get_bus().remove_signal_watch()</p>
198<p style="Normal" xid="180" props="text-align:left; dom-dir:ltr">            pipe.get_bus().disable_sync_message_emission()</p>
199<p style="Normal" xid="181"><c></c></p>
200<p style="Normal" xid="182" props="text-align:left; dom-dir:ltr">            os.remove(self.capture_file)</p>
201<p style="Normal" xid="183" props="text-align:left; dom-dir:ltr">            return False</p>
202<p style="Normal" xid="184"><c></c></p>
203<p style="Normal" xid="185" props="text-align:left; dom-dir:ltr">        def _bus_message_handler(self, bus, message):</p>
204<p style="Normal" xid="186" props="text-align:left; dom-dir:ltr">            ''' Handle any messages associated with the stream. '''</p>
205<p style="Normal" xid="187" props="text-align:left; dom-dir:ltr">            t = message.type</p>
206<p style="Normal" xid="188" props="text-align:left; dom-dir:ltr">            if t == gst.MESSAGE_EOS:</p>
207<p style="Normal" xid="189" props="text-align:left; dom-dir:ltr">                if self._eos_cb:</p>
208<p style="Normal" xid="190" props="text-align:left; dom-dir:ltr">                    cb = self._eos_cb</p>
209<p style="Normal" xid="191" props="text-align:left; dom-dir:ltr">                    self._eos_cb = None</p>
210<p style="Normal" xid="192" props="text-align:left; dom-dir:ltr">                    cb()</p>
211<p style="Normal" xid="193" props="text-align:left; dom-dir:ltr">            elif t == gst.MESSAGE_ERROR:</p>
212<p style="Normal" xid="194" props="text-align:left; dom-dir:ltr">                # TODO: if we come out of suspend/resume with errors, then</p>
213<p style="Normal" xid="195" props="text-align:left; dom-dir:ltr">                # get us back up and running...  TODO: handle "No space</p>
214<p style="Normal" xid="196" props="text-align:left; dom-dir:ltr">                # left on the resource.gstfilesink.c" err, debug =</p>
215<p style="Normal" xid="197" props="text-align:left; dom-dir:ltr">                # message.parse_error()</p>
216<p style="Normal" xid="198" props="text-align:left; dom-dir:ltr">                pass</p>
217<p style="Normal" xid="199"><c></c></p>
218<p style="Normal" xid="200" props="text-align:left; dom-dir:ltr">    # We store the audio-record stream instance as tw.grecord so that</p>
219<p style="Normal" xid="201" props="text-align:left; dom-dir:ltr">    # we can use it repeatedly.</p>
220<p style="Normal" xid="202" props="text-align:left; dom-dir:ltr">    if not hasattr(tw, 'grecord'):</p>
221<p style="Normal" xid="203" props="text-align:left; dom-dir:ltr">        tw.grecord = Grecord(tw)</p>
222<p style="Normal" xid="204"><c></c></p>
223<p style="Normal" xid="205" props="text-align:left; dom-dir:ltr">    # Sometime we need to parse multiple arguments, e.g., save, savename</p>
224<p style="Normal" xid="206" props="text-align:left; dom-dir:ltr">    save_name = _('Turtle Art') + ' ' + _('sound')</p>
225<p style="Normal" xid="207" props="text-align:left; dom-dir:ltr">    if type(arg) == type([]):</p>
226<p style="Normal" xid="208" props="text-align:left; dom-dir:ltr">        cmd = arg[0].lower()</p>
227<p style="Normal" xid="209" props="text-align:left; dom-dir:ltr">        if len(arg) &gt; 1:</p>
228<p style="Normal" xid="210" props="text-align:left; dom-dir:ltr">            save_name = str(arg[1])</p>
229<p style="Normal" xid="211" props="text-align:left; dom-dir:ltr">    else:</p>
230<p style="Normal" xid="212" props="text-align:left; dom-dir:ltr">        cmd = arg.lower()</p>
231<p style="Normal" xid="213"><c></c></p>
232<p style="Normal" xid="214" props="text-align:left; dom-dir:ltr">    if cmd == 'start' or cmd == _('start').lower():</p>
233<p style="Normal" xid="215" props="text-align:left; dom-dir:ltr">        tw.grecord.start_recording_audio()</p>
234<p style="Normal" xid="216" props="text-align:left; dom-dir:ltr">    elif cmd == 'stop' or cmd == _('stop').lower():</p>
235<p style="Normal" xid="217" props="text-align:left; dom-dir:ltr">        tw.grecord.stop_recording_audio()</p>
236<p style="Normal" xid="218" props="text-align:left; dom-dir:ltr">    elif cmd == 'play' or cmd == _('play').lower():</p>
237<p style="Normal" xid="219" props="text-align:left; dom-dir:ltr">        play_audio_from_file(tw.lc, tw.grecord.save_file)</p>
238<p style="Normal" xid="220" props="text-align:left; dom-dir:ltr">    elif cmd == 'save' or cmd == _('save').lower():</p>
239<p style="Normal" xid="221" props="text-align:left; dom-dir:ltr">        if os.path.exists(tw.grecord.save_file) and tw.running_sugar:</p>
240<p style="Normal" xid="222" props="text-align:left; dom-dir:ltr">            dsobject = datastore.create()</p>
241<p style="Normal" xid="223" props="text-align:left; dom-dir:ltr">            dsobject.metadata['title'] = save_name</p>
242<p style="Normal" xid="224" props="text-align:left; dom-dir:ltr">            dsobject.metadata['icon-color'] = profile.get_color().to_string()</p>
243<p style="Normal" xid="225" props="text-align:left; dom-dir:ltr">            dsobject.metadata['mime_type'] = 'audio/ogg'</p>
244<p style="Normal" xid="226" props="text-align:left; dom-dir:ltr">            dsobject.set_file_path(tw.grecord.save_file)</p>
245<p style="Normal" xid="227" props="text-align:left; dom-dir:ltr">            datastore.write(dsobject)</p>
246<p style="Normal" xid="228" props="text-align:left; dom-dir:ltr">            dsobject.destroy()</p>
247<p style="Normal" xid="229"></p>
248</section>
249</abiword>