Esempio n. 1
0
 def get_buffer(self):
     if not self:
         buffer = al.ALuint()
         al.alGenBuffers(1, buffer)
     else:
         buffer = self.pop(0)
     return buffer
Esempio n. 2
0
    def __init__(self, source_group, player):
        super(OpenALAudioPlayer, self).__init__(source_group, player)
        audio_format = source_group.audio_format

        try:
            self._al_format = format_map[(audio_format.channels,
                                          audio_format.sample_size)]
        except KeyError:
            raise OpenALException('Unsupported audio format.')

        self._al_source = al.ALuint()
        al.alGenSources(1, self._al_source)

        # Lock policy: lock all instance vars (except constants).  (AL calls
        # are locked on context).
        self._lock = threading.RLock()

        # Cursor positions, like DSound and Pulse drivers, refer to a
        # hypothetical infinite-length buffer.  Cursor units are in bytes.

        # Cursor position of current (head) AL buffer
        self._buffer_cursor = 0

        # Estimated playback cursor position (last seen)
        self._play_cursor = 0

        # Cursor position of end of queued AL buffer.
        self._write_cursor = 0

        # List of currently queued buffer sizes (in bytes)
        self._buffer_sizes = []

        # List of currently queued buffer timestamps
        self._buffer_timestamps = []

        # Timestamp at end of last written buffer (timestamp to return in case
        # of underrun)
        self._underrun_timestamp = None

        # List of (cursor, MediaEvent)
        self._events = []

        # Desired play state (True even if stopped due to underrun)
        self._playing = False

        # Has source group EOS been seen (and hence, event added to queue)?
        self._eos = False

        # OpenAL 1.0 timestamp interpolation: system time of current buffer
        # playback (best guess)
        if not context.have_1_1:
            self._buffer_system_time = time.time()

        self.refill(self._ideal_buffer_size)
Esempio n. 3
0
 def dequeueBuffer(self, alSource, buffer):
     """A buffer has finished playing, free it."""
     assert context._lock.locked()
     sourceBuffs = self._sources[alSource.value]
     if buffer in map(lambda x: x.value, sourceBuffs):
         #sourceBuffs.remove(buffer)
         self._sources[alSource.value] = [
             b for b in sourceBuffs if b.value != buffer
         ]
         self._buffers.append(al.ALuint(buffer))
     elif _debug_buffers:
         # This seems to be the problem with Mac OS X - The buffers are
         # dequeued, but they're not _actually_ buffers.  In other words,
         # there's some leakage, so after awhile, things break.
         print("Bad buffer: " + str(buffer))
Esempio n. 4
0
    def refill(self, write_size):
        if _debug:
            print 'refill', write_size

        self._lock.acquire()

        while write_size > self._min_buffer_size:
            audio_data = self.source_group.get_audio_data(write_size)
            if not audio_data:
                self._eos = True
                self._events.append(
                    (self._write_cursor, mt_media.MediaEvent(0, 'on_eos')))
                self._events.append(
                    (self._write_cursor,
                     mt_media.MediaEvent(0, 'on_source_group_eos')))
                break

            for event in audio_data.events:
                cursor = self._write_cursor + event.timestamp * \
                    self.source_group.audio_format.bytes_per_second
                self._events.append((cursor, event))

            buffer = al.ALuint()
            context.lock()
            al.alGenBuffers(1, buffer)
            al.alBufferData(buffer, self._al_format, audio_data.data,
                            audio_data.length,
                            self.source_group.audio_format.sample_rate)
            al.alSourceQueueBuffers(self._al_source, 1, ctypes.byref(buffer))
            context.unlock()

            self._write_cursor += audio_data.length
            self._buffer_sizes.append(audio_data.length)
            self._buffer_timestamps.append(audio_data.timestamp)
            write_size -= audio_data.length

        # Check for underrun stopping playback
        if self._playing:
            state = al.ALint()
            context.lock()
            al.alGetSourcei(self._al_source, al.AL_SOURCE_STATE, state)
            if state.value != al.AL_PLAYING:
                if _debug:
                    print 'underrun'
                al.alSourcePlay(self._al_source)
            context.unlock()

        self._lock.release()
Esempio n. 5
0
    def getBuffers(self, alSource, i):
        """Returns an array containing i buffer names.  The returned list must
        not be modified in any way, and may get changed by subsequent calls to
        getBuffers.
        """
        assert context._lock.locked()
        buffs = []
        try:
            while i > 0:
                b = self._buffers.pop()
                if not al.alIsBuffer(b):
                    # Protect against implementations that DO free buffers
                    # when they delete a source - carry on.
                    if _debug_buffers:
                        print("Found a bad buffer")
                    continue
                buffs.append(b)
                i -= 1
        except IndexError:
            while i > 0:
                buffer = al.ALuint()
                al.alGenBuffers(1, buffer)
                if _debug_buffers:
                    error = al.alGetError()
                    if error != 0:
                        print("GEN BUFFERS: " + str(error))
                buffs.append(buffer)
                i -= 1

        alSourceVal = alSource.value
        if alSourceVal not in self._sources:
            self._sources[alSourceVal] = buffs
        else:
            self._sources[alSourceVal].extend(buffs)

        return buffs
Esempio n. 6
0
        return True


if __name__ == '__main__':
    import sys

    # openal
    device = alc.alcOpenDevice(None)
    if not device:
        raise Exception('No OpenAL device.')

    alcontext = alc.alcCreateContext(device, None)
    alc.alcMakeContextCurrent(alcontext)

    source = al.ALuint()
    al.alGenSources(1, source)

    pool = BufferPool()

    # avcodec
    init()
    container = open(sys.argv[1])
    stream = get_audio_stream(container)

    decoder = AVCodecDecoder(container, stream)

    while True:
        buffer = pool.get_buffer()
        if not decoder.fill_buffer(buffer):
            break
Esempio n. 7
0
class AVCodecDecoder:
    def __init__(self, container, stream):
        self.codec = get_codec(container, stream)
        if self.codec.contents.channels == 1:
            self.buffer_format = al.AL_FORMAT_MONO16
        elif self.codec.contents.channels == 2:
            self.buffer_format = al.AL_FORMAT_STEREO16
        else:
            raise Exception('Invalid number of channels')
        self.sample_rate = self.codec.contents.sample_rate

        self.container = container
        self.stream = stream
        self.packet = avformat.AVPacket()
        self.sample_buffer = \
            (ctypes.c_int16 * (avcodec.AVCODEC_MAX_AUDIO_FRAME_SIZE / 2))()

        self.read_packet()

    def read_packet(self):
        while True:
            if self.packet.data:
                self.packet.data = None
                self.packet.size = 0

            if avformat.av_read_packet(self.container, self.packet) < 0:
                break

            if self.packet.stream_index == self.stream:
                break

        self.packet_data = self.packet.data
        self.packet_size = self.packet.size

    def fill_buffer(self, buffer):
        if self.packet_size <= 0:
            self.read_packet()

        if self.packet_size == 0:  # EOS
            return False

        sample_buffer_size = ctypes.c_int()
        len = avcodec.avcodec_decode_audio(self.codec, self.sample_buffer,
                                           sample_buffer_size,
                                           self.packet_data, self.packet_size)
        if len < 0:
            # Error, skip frame
            raise Exception('frame error TODO')

        if sample_buffer_size.value > 0:
            al.alBufferData(buffer, self.buffer_format, self.sample_buffer,
                            sample_buffer_size.value, self.sample_rate)

        # Advance buffer pointer
        self.packet_data = ctypes.c_uint8.from_address(
            ctypes.addressof(self.packet_data) + len)
        self.packet_size -= len

        return True

    import sys

    # openal
    device = alc.alcOpenDevice(None)
    if not device:
        raise Exception('No OpenAL device.')

    alcontext = alc.alcCreateContext(device, None)
    alc.alcMakeContextCurrent(alcontext)

    source = al.ALuint()
    al.alGenSources(1, source)

    pool = BufferPool()

    # avcodec
    init()
    container = open(sys.argv[1])
    stream = get_audio_stream(container)

    decoder = AVCodecDecoder(container, stream)

    while True:
        buffer = pool.get_buffer()
        if not decoder.fill_buffer(buffer):
            break
        al.alSourceQueueBuffers(source, 1, buffer)

    al.alSourcePlay(source)

    while True:
        value = al.ALint()
        al.alGetSourcei(source, al.AL_SOURCE_STATE, value)
        if value.value == al.AL_STOPPED:
            break

        time.sleep(1)