示例#1
0
    def refill(self, write_size):
        assert _debug_media('refill', write_size)

        with self._lock:

            while write_size > self.min_buffer_size:
                audio_data = self.source_group.get_audio_data(write_size)
                if not audio_data:
                    assert _debug_media('No audio data left')
                    if self._has_underrun():
                        assert _debug_media('Underrun')
                        MediaEvent(0, 'on_eos')._sync_dispatch_to_player(
                            self.player)
                        MediaEvent(
                            0, 'on_source_group_eos')._sync_dispatch_to_player(
                                self.player)
                    break

                assert _debug_media('Writing {} bytes'.format(
                    audio_data.length))
                self._queue_events(audio_data)
                self._queue_audio_data(audio_data)
                self._update_write_cursor(audio_data)
                write_size -= audio_data.length

            # Check for underrun stopping playback
            with self.driver:
                if self._playing and not self.source.is_playing:
                    assert _debug_media('underrun')
                    self.source.play()
示例#2
0
    def test_add_events(self):
        buf = EventBuffer()
        self.assertIsNone(buf.get_next_event_timestamp())

        event1 = MediaEvent(.1, 'Event1')
        event2 = MediaEvent(.5, 'Event2')
        data = AudioData('', 0, 0., 1., [event1, event2])
        buf.add_events(data)

        self.assertAlmostEqual(.1, buf.get_next_event_timestamp())
示例#3
0
    def _consume_data(self):
        """Consume content of packets that should have been played back up to now."""
        with self._thread.condition:
            offset = self._calculate_offset()
            self._audio_buffer.consume_audio_data(offset)
            self._update_time()

            if self._audio_buffer.is_empty():
                if _debug:
                    print('Out of packets')
                timestamp = self.get_time()
                MediaEvent(timestamp, 'on_eos')._sync_dispatch_to_player(self.player)
                MediaEvent(timestamp, 'on_source_group_eos')._sync_dispatch_to_player(self.player)
示例#4
0
    def refill(self, write_size):
        with self._lock:
            while write_size > 0:
                if _debug:
                    print('refill, write_size =', write_size)
                # Get next audio packet (or remains of last one)
                if self._next_audio_data:
                    audio_data = self._next_audio_data
                    self._next_audio_data = None
                else:
                    audio_data = self.source_group.get_audio_data(write_size)

                # Write it, or silence if there are no more packets
                if audio_data:
                    # Add events
                    for event in audio_data.events:
                        event_cursor = self._write_cursor + event.timestamp * \
                            self.source_group.audio_format.bytes_per_second
                        self._events.append((event_cursor, event))

                    # Add timestamp (at end of this data packet)
                    ts_cursor = self._write_cursor + audio_data.length
                    self._timestamps.append(
                        (ts_cursor,
                         audio_data.timestamp + audio_data.duration))

                    # Write data
                    if _debug:
                        print('write', audio_data.length)
                    length = min(write_size, audio_data.length)
                    self.write(audio_data, length)
                    if audio_data.length:
                        self._next_audio_data = audio_data
                    write_size -= length
                else:
                    # Write silence
                    if self._eos_cursor is None:
                        self._eos_cursor = self._write_cursor
                        self._events.append(
                            (self._eos_cursor, MediaEvent(0, 'on_eos')))
                        self._events.append(
                            (self._eos_cursor,
                             MediaEvent(0, 'on_source_group_eos')))
                        self._events.sort()
                    if self._write_cursor > self._eos_cursor + self._buffer_size:
                        self.stop()
                    else:
                        self.write(None, write_size)
                    write_size = 0
示例#5
0
    def test_consume_non_str_data(self):
        audio_format = AudioFormat(1, 8, 11025)
        duration = 1.0
        length = int(duration * audio_format.bytes_per_second)
        data = self.generate_random_string_data(length)
        non_str_data = self.create_string_buffer(data)

        audio_data = AudioData(non_str_data, length, 0.0, duration,
                               (MediaEvent(0.0, 'event'), ))

        chunk_duration = 0.1
        chunk_size = int(chunk_duration * audio_format.bytes_per_second)
        self.assertLessEqual(chunk_size, length)

        audio_data.consume(chunk_size, audio_format)

        self.assertEqual(audio_data.length, length - chunk_size)
        self.assertAlmostEqual(audio_data.duration,
                               duration - chunk_duration,
                               places=2)
        self.assertAlmostEqual(audio_data.timestamp, chunk_duration, places=2)

        self.assertEqual(audio_data.get_string_data(), data[chunk_size:])

        self.assertTupleEqual(audio_data.events, ())
