예제 #1
0
def test_ringbuffer_overflow():
    buffer = RingBuffer(format='B', capacity=7)
    remaining = buffer.push(b'spam')
    assert remaining is None
    remaining = buffer.push(b'eggs')
    assert bytes(remaining) == b's'
    assert bytes(buffer.pop(7)) == b'spamegg'
예제 #2
0
    def __init__(
        self,
        playback_stopped_callback = lambda: print('playback stopped'),
        frames_played_callback = lambda: print(".", end="", flush=True)
    ):
        self.playback_stopped_callback = playback_stopped_callback
        self.frames_played_callback = frames_played_callback

        # the audio stops and should be started
        # from scratch as soon as this lock is released
        self.running = threading.RLock()
        self.running.acquire()

        self.playing = threading.Event()
        self.pause()

        self.stream = RingBuffer(format='B', capacity=BUFFER_SIZE)

        self.frames_callback_executor = ThreadPoolExecutor(max_workers=1)

        self.thread = threading.Thread(
            target=self._start_device,
            name='audio device'
        )
        self.thread.daemon = True
        self.thread.start()
예제 #3
0
 def test_wrapping_overwriting_push_pop(self):
     R = RingBuffer(3)
     R.push("1")
     R.push("2")
     R.push("3")
     R.push("a")
     self.assertEqual(R.pop(), "a")
예제 #4
0
def test_ringbuffer_underflow():
    buffer = RingBuffer(format='b', capacity=1)
    assert buffer.pop(1) is None
예제 #5
0
def test_ringbuffer_push_pop(expected):
    capacity = expected.size

    buffer = RingBuffer(format=expected.dtype.char, capacity=capacity)
    assert buffer.capacity == capacity
    assert buffer.is_lock_free

    assert buffer.read_available == 0
    assert buffer.write_available == capacity

    # test full write
    remaining = buffer.push(expected)
    assert remaining is None
    assert buffer.read_available == capacity
    assert buffer.write_available == 0

    # test full read
    assert np.array_equal(buffer.pop(capacity), expected)
    assert buffer.read_available == 0
    assert buffer.write_available == capacity

    # test writing chunks
    prev_read_available = 0
    for chunk in np.array_split(expected, 6):
        remaining = buffer.push(chunk)
        assert remaining is None
        assert buffer.read_available == prev_read_available + len(chunk)
        prev_read_available += len(chunk)

    assert buffer.read_available == capacity
    assert buffer.write_available == 0

    # test reading chunks
    prev_write_available = 0
    for chunk in np.array_split(expected, 6):
        assert np.array_equal(buffer.pop(len(chunk)), chunk)
        assert buffer.write_available == prev_write_available + len(chunk)
        prev_write_available += len(chunk)

    # test reading more than available
    buffer.push(expected[:10])
    assert np.array_equal(buffer.pop(capacity), expected[:10])

    # teest reading more than capacity
    buffer.push(expected)
    assert np.array_equal(buffer.pop(capacity + 123), expected)
예제 #6
0
def test_ringbuffer_invalid():
    with pytest.raises(ValueError):
        RingBuffer(format='B', capacity=0)

    buffer = RingBuffer(format='B', capacity=10)

    # Empty data is okay
    buffer.push(b'')

    buffer.push(b'hello')

    # Can't pop negative or zero
    for i in (-1, 0):
        with pytest.raises(ValueError):
            buffer.pop(i)

    # Types must match
    with pytest.raises(TypeError):
        buffer.push(np.array('f', [1.0]))
예제 #7
0
def test_ringbuffer_reset():
    buffer = RingBuffer(format='B', capacity=5)
    buffer.push(b'hello')
    buffer.reset()
    assert buffer.pop(5) is None
예제 #8
0
from ringbuf import RingBuffer

if __name__ == "__main__":
    buff = RingBuffer(50)

    temp = str("123456789")

    # print("temp size : " + str(len(temp)))
    # print(temp[:])
    for i in range(10, 40):
        buff.push(chr(i))

    for i in range(10, 40):
        test = buff.pop()
        print("Pop : " + test + "is Oct" + " is a type, " + str(type(test)))
