def pump(self):
        underrun = False

        if self._stop_alsatime is not None:
            return underrun

        # Check that ALSA's still playing
        if self._playing:
            state = asound.snd_pcm_state(self.pcm)
            if state not in (asound.SND_PCM_STATE_RUNNING,
                             asound.SND_PCM_STATE_PREPARED):
                # Underrun!
                check(asound.snd_pcm_prepare(self.pcm))
                underrun = True

        alsatime = self._get_asound_time()
        try:
            while self._timestamps[0][0] < alsatime:
                self._timestamps.pop(0)
                while self._timestamps[0][0] is None:
                    self._eos_count += 1
                    self._timestamps.pop(0)
        except IndexError:
            pass

        return underrun
Example #2
0
    def pump(self):
        underrun = False

        if self._stop_alsatime is not None:
            return underrun

        # Check that ALSA's still playing
        if self._playing:
            state = asound.snd_pcm_state(self.pcm)
            if state not in (asound.SND_PCM_STATE_RUNNING,
                             asound.SND_PCM_STATE_PREPARED):
                # Underrun!
                check(asound.snd_pcm_prepare(self.pcm))
                underrun = True

        alsatime = self._get_asound_time()
        try:
            while self._timestamps[0][0] < alsatime:
                self._timestamps.pop(0)
                while self._timestamps[0][0] is None:
                    self._eos_count += 1
                    self._timestamps.pop(0)
        except IndexError:
            pass

        return underrun
Example #3
0
 def _clear_ring_buffer(self):
     check(asound.snd_pcm_drop(self._device.pcm))
     check(asound.snd_pcm_prepare(self._device.pcm))
     self._current_buffer_time = 0.
     self._cumulative_buffer_time = 0.
     self._source_read_index = 0
     self._queue_audio_data = None
     self._start_time = None
    def play(self):
        if self._playing:
            return

        state = asound.snd_pcm_state(self.pcm)
        if self.can_pause and state == asound.SND_PCM_STATE_PAUSED:
            check(asound.snd_pcm_pause(self.pcm, 0))
        elif state not in (asound.SND_PCM_STATE_RUNNING,
                           asound.SND_PCM_STATE_PREPARED):
            check(asound.snd_pcm_prepare(self.pcm))
        self._playing = True

        if self._stop_alsatime is not None:
            diff = self._get_asound_time() - self._stop_alsatime
            self._timestamps = [(a + diff, t) for a, t in self._timestamps]
            self._stop_alsatime = None
Example #5
0
    def play(self):
        if self._playing:
            return

        state = asound.snd_pcm_state(self.pcm)
        if self.can_pause and state == asound.SND_PCM_STATE_PAUSED:
            check(asound.snd_pcm_pause(self.pcm, 0))
        elif state not in (asound.SND_PCM_STATE_RUNNING,
                           asound.SND_PCM_STATE_PREPARED):
            check(asound.snd_pcm_prepare(self.pcm))
        self._playing = True

        if self._stop_alsatime is not None:
            diff = self._get_asound_time() - self._stop_alsatime
            self._timestamps = [(a + diff, t) for a, t in self._timestamps]
            self._stop_alsatime = None
    def write(self, audio_data):
        samples = audio_data.length // self.audio_format.bytes_per_sample
        samples_out = asound.snd_pcm_writei(self.pcm, audio_data.data, samples)
        if samples_out < 0:
            if samples_out == -11:  # EAGAIN
                return
            elif samples_out == -32:  # EPIPE (xrun)
                check(asound.snd_pcm_prepare(self.pcm))
                return
            else:
                raise ALSAException(asound.snd_strerror(samples_out))

        delay = asound.snd_pcm_sframes_t()
        check(asound.snd_pcm_delay(self.pcm, delay))
        alsatime = self._get_asound_time() + \
            delay.value / float(self.audio_format.sample_rate)

        self._timestamps.append((alsatime, audio_data.timestamp))

        audio_data.consume(samples_out * self.audio_format.bytes_per_sample,
                           self.audio_format)
