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 refill(self, write_size): 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 self.unlock()
def _worker_func(self): thread = self._thread #buffered_time = 0 eos = False events = self._events while True: with thread.condition: if thread.stopped or (eos and not events): break # Use up "buffered" audio based on amount of time passed. timestamp = self.get_time() if _debug: print 'timestamp: %r' % timestamp # Dispatch events while events and timestamp is not None: if (events[0].timestamp is None or events[0].timestamp <= timestamp): events[0]._sync_dispatch_to_player(self.player) del events[0] else: break # Calculate how much data to request from source secs = self._buffer_time - self._packets_duration bytes = secs * self.source_group.audio_format.bytes_per_second if _debug: print 'Trying to buffer %d bytes (%r secs)' % (bytes, secs) while bytes > self._min_update_bytes and not eos: # Pull audio data from source audio_data = self.source_group.get_audio_data(int(bytes)) if not audio_data and not eos: events.append(MediaEvent(timestamp, 'on_eos')) events.append( MediaEvent(timestamp, 'on_source_group_eos')) eos = True break # Pretend to buffer audio data, collect events. if self._playing and not self._packets: self._timestamp_time = time.time() self._packets.append( SilentAudioPacket(audio_data.timestamp, audio_data.duration)) self._packets_duration += audio_data.duration for event in audio_data.events: event.timestamp += audio_data.timestamp events.append(event) events.extend(audio_data.events) bytes -= audio_data.length sleep_time = self._sleep_time if not self._playing: sleep_time = None elif events and events[0].timestamp and timestamp: sleep_time = min(sleep_time, events[0].timestamp - timestamp) if _debug: print 'SilentAudioPlayer(Worker).sleep', sleep_time thread.sleep(sleep_time)