package Ġcom . so y wiz . kor au . sound Ċ Ċ import Ġandroid . annotation .* Ċ import Ġandroid . content .* Ċ import Ġandroid . media .* Ċ import Ġandroid . media . Audio Format Ċ import Ġandroid . os .* Ċ import Ġcom . so y wiz . k ds .* Ċ import Ġcom . so y wiz . k lock .* Ċ import Ġcom . so y wiz . k logger .* Ċ import Ġcom . so y wiz . kor au . format .* Ċ import Ġcom . so y wiz . kor au . format . mp 3 .* Ċ import Ġcom . so y wiz . kor io . android .* Ċ import Ġcom . so y wiz . kor io . async .* Ċ import Ġkotlin . coroutines .* Ċ Ċ actual Ġval Ġnative Sound Provider : ĠNative Sound Provider Ġby Ġlazy Ġ{ ĠAndroid Native Sound Provider () Ġ} Ċ Ċ class ĠAndroid Native Sound Provider Ġ: ĠNative Sound Provider () Ġ{ ĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġval ĠMAX _ CHANNEL S Ġ= Ġ 1 6 ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġval Ġtarget : ĠString Ġ= Ġ" android " ĊĊĠĠĠ Ġoverride Ġval Ġaudio Formats : ĠAudio Formats Ġ= ĠAudio Formats ( MP 3 Decoder ) Ġ+ Ġdefault Audio Formats ĊĊĠĠĠ Ġprivate Ġvar Ġaudio Manager : ĠAudio Manager ? Ġ= Ġnull ĊĠĠĠ Ġval Ġaudio SessionId Ġby Ġlazy Ġ{ Ġaudio Manager !!. generate Audio SessionId () Ġ} ĊĠĠĠ Ġ// val Ġaudio SessionId Ġget () Ġ= Ġaudio Manager !!. generate Audio SessionId () ĊĊĠĠĠ Ġprivate Ġval Ġthread Pool Ġ= ĠPool Ġ{ Ġid Ġ-> ĊĠĠĠĠĠĠĠ Ġ// Console . info (" Creating ĠAudio Thread [$ id ]") ĊĠĠĠĠĠĠĠ ĠAudio Thread ( this , Ġid Ġ= Ġid ). also Ġ{ Ġit . is Daemon Ġ= Ġtrue Ġ}. also Ġ{ Ġit . start () Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġclass ĠAudio Thread ( val Ġprovider : ĠAndroid Native Sound Provider , Ġvar Ġfreq : ĠInt Ġ= Ġ 4 4 1 0 0 , Ġval Ġid : ĠInt Ġ= Ġ- 1 ) Ġ: ĠThread () Ġ{ ĊĠĠĠĠĠĠĠ Ġvar Ġprops : ĠSound Props Ġ= ĠDummy Sound Props ĊĠĠĠĠĠĠĠ Ġval Ġdeque Ġ= ĠAudio Samples Deque ( 2 ) ĊĠĠĠĠĠĠĠ Ġ@ Volatile ĊĠĠĠĠĠĠĠ Ġvar Ġrunning Ġ= Ġtrue ĊĊĠĠĠĠĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthis . is Daemon Ġ= Ġtrue ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġoverride Ġfun Ġrun () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġbuffer Samples Ġ= Ġ 4 0 9 6 ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġat Ġ= Ġif Ġ( android . os . Build . VERSION . SDK _ INT Ġ>= Ġandroid . os . Build . VERSION _ CODES . LO L LI POP ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Track ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Attributes . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Usage ( Audio Attributes . USAGE _ GAME ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// . set ContentType ( Audio Attributes . CONTENT _ TYPE _ M US IC ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set ContentType ( Audio Attributes . CONTENT _ TYPE _ UNKNOWN ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Format . Builder () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Channel Mask ( Audio Format . CHANNEL _ IN _ STER EO ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Sample Rate ( freq ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Encoding ( Audio Format . ENCODING _ PCM _ 1 6 BIT ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. build (), ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 2 Ġ* Ġ 2 Ġ* Ġbuffer Samples , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Track . MODE _ STREAM , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġprovider . audio SessionId ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ@ Suppress (" DE PREC ATION ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Track ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Manager . STREAM _ M US IC , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfreq , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Format . CHANNEL _ OUT _ STER EO , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Format . ENCODING _ PCM _ 1 6 BIT , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ 2 Ġ* Ġ 2 Ġ* Ġbuffer Samples , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAudio Track . MODE _ STREAM ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( at . state Ġ== ĠAudio Track . STATE _ UN INITIAL IZED ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠSystem . err . println (" Audio Ġtrack Ġwas Ġnot Ġinitialized Ġcorrectly Ġfreq =$ freq , Ġbuffer Samples =$ buffer Samples ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// if Ġ( at . state Ġ== ĠAudio Track . STATE _ INITIAL IZED ) Ġat . play () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( running ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtemp Ġ= ĠAudio Samples Inter leaved ( 2 , Ġbuffer Samples ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// val Ġtemp Empty Ġ= ĠShort Array ( 1 0 2 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġpaused Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( running ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġread Count Ġ= Ġdeque . read ( temp ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( at . state Ġ== ĠAudio Track . STATE _ UN INITIAL IZED ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠThread . sleep ( 5 0 L ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontinue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( read Count Ġ> Ġ 0 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( paused ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// println ("[ K OR AU ] ĠResume Ġ$ id ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpaused Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . play () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// println (" AUDIO ĠCH UNK : Ġ$ read Count Ġ: Ġ${ temp . data . toList () }") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( at . state Ġ== ĠAudio Track . STATE _ INITIAL IZED ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . playback Rate Ġ= Ġfreq ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( Build . VERSION . SDK _ INT Ġ>= ĠBuild . VERSION _ CODES . M ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . playback Params . speed Ġ= Ġprops . pitch . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġvol Ġ= Ġprops . volume . toFloat () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( android . os . Build . VERSION . SDK _ INT Ġ>= Ġandroid . os . Build . VERSION _ CODES . LO L LI POP ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . set Volume ( vol ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ@ Suppress (" DE PREC ATION ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . set Ster eo Volume ( vol , Ġvol ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . write ( temp . data , Ġ 0 , Ġread Count Ġ* Ġ 2 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// at . write ( temp Empty , Ġ 0 , Ġtemp Empty . size ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! paused ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// println ("[ K OR AU ] ĠStop Ġ$ id ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// at . flush () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . stop () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpaused Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠThread . sleep ( 2 L ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġe . printStackTrace () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ// println ("[ K OR AU ] ĠCompleted Ġ$ id ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġat . stop () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠThrowable ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġe . printStackTrace () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġat . release () ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġensure Audio Manager ( coroutine Context : ĠCor outine Context ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( audio Manager Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġctx Ġ= Ġcoroutine Context [ Android Coroutine Context . Key ]?. context Ġ?: Ġerror (" Can 't Ġfind Ġthe ĠAndroid ĠContext Ġon Ġthe ĠCor outine Context . ĠMust Ġcall Ġwith Android Context Ġfirst ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġaudio Manager Ġ= Ġctx . getSystem Service ( Context . AUDIO _ SERVICE ) Ġas ĠAudio Manager ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġoverride Ġfun Ġcreate Audio Stream ( coroutine Context : ĠCor outine Context , Ġfreq : ĠInt ): ĠPlatform Audio Output Ġ{ ĊĠĠĠĠĠĠĠ Ġensure Audio Manager ( coroutine Context ) ĊĊĠĠĠĠĠĠĠ Ġreturn Ġobject Ġ: ĠPlatform Audio Output ( coroutine Context , Ġfreq ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġstarted Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġvar Ġthread : ĠAudio Thread ? Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġprivate Ġval Ġthread Deque Ġget () Ġ= Ġthread ?. deque ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġval Ġavailable Samples : ĠInt Ġget () Ġ= Ġthread Deque ?. available Read Ġ?: Ġ 0 ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġsuspend Ġfun Ġadd ( samples : ĠAudio Samples , Ġoffset : ĠInt , Ġsize : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( thread Ġ== Ġnull ) Ġdelay ( 1 0 . milliseconds ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread Deque !!. write ( samples , Ġoffset , Ġsize ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġstart (): ĠUnit Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( started ) Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstarted Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlaunch Immediate ly ( coroutine Context ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwhile Ġ( thread Pool . total Items InUse Ġ>= ĠMAX _ CHANNEL S ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelay ( 1 0 . milliseconds ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread Ġ= Ġthread Pool . alloc () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread ?. props Ġ= Ġthis ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread ?. freq Ġ= Ġfreq ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread Deque ?. clear () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġstop () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! started ) Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstarted Ġ= Ġfalse ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( thread Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread Pool . free ( thread !! ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthread Ġ= Ġnull ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