Example #7
0
    def write(self, audio_data):
        samples = audio_data.length // self.audio_format.bytes_per_sample
        samples_out = asound.snd_pcm_writei(self.pcm, audio_data.data,
                                            samples)
        if samples_out < 0:
            if samples_out == -11: # EAGAIN
                return
            elif samples_out == -32: # EPIPE (xrun)
                check(asound.snd_pcm_prepare(self.pcm))
                return
            else:
                raise ALSAException(asound.snd_strerror(samples_out))

        delay = asound.snd_pcm_sframes_t()
        check(asound.snd_pcm_delay(self.pcm, delay))
        alsatime = self._get_asound_time() + \
            delay.value / float(self.audio_format.sample_rate)

        self._timestamps.append((alsatime, audio_data.timestamp))

        audio_data.consume(samples_out * self.audio_format.bytes_per_sample,
                           self.audio_format)
Example #8
0
    def dispatch_events(self):
        if not self._sources:
            return

        if not self._playing:
            # If paused, just update the video texture.
            if self._texture:
                self._sources[0]._update_texture(self, self.time)
            return

        # Create a device if there isn't one.  TODO only if source and source
        # has audio
        if not self._device:
            self._device = Device('plug:front')
            self._device.prepare(self._sources[0])

        self_time = self.time 

        # Passed EOS?
        source = self._sources[0]
        while source and source.duration < self_time:
            if self._eos_action == self.EOS_NEXT:
                self.next()
            elif self._eos_action == self.EOS_STOP:
                self.stop()
                self._sources = []
                return
            self.dispatch_event('on_eos')

            self_time -= source.duration
            self._cumulative_buffer_time -= source.duration
            assert self._cumulative_buffer_time >= -0.001 # some float err ok
            try:
                source = self._sources[0]
                self._set_start_time(self._sources[0], self_time)
            except IndexError:
                source = None
                self._start_time = None

        # Ensure device buffer is full
        try:
            source = self._sources[self._source_read_index]
        except IndexError:
            source = None
        while (source and 
               self._cumulative_buffer_time + self._current_buffer_time - self_time
                  < self._min_buffer_time):
            if self._queue_audio_data:
                audio_data = self._queue_audio_data
                self._queue_audio_data = None
            else:
                max_bytes = int(
                  self._min_buffer_time * source.audio_format.bytes_per_second)
                max_bytes = min(max_bytes, self._max_buffer_size)
                audio_data = source._get_audio_data(max_bytes)

            if audio_data: 
                samples = \
                    audio_data.length // source.audio_format.bytes_per_sample
                samples_out = asound.snd_pcm_writei(self._device.pcm, 
                    audio_data.data, samples)
                if samples_out < 0:
                    if samples_out == -11: # EAGAIN
                        self._queue_audio_data = audio_data
                    elif samples_out == -32: # EPIPE
                        # xrun recovery
                        check(asound.snd_pcm_prepare(self._device.pcm))
                        self._queue_audio_data = audio_data
                    else:
                        raise ALSAException(asound.snd_strerror(samples_out))
                elif samples_out < samples:
                    audio_data.consume(
                        samples_out * source.audio_format.bytes_per_sample,
                        source.audio_format)
                    self._current_buffer_time = audio_data.timestamp
                    self._queue_audio_data = audio_data
                else:
                    self._current_buffer_time = \
                        audio_data.timestamp + audio_data.duration
                    
                if self._start_time is None:
                    # XXX start playback
                    self._set_start_time(source, audio_data.timestamp)
                    
            else:
                # EOS on read source
                self._cumulative_buffer_time += source.duration
                self._current_buffer_time = 0.
                if self._eos_action == self.EOS_NEXT:
                    self._source_read_index += 1
                    try:
                        # preroll
                        source = self._sources[self._source_read_index]
                        source._play()
                    except IndexError:
                        source = None
                elif self._eos_action == self.EOS_LOOP:
                    source._seek(0)
                elif self._eos_action == self.EOS_PAUSE:
                    source = None
                elif self._eos_action == self.EOS_STOP:
                    source = None
                else:
                    assert False, 'Invalid eos_action'
                    source = None

        # Update video texture
        if self._texture:
            self._sources[0]._update_texture(self, self_time)