<s> import ctypes <EOL> import heapq <EOL> import sys <EOL> import threading <EOL> import time <EOL> import Queue <EOL> import pyglet <EOL> _debug = pyglet . options [ '<STR_LIT>' ] <EOL> import mt_media <EOL> import lib_openal as al <EOL> import lib_alc as alc <EOL> class OpenALException ( mt_media . MediaException ) : <EOL> pass <EOL> def _split_nul_strings ( s ) : <EOL> nul = False <EOL> i = <NUM_LIT:0> <EOL> while True : <EOL> if s [ i ] == '<STR_LIT>' : <EOL> if nul : <EOL> break <EOL> else : <EOL> nul = True <EOL> else : <EOL> nul = False <EOL> i += <NUM_LIT:1> <EOL> s = s [ : i - <NUM_LIT:1> ] <EOL> return s . split ( '<STR_LIT>' ) <EOL> def get_extensions ( ) : <EOL> extensions = alc . alcGetString ( context . _device , alc . ALC_EXTENSIONS ) <EOL> if sys . platform == '<STR_LIT>' : <EOL> return ctypes . cast ( extensions , ctypes . c_char_p ) . value . split ( '<STR_LIT:U+0020>' ) <EOL> else : <EOL> return _split_nul_strings ( extensions ) <EOL> def have_extension ( extension ) : <EOL> return extension in get_extensions ( ) <EOL> format_map = { <EOL> ( <NUM_LIT:1> , <NUM_LIT:8> ) : al . AL_FORMAT_MONO8 , <EOL> ( <NUM_LIT:1> , <NUM_LIT:16> ) : al . AL_FORMAT_MONO16 , <EOL> ( <NUM_LIT:2> , <NUM_LIT:8> ) : al . AL_FORMAT_STEREO8 , <EOL> ( <NUM_LIT:2> , <NUM_LIT:16> ) : al . AL_FORMAT_STEREO16 , <EOL> } <EOL> class OpenALWorker ( mt_media . MediaThread ) : <EOL> _min_write_size = <NUM_LIT> <EOL> _nap_time = <NUM_LIT> <EOL> _sleep_time = None <EOL> def __init__ ( self ) : <EOL> super ( OpenALWorker , self ) . __init__ ( ) <EOL> self . players = set ( ) <EOL> def run ( self ) : <EOL> while True : <EOL> self . condition . acquire ( ) <EOL> if self . stopped : <EOL> self . condition . release ( ) <EOL> break <EOL> sleep_time = - <NUM_LIT:1> <EOL> if self . players : <EOL> player = None <EOL> write_size = <NUM_LIT:0> <EOL> for p in self . players : <EOL> s = p . get_write_size ( ) <EOL> if s > write_size : <EOL> player = p <EOL> write_size = s <EOL> if write_size > self . _min_write_size : <EOL> player . refill ( write_size ) <EOL> else : <EOL> sleep_time = self . _nap_time <EOL> else : <EOL> sleep_time = self . _sleep_time <EOL> self . condition . release ( ) <EOL> if sleep_time != - <NUM_LIT:1> : <EOL> self . sleep ( sleep_time ) <EOL> def add ( self , player ) : <EOL> self . condition . acquire ( ) <EOL> self . players . add ( player ) <EOL> self . condition . notify ( ) <EOL> self . condition . release ( ) <EOL> def remove ( self , player ) : <EOL> self . condition . acquire ( ) <EOL> self . players . remove ( player ) <EOL> self . condition . notify ( ) <EOL> self . condition . release ( ) <EOL> class OpenALAudioPlayer ( mt_media . AbstractAudioPlayer ) : <EOL> _min_buffer_size = <NUM_LIT> <EOL> _ideal_buffer_size = <NUM_LIT> <EOL> def __init__ ( self , source_group , player ) : <EOL> super ( OpenALAudioPlayer , self ) . __init__ ( source_group , player ) <EOL> audio_format = source_group . audio_format <EOL> try : <EOL> self . _al_format = format_map [ ( audio_format . channels , <EOL> audio_format . sample_size ) ] <EOL> except KeyError : <EOL> raise OpenALException ( '<STR_LIT>' ) <EOL> self . _al_source = al . ALuint ( ) <EOL> al . alGenSources ( <NUM_LIT:1> , self . _al_source ) <EOL> self . _lock = threading . RLock ( ) <EOL> self . _buffer_cursor = <NUM_LIT:0> <EOL> self . _play_cursor = <NUM_LIT:0> <EOL> self . _write_cursor = <NUM_LIT:0> <EOL> self . _buffer_sizes = [ ] <EOL> self . _buffer_timestamps = [ ] <EOL> self . _underrun_timestamp = None <EOL> self . _events = [ ] <EOL> self . _playing = False <EOL> self . _eos = False <EOL> if not context . have_1_1 : <EOL> self . _buffer_system_time = time . time ( ) <EOL> self . refill ( self . _ideal_buffer_size ) <EOL> def __del__ ( self ) : <EOL> try : <EOL> self . delete ( ) <EOL> except : <EOL> pass <EOL> def delete ( self ) : <EOL> return <EOL> context . lock ( ) <EOL> al . alDeleteSources ( <NUM_LIT:1> , self . _al_source ) <EOL> context . unlock ( ) <EOL> self . _al_source = None <EOL> def play ( self ) : <EOL> if self . _playing : <EOL> return <EOL> self . _playing = True <EOL> self . _al_play ( ) <EOL> if not context . have_1_1 : <EOL> self . _buffer_system_time = time . time ( ) <EOL> context . worker . add ( self ) <EOL> def _al_play ( self ) : <EOL> context . lock ( ) <EOL> state = al . ALint ( ) <EOL> al . alGetSourcei ( self . _al_source , al . AL_SOURCE_STATE , state ) <EOL> if state . value != al . AL_PLAYING : <EOL> al . alSourcePlay ( self . _al_source ) <EOL> context . unlock ( ) <EOL> def stop ( self ) : <EOL> if not self . _playing : <EOL> return <EOL> self . _pause_timestamp = self . get_time ( ) <EOL> context . lock ( ) <EOL> al . alSourcePause ( self . _al_source ) <EOL> context . unlock ( ) <EOL> self . _playing = False <EOL> context . worker . remove ( self ) <EOL> def clear ( self ) : <EOL> self . _lock . acquire ( ) <EOL> context . lock ( ) <EOL> al . alSourceStop ( self . _al_source ) <EOL> self . _playing = False <EOL> del self . _events [ : ] <EOL> self . _underrun_timestamp = None <EOL> self . _buffer_timestamps = [ None for _ in self . _buffer_timestamps ] <EOL> context . unlock ( ) <EOL> self . _lock . release ( ) <EOL> def _update_play_cursor ( self ) : <EOL> self . _lock . acquire ( ) <EOL> context . lock ( ) <EOL> processed = al . ALint ( ) <EOL> al . alGetSourcei ( self . _al_source , al . AL_BUFFERS_PROCESSED , processed ) <EOL> processed = processed . value <EOL> if processed : <EOL> buffers = ( al . ALuint * processed ) ( ) <EOL> al . alSourceUnqueueBuffers ( self . _al_source , len ( buffers ) , buffers ) <EOL> al . alDeleteBuffers ( len ( buffers ) , buffers ) <EOL> context . unlock ( ) <EOL> if processed : <EOL> if len ( self . _buffer_timestamps ) == processed : <EOL> self . _underrun_timestamp = self . _buffer_timestamps [ - <NUM_LIT:1> ] + self . _buffer_sizes [ - <NUM_LIT:1> ] / float ( self . source_group . audio_format . bytes_per_second ) <EOL> self . _buffer_cursor += sum ( self . _buffer_sizes [ : processed ] ) <EOL> del self . _buffer_sizes [ : processed ] <EOL> del self . _buffer_timestamps [ : processed ] <EOL> if not context . have_1_1 : <EOL> self . _buffer_system_time = time . time ( ) <EOL> if context . have_1_1 : <EOL> bytes = al . ALint ( ) <EOL> context . lock ( ) <EOL> al . alGetSourcei ( self . _al_source , al . AL_BYTE_OFFSET , bytes ) <EOL> context . unlock ( ) <EOL> if _debug : <EOL> print '<STR_LIT>' , bytes . value <EOL> self . _play_cursor = self . _buffer_cursor + bytes . value <EOL> else : <EOL> self . _play_cursor = self . _buffer_cursor + int ( <EOL> ( time . time ( ) - self . _buffer_system_time ) * self . source_group . audio_format . bytes_per_second ) <EOL> while self . _events and self . _events [ <NUM_LIT:0> ] [ <NUM_LIT:0> ] < self . _play_cursor : <EOL> _ , event = self . _events . pop ( <NUM_LIT:0> ) <EOL> event . _sync_dispatch_to_player ( self . player ) <EOL> self . _lock . release ( ) <EOL> def get_write_size ( self ) : <EOL> self . _lock . acquire ( ) <EOL> self . _update_play_cursor ( ) <EOL> write_size = self . _ideal_buffer_size - ( self . _write_cursor - self . _play_cursor ) <EOL> if self . _eos : <EOL> write_size = <NUM_LIT:0> <EOL> self . _lock . release ( ) <EOL> return write_size <EOL> def refill ( self , write_size ) : <EOL> if _debug : <EOL> print '<STR_LIT>' , write_size <EOL> self . _lock . acquire ( ) <EOL> while write_size > self . _min_buffer_size : <EOL> audio_data = self . source_group . get_audio_data ( write_size ) <EOL> if not audio_data : <EOL> self . _eos = True <EOL> self . _events . append ( <EOL> ( self . _write_cursor , mt_media . MediaEvent ( <NUM_LIT:0> , '<STR_LIT>' ) ) ) <EOL> self . _events . append ( <EOL> ( self . _write_cursor , <EOL> mt_media . MediaEvent ( <NUM_LIT:0> , '<STR_LIT>' ) ) ) <EOL> break <EOL> for event in audio_data . events : <EOL> cursor = self . _write_cursor + event . timestamp * self . source_group . audio_format . bytes_per_second <EOL> self . _events . append ( ( cursor , event ) ) <EOL> buffer = al . ALuint ( ) <EOL> context . lock ( ) <EOL> al . alGenBuffers ( <NUM_LIT:1> , buffer ) <EOL> al . alBufferData ( buffer , <EOL> self . _al_format , <EOL> audio_data . data , <EOL> audio_data . length , <EOL> self . source_group . audio_format . sample_rate ) <EOL> al . alSourceQueueBuffers ( self . _al_source , <NUM_LIT:1> , ctypes . byref ( buffer ) ) <EOL> context . unlock ( ) <EOL> self . _write_cursor += audio_data . length <EOL> self . _buffer_sizes . append ( audio_data . length ) <EOL> self . _buffer_timestamps . append ( audio_data . timestamp ) <EOL> write_size -= audio_data . length <EOL> if self . _playing : <EOL> state = al . ALint ( ) <EOL> context . lock ( ) <EOL> al . alGetSourcei ( self . _al_source , al . AL_SOURCE_STATE , state ) <EOL> if state . value != al . AL_PLAYING : <EOL> if _debug : <EOL> print '<STR_LIT>' <EOL> al . alSourcePlay ( self . _al_source ) <EOL> context . unlock ( ) <EOL> self . _lock . release ( ) <EOL> def get_time ( self ) : <EOL> try : <EOL> buffer_timestamp = self . _buffer_timestamps [ <NUM_LIT:0> ] <EOL> except IndexError : <EOL> return self . _underrun_timestamp <EOL> if buffer_timestamp is None : <EOL> return None <EOL> return buffer_timestamp + ( self . _play_cursor - self . _buffer_cursor ) / float ( self . source_group . audio_format . bytes_per_second ) <EOL> def set_volume ( self , volume ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_GAIN , max ( <NUM_LIT:0> , volume ) ) <EOL> context . unlock ( ) <EOL> def set_position ( self , position ) : <EOL> x , y , z = position <EOL> context . lock ( ) <EOL> al . alSource3f ( self . _al_source , al . AL_POSITION , x , y , z ) <EOL> context . unlock ( ) <EOL> def set_min_distance ( self , min_distance ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_REFERENCE_DISTANCE , min_distance ) <EOL> context . unlock ( ) <EOL> def set_max_distance ( self , max_distance ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_MAX_DISTANCE , max_distance ) <EOL> context . unlock ( ) <EOL> def set_pitch ( self , pitch ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_PITCH , max ( <NUM_LIT:0> , pitch ) ) <EOL> context . unlock ( ) <EOL> def set_cone_orientation ( self , cone_orientation ) : <EOL> x , y , z = cone_orientation <EOL> context . lock ( ) <EOL> al . alSource3f ( self . _al_source , al . AL_DIRECTION , x , y , z ) <EOL> context . unlock ( ) <EOL> def set_cone_inner_angle ( self , cone_inner_angle ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_CONE_INNER_ANGLE , cone_inner_angle ) <EOL> context . unlock ( ) <EOL> def set_cone_outer_angle ( self , cone_outer_angle ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_CONE_OUTER_ANGLE , cone_outer_angle ) <EOL> context . unlock ( ) <EOL> def set_cone_outer_gain ( self , cone_outer_gain ) : <EOL> context . lock ( ) <EOL> al . alSourcef ( self . _al_source , al . AL_CONE_OUTER_GAIN , cone_outer_gain ) <EOL> context . unlock ( ) <EOL> class OpenALDriver ( mt_media . AbstractAudioDriver ) : <EOL> def __init__ ( self , device_name = None ) : <EOL> super ( OpenALDriver , self ) . __init__ ( ) <EOL> self . _device = alc . alcOpenDevice ( device_name ) <EOL> if not self . _device : <EOL> raise Exception ( '<STR_LIT>' ) <EOL> alcontext = alc . alcCreateContext ( self . _device , None ) <EOL> alc . alcMakeContextCurrent ( alcontext ) <EOL> self . have_1_1 = self . have_version ( <NUM_LIT:1> , <NUM_LIT:1> ) and False <EOL> self . _lock = threading . Lock ( ) <EOL> self . worker = OpenALWorker ( ) <EOL> self . worker . start ( ) <EOL> def create_audio_player ( self , source_group , player ) : <EOL> return OpenALAudioPlayer ( source_group , player ) <EOL> def delete ( self ) : <EOL> self . worker . stop ( ) <EOL> def lock ( self ) : <EOL> self . _lock . acquire ( ) <EOL> def unlock ( self ) : <EOL> self . _lock . release ( ) <EOL> def have_version ( self , major , minor ) : <EOL> return ( major , minor ) <= self . get_version ( ) <EOL> def get_version ( self ) : <EOL> major = alc . ALCint ( ) <EOL> minor = alc . ALCint ( ) <EOL> alc . alcGetIntegerv ( self . _device , alc . ALC_MAJOR_VERSION , <EOL> ctypes . sizeof ( major ) , major ) <EOL> alc . alcGetIntegerv ( self . _device , alc . ALC_MINOR_VERSION , <EOL> ctypes . sizeof ( minor ) , minor ) <EOL> return major . value , minor . value <EOL> def _set_volume ( self , volume ) : <EOL> self . lock ( ) <EOL> al . alListenerf ( al . AL_GAIN , volume ) <EOL> self . unlock ( ) <EOL> self . _volume = volume <EOL> def _set_position ( self , position ) : <EOL> x , y , z = position <EOL> self . lock ( ) <EOL> al . alListener3f ( al . AL_POSITION , x , y , z ) <EOL> self . unlock ( ) <EOL> self . _position = position <EOL> def _set_forward_orientation ( self , orientation ) : <EOL> val = ( al . ALfloat * <NUM_LIT:6> ) ( * ( orientation + self . _up_orientation ) ) <EOL> self . lock ( ) <EOL> al . alListenerfv ( al . AL_ORIENTATION , val ) <EOL> self . unlock ( ) <EOL> self . _forward_orientation = orientation <EOL> def _set_up_orientation ( self , orientation ) : <EOL> val = ( al . ALfloat * <NUM_LIT:6> ) ( * ( self . _forward_orientation + orientation ) ) <EOL> self . lock ( ) <EOL> al . alListenerfv ( al . AL_ORIENTATION , val ) <EOL> self . unlock ( ) <EOL> self . _up_orientation = orientation <EOL> context = None <EOL> def create_audio_driver ( device_name = None ) : <EOL> global context <EOL> context = OpenALDriver ( device_name ) <EOL> if _debug : <EOL> print '<STR_LIT>' , context . get_version ( ) <EOL> return context </s>