示例#6
0
    def _get_new_audiodata(self):
        assert _debug_media('Getting new audio data buffer.')
        self._audiodata_buffer = self.source_group.get_audio_data(
            self.ideal_buffer_size)

        if self._audiodata_buffer is not None:
            assert _debug_media('New audio data available: {} bytes'.format(
                self._audiodata_buffer.length))
            self._queue_events(self._audiodata_buffer)
        else:
            assert _debug_media('No audio data left')
            if self._has_underrun():
                assert _debug_media('Underrun')
                MediaEvent(0, 'on_eos')._sync_dispatch_to_player(self.player)
                MediaEvent(0, 'on_source_group_eos')._sync_dispatch_to_player(
                    self.player)
示例#7
0
    def test_get_time_to_next_event(self):
        buf = EventBuffer()
        self.assertIsNone(buf.get_next_event_timestamp())

        event1 = MediaEvent(.2, 'Event1')
        event2 = MediaEvent(.2, 'Event2')
        data1 = AudioData('', 0, 0., 1., [event1, event2])
        buf.add_events(data1)

        event3 = MediaEvent(.3, 'Event3')
        event4 = MediaEvent(.4, 'Event4')
        data2 = AudioData('', 0, 1., 1., [event3, event4])
        buf.add_events(data2)

        self.assertAlmostEqual(.2, buf.get_time_to_next_event(0.))
        self.assertAlmostEqual(.1, buf.get_time_to_next_event(.1))

        buf.get_expired_events(.2)
        self.assertAlmostEqual(1.1, buf.get_time_to_next_event(.2))
        self.assertAlmostEqual(.1, buf.get_time_to_next_event(1.2))
示例#8
0
    def test_get_multiple_events(self):
        buf = EventBuffer()
        self.assertIsNone(buf.get_next_event_timestamp())

        event1 = MediaEvent(.2, 'Event1')
        event2 = MediaEvent(.2, 'Event2')
        data1 = AudioData('', 0, 0., 1., [event1, event2])
        buf.add_events(data1)

        event3 = MediaEvent(.3, 'Event3')
        event4 = MediaEvent(.4, 'Event4')
        data2 = AudioData('', 0, 1., 1., [event3, event4])
        buf.add_events(data2)

        expired_events = buf.get_expired_events(0.)
        self.assertListEqual([], expired_events)

        expired_events = buf.get_expired_events(.2)
        self.assertListEqual([event1, event2], expired_events)

        expired_events = buf.get_expired_events(1.6)
        self.assertListEqual([event3, event4], expired_events)
示例#9
0
    def test_get_expired_events(self):
        buf = EventBuffer()
        self.assertIsNone(buf.get_next_event_timestamp())

        event1 = MediaEvent(.1, 'Event1')
        event2 = MediaEvent(.5, 'Event2')
        data = AudioData('', 0, 0., 1., [event1, event2])
        buf.add_events(data)

        expired_events = buf.get_expired_events(0.)
        self.assertListEqual([], expired_events)

        expired_events = buf.get_expired_events(.1)
        self.assertListEqual([event1], expired_events)

        expired_events = buf.get_expired_events(.1)
        self.assertListEqual([], expired_events)

        expired_events = buf.get_expired_events(.6)
        self.assertListEqual([event2], expired_events)

        expired_events = buf.get_expired_events(.6)
        self.assertListEqual([], expired_events)
示例#10
0
    def _get_new_audiodata(self):
        assert _debug('Getting new audio data buffer.')
        compensation_time = self.get_audio_time_diff()
        self._audiodata_buffer = self.playlist.get_audio_data(
            self.ideal_buffer_size, compensation_time)

        if self._audiodata_buffer is not None:
            assert _debug('New audio data available: {} bytes'.format(
                self._audiodata_buffer.length))
            self._queue_events(self._audiodata_buffer)
        else:
            assert _debug('No audio data left')
            if self._has_underrun():
                assert _debug('Underrun')
                MediaEvent(0, 'on_eos')._sync_dispatch_to_player(self.player)