예제 #9
0
class MiniaudioSink(object):
    """
    Audio device interface. Internally uses a stream from which frames are read
    into an output sound device. The stream is backed by a buffer. This buffer
    is appended to with track PCM data. This object doesn't care about the overall
    state of the application -- it just feeds frames into sound card and expects
    an outside actor to tell it what other file to load. Since the buffer maintains
    a healthy headroom gapless playback is achieved with no special effort.

    `ffmpeg` is invoked to perform conversion to PCM. Tracks are loaded at once into
    memory.
    """
    def __init__(
        self,
        playback_stopped_callback = lambda: print('playback stopped'),
        frames_played_callback = lambda: print(".", end="", flush=True)
    ):
        self.playback_stopped_callback = playback_stopped_callback
        self.frames_played_callback = frames_played_callback

        # the audio stops and should be started
        # from scratch as soon as this lock is released
        self.running = threading.RLock()
        self.running.acquire()

        self.playing = threading.Event()
        self.pause()

        self.stream = RingBuffer(format='B', capacity=BUFFER_SIZE)

        self.frames_callback_executor = ThreadPoolExecutor(max_workers=1)

        self.thread = threading.Thread(
            target=self._start_device,
            name='audio device'
        )
        self.thread.daemon = True
        self.thread.start()

    def _start_device(self):
        with miniaudio.PlaybackDevice(
            output_format=miniaudio.SampleFormat.SIGNED16,
            backends=[miniaudio.Backend.PULSEAUDIO],
            nchannels=CHANNELS,
            sample_rate=SAMPLE_RATE) as device:

            generator = self._read_frames()
            next(generator)
            device.start(generator)
            self.running.acquire()  # keep the thread running or else audio stops

    def _read_frames(self):
        required_frames = yield b''
        while True:
            self.playing.wait()
            required_bytes = required_frames * CHANNELS * SAMPLE_WIDTH
            sample_data = self.stream.pop(required_bytes)

            if not sample_data:
                self.playback_stopped_callback()
                break

            self._on_frames_played(required_frames)
            required_frames = yield sample_data

    def _on_frames_played(self, frames):
        self.frames_callback_executor.submit(self.frames_played_callback, frames)

    def buffer_track(self, track_file_name):
        logger.debug('Loading track %s into buffer', track_file_name)

        pcm_data = subprocess.run(
            [
                "ffmpeg", "-v", "fatal", "-hide_banner", "-nostdin",
                "-i", track_file_name, "-f", "s16le", "-acodec", "pcm_s16le",
                "-ac", str(CHANNELS), "-ar", str(SAMPLE_RATE), "-"
            ],
            capture_output=True
        ).stdout

        self.stream.push(pcm_data)
        return self.get_frame_count(pcm_data)

    def get_frame_count(self, pcm_data):
        return len(pcm_data) // (CHANNELS * SAMPLE_WIDTH)

    def pause(self):
        self.playing.clear()

    def resume(self):
        self.playing.set()

    def release(self):
        """
        Once this has been called a new object should be created and the existing one
        cannot be used anymore.
        """
        self.running.release()
예제 #10
0
 def test_push_push_pop_pop(self):
     R = RingBuffer(5)
     R.push("1")
     R.push("2")
     self.assertEqual(R.pop()+R.pop(), "12")
예제 #11
0
 def test_write_read_read(self):
     R = RingBuffer(5)
     with self.assertRaises(ValueError):
         R.write("abcdef")
예제 #12
0
 def test_write_read_read(self):
     R = RingBuffer(5)
     R.write("abcd")
     self.assertEqual(R.read(4), "abcd")
     self.assertEqual(R.read(2), "")
예제 #13
0
 def test_wrapping_write_wrapping_read(self):
     R = RingBuffer(5)
     R.write("abcd")
     self.assertEqual(R.read(1), "a")
     R.write("e1")
     self.assertEqual(R.read(5), "bcde1")
예제 #14
0
 def test_wrapping_push_pop(self):
     R = RingBuffer(3)
     R.push("1")
     R.push("2")
     R.push("3")
     self.assertEqual(R.pop(), "1")
     R.push("a")
     self.assertEqual(R.read(2), "23")
     self.assertEqual(R.pop(), "a")