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, MediaEvent(0, 'on_eos'))) self._events.append( (self._write_cursor, 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)) context.lock() buffer = bufferPool.getBuffer(self._al_source) al.alBufferData(buffer, self._al_format, audio_data.data, audio_data.length, self.source_group.audio_format.sample_rate) if _debug_buffers: error = al.alGetError() if error != 0: print("BUFFER DATA ERROR: " + str(error)) al.alSourceQueueBuffers(self._al_source, 1, ctypes.byref(buffer)) if _debug_buffers: error = al.alGetError() if error != 0: print("QUEUE BUFFER ERROR: " + str(error)) 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()
def _update_play_cursor(self): if not self._al_source: return self._lock.acquire() context.lock() # Release spent buffers processed = al.ALint() al.alGetSourcei(self._al_source, al.AL_BUFFERS_PROCESSED, processed) processed = processed.value if processed: buffers = (al.ALuint * processed)() al.alSourceUnqueueBuffers(self._al_source, len(buffers), buffers) error = al.alGetError() if error != 0: if _debug_buffers: print ("Source unqueue error: " + str(error)) else: for b in buffers: bufferPool.dequeueBuffer(self._al_source, b) context.unlock() if processed: if len(self._buffer_timestamps) == processed and self._buffer_timestamps[-1] is not None: # Underrun, take note of timestamp. # We check that the timestamp is not None, because otherwise # our source could have been cleared. self._underrun_timestamp = self._buffer_timestamps[-1] + self._buffer_sizes[-1] / float( self.source_group.audio_format.bytes_per_second ) self._buffer_cursor += sum(self._buffer_sizes[:processed]) del self._buffer_sizes[:processed] del self._buffer_timestamps[:processed] if not context.have_1_1: self._buffer_system_time = time.time() # Update play cursor using buffer cursor + estimate into current # buffer if context.have_1_1: bytes = al.ALint() context.lock() al.alGetSourcei(self._al_source, al.AL_BYTE_OFFSET, bytes) context.unlock() if _debug: print "got bytes offset", bytes.value self._play_cursor = self._buffer_cursor + bytes.value else: # Interpolate system time past buffer timestamp self._play_cursor = self._buffer_cursor + int( (time.time() - self._buffer_system_time) * self.source_group.audio_format.bytes_per_second ) # Process events while self._events and self._events[0][0] < self._play_cursor: _, event = self._events.pop(0) event._sync_dispatch_to_player(self.player) self._lock.release()
def delete(self): if _debug: print 'OpenALAudioPlayer.delete()' if not self._al_source: return context.worker.remove(self) with self._lock: with context.lock: al.alDeleteSources(1, self._al_source) bufferPool.deleteSource(self._al_source) if _debug_buffers: error = al.alGetError() if error != 0: print("DELETE ERROR: " + str(error)) self._al_source = None
def delete(self): if _debug: print "OpenALAudioPlayer.delete()" if not self._al_source: return context.worker.remove(self) self._lock.acquire() context.lock() al.alDeleteSources(1, self._al_source) bufferPool.deleteSource(self._al_source) if _debug_buffers: error = al.alGetError() if error != 0: print ("DELETE ERROR: " + str(error)) context.unlock() self._al_source = None self._lock.release()
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
def _update_play_cursor(self): if not self._al_source: return self._lock.acquire() context.lock() # Release spent buffers processed = al.ALint() al.alGetSourcei(self._al_source, al.AL_BUFFERS_PROCESSED, processed) processed = processed.value if processed: buffers = (al.ALuint * processed)() al.alSourceUnqueueBuffers(self._al_source, len(buffers), buffers) error = al.alGetError() if error != 0: if _debug_buffers: print("Source unqueue error: " + str(error)) else: for b in buffers: bufferPool.dequeueBuffer(self._al_source, b) context.unlock() if processed: if (len(self._buffer_timestamps) == processed and self._buffer_timestamps[-1] is not None): # Underrun, take note of timestamp. # We check that the timestamp is not None, because otherwise # our source could have been cleared. self._underrun_timestamp = \ self._buffer_timestamps[-1] + \ self._buffer_sizes[-1] / \ float(self.source_group.audio_format.bytes_per_second) self._buffer_cursor += sum(self._buffer_sizes[:processed]) del self._buffer_sizes[:processed] del self._buffer_timestamps[:processed] if not context.have_1_1: self._buffer_system_time = time.time() # Update play cursor using buffer cursor + estimate into current # buffer if context.have_1_1: bytes = al.ALint() context.lock() al.alGetSourcei(self._al_source, al.AL_BYTE_OFFSET, bytes) context.unlock() if _debug: print 'got bytes offset', bytes.value self._play_cursor = self._buffer_cursor + bytes.value else: # Interpolate system time past buffer timestamp self._play_cursor = \ self._buffer_cursor + int( (time.time() - self._buffer_system_time) * \ self.source_group.audio_format.bytes_per_second) # Process events while self._events and self._events[0][0] < self._play_cursor: _, event = self._events.pop(0) event._sync_dispatch_to_player(self.player) self._lock.release()