示例#11
0
    def test_consume_only_events(self):
        audio_format = AudioFormat(1, 8, 11025)
        duration = 1.0
        length = int(duration * audio_format.bytes_per_second)
        data = self.generate_random_string_data(length)

        audio_data = AudioData(data, length, 0.0, duration, (MediaEvent(0.0, 'event'),))

        chunk_size = 0

        audio_data.consume(chunk_size, audio_format)

        self.assertEqual(audio_data.length, length)
        self.assertAlmostEqual(audio_data.duration, duration, places=2)
        self.assertAlmostEqual(audio_data.timestamp, 0., places=2)

        self.assertEqual(audio_data.get_string_data(), data)

        self.assertTupleEqual(audio_data.events, ())
示例#12
0
    def get_audio_data(self, bytes):
        """Get next audio packet.

        :Parameters:
            `bytes` : int
                Hint for preferred size of audio packet; may be ignored.

        :rtype: `AudioData`
        :return: Audio data, or None if there is no more data.
        """

        if not self._sources:
            return None
        data = self._sources[0].get_audio_data(bytes)
        eos = False
        while not data:
            eos = True
            if self._loop and not self._advance_after_eos:
                self._timestamp_offset += self._sources[0].duration
                self._dequeued_durations.insert(0, self._sources[0].duration)
                self._sources[0].seek(0)
            else:
                self._advance_after_eos = False

                # Advance source if there's something to advance to.
                # Otherwise leave last source paused at EOS.
                if len(self._sources) > 1:
                    self._advance()
                else:
                    return None

            data = self._sources[0].get_audio_data(bytes)  # TODO method rename

        data.timestamp += self._timestamp_offset
        if eos:
            if _debug:
                print('adding on_eos event to audio data')
            data.events.append(MediaEvent(0, 'on_eos'))
        return data
 def _dispatch_new_event(self, event_name):
     MediaEvent(0, event_name)._sync_dispatch_to_player(self.player)
    def refill_source_player(self):
        """Obtains audio data from the source, puts it into a buffer to submit to the voice.
        Unlike the other drivers this does not carve pieces of audio from the buffer and slowly
        consume it. This submits the buffer retrieved from the decoder in it's entirety.
        """

        buffers_queued = self._xa2_source_voice.buffers_queued

        # Free any buffers that have ended.
        while len(self._buffers) > buffers_queued:
            # Clean out any buffers that have played.
            buffer = self._buffers.pop(0)
            self._play_cursor += buffer.AudioBytes
            del buffer  # Does this remove AudioData within the buffer? Let GC remove or explicit remove?

        # We have to wait for all of the buffers we are flushing to end before we restart next buffer.
        # When voice reaches 0 buffers, it is available for re-use.
        if self._flushing:
            if buffers_queued == 0:
                self._flushing = False

                # This is required because the next call to play will come before all flushes are done.
                # Restart at next available opportunity.
                pyglet.clock.schedule_once(self._restart, 0)
            return

        if self._deleted:
            if buffers_queued == 0:
                self._deleted = False
                self._xa2_driver.return_voice(self._xa2_source_voice)
            return

        # Wait for the playback to hit 0 buffers before we eos.
        if self.buffer_end_submitted:
            if buffers_queued == 0:
                self._xa2_source_voice.stop()
                MediaEvent(0, "on_eos")._sync_dispatch_to_player(self.player)
        else:
            current_buffers = []
            while buffers_queued < self.max_buffer_count:
                audio_data = self.source.get_audio_data(self._buffer_size, 0.0)
                if audio_data:
                    assert _debug(
                        'Xaudio2: audio data - length: {}, duration: {}, buffer size: {}'
                        .format(audio_data.length, audio_data.duration,
                                self._buffer_size))

                    if audio_data.length == 0:  # Sometimes audio data has 0 length at the front?
                        continue

                    x2_buffer = self._xa2_driver.create_buffer(audio_data)

                    current_buffers.append(x2_buffer)

                    self._write_cursor += x2_buffer.AudioBytes  # We've pushed this many bytes into the source player.

                    self._add_audiodata_events(audio_data)
                    self._add_audiodata_timestamp(audio_data)

                    buffers_queued += 1
                else:
                    # End of audio data, set last packet as end.
                    self.buffer_end_submitted = True
                    break

            # We submit the buffers here, just in-case the end of stream was found.
            for cx2_buffer in current_buffers:
                self._xa2_source_voice.submit_buffer(cx2_buffer)

            # Store buffers temporarily, otherwise they get GC'd.
            self._buffers.extend(current_buffers)

        self._dispatch_pending_events()
 def _add_event_at_write_index(self, event_name):
     assert _debug('PulseAudioPlayer: Add event at index {}'.format(
         self._write_index))
     self._events.append((self._write_index, MediaEvent(0., event_name)))