Status_t audioflinger: playbackthread: Track: Start () {status_t status = no_error; logv ("START (% d), calling thread % d session % d", mname, ipcthreadstate: Self ()-> getcallingpid (), msessionid); // mthread is assigned a value in the audioflinger: threadbase: trackbase constructor // The value is calculated by audioflinger :: playbackthread: track passed to its parent class threadbase // function audioflinger: playbackthread: createtrack_l created audioflinger: playbackthread: track object/ /The parameter corresponding to the thread is its own this pointer // function audioflinger: The playbackthread subclass mixerthread object is created in openoutput, // Add it and an ID to mplaybackthreads. // The thread-> ID () used below is the ID here. // However, when thread-> ID () is used below, it is actually used as an output. // What is the relationship between ID and output? // The answer is found in the audioflinger: openoutput function. When the audioflinger: openoutput function is called to open an output, the returned value is actually the ID of the thread mentioned above. // Audiopolicymanagerbase stores this ID and an audiooutputdescriptor object as a pair in moutputs. Sp <threadbase> thread = mthread. Promote (); If (thread! = 0) {mutex: autolock _ L (thread-> mlock); int state = mstate; // here the track cocould be either new, or restarted // in both cases "unstop" the track if (mstate = paused) {mstate = trackbase: resuming; logv ("paused => resuming (% d) on thread % P ", mname, this);} else {mstate = trackbase: active; logv ("? => Active (% d) on thread % P ", mname, this);} If (! Isoutputtrack () & state! = Active & state! = Resuming) {thread-> mlock. Unlock (); // The following thread-> ID () corresponds to the output obtained by calling the audiopolicyservice: openoutput function. // The Implementation of the function audiosystem: startoutput directly calls the function audiopolicyservice: startoutput // The function audiopolicyservice: startoutput is to call the function audiopolicymanagerbase: startoutput status = audiosystem :: startoutput (thread-> ID (), (audiosystem: stream_type) mstreamtype, msessionid); thread-> mlock. lock ();} If (status = no_error) {playbackthread * playbackthread = (playbackthread *) thread. get (); playbackthread-> addtrack_l (T His);} else {mstate = State;} else {status = bad_value;} return status;} status_t audiopolicymanagerbase: startoutput (audio_io_handle_t output, audiosystem: stream_type stream, int session) {logv ("startoutput () Output % d, stream % d, session % d", output, stream, session); ssize_t Index = moutputs. indexofkey (output); If (index <0) {logw ("startoutput () unknow output % d", output); Return bad_v Alue;} // origin of the object: // function audiopolicymanagerbase: audiopolicymanagerbase opens the output corresponding to device_out_speaker, and assigns it to the member variable mhardwareoutput of audiopolicymanagerbase. // Create an audiooutputdescriptor object (outputdesc) for the output, and add mhardwareoutput and outputdesc as one pair to moutputs. // Call the setoutputdevice function to set the default output device to device_out_speaker: setoutputdevice (mhardwareoutput, (uint32_t) audiosystem: device_out_speaker, true). // Function Identifier: getoutput, if an output is opened, an audiooutputdescriptor object is created for it and added to moutputs. // Find the corresponding audiooutputdescriptor object based on output. // The audiooutputdescriptor object is created in audiopolicymanagerbase's constructor or function audiopolicymanagerbase: getoutput and added to moutputs as a pair with output. Audiooutputdescriptor * outputdesc = moutputs. valueat (INDEX); routing_strategy strategy = getstrategy (audiosystem: stream_type) stream); # ifdef with_a2dp if (ma2dpoutput! = 0 &&! A2dpusedforsonification () & Strategy = strategy_sonification) {setstrategymute (strategy_media, true, ma2dpoutput);} # endif // incremenent usage count for this stream on the requested output: // note that the usage count is the same for duplicated output and hardware output which is // necassary for a correct control of hardware output routing by startoutput () and stopoutput () // audiooutputdescri The ptor object contains an array that stores the Count of each stream in the output. // The Count outputdesc-> changerefcount (stream, 1) is used in the getnewdevice function ); // for the implementation of the getnewdevice function, see the following code // setoutputdevice function implementation. The setoutputdevice (output, getnewdevice (output) is also analyzed later )); // handle special case for sonification while in call if (isincall () {// This is a special handling of the sonification policy when a call is made. // If the stream is low-visibility, the stream mute will be dropped. // otherwise, starttone handleincallsonification (stream, true, false );} // apply volume rules for current stream and device if necessary // The Implementation of The checkandsetvolume function is shown later in the checkandsetvolume (stream, mstreams [stream]. mindexcur, output, outputdesc-> device (); Return no_error;} // find a device for output. // The priority of strategy involved in the function is the priority of the device corresponding to strategy for the output. Uint32_t audiopolicymanagerbase: getnewdevice (audio_io_handle_t output, bool fromcache) {uint32_t device = 0; audiooutputdescriptor * outputdesc = moutputs. valuefor (output); // check the following by order of priority to request a routing change if necessary: // 1: we are in call or the strategy phone is active on the hardware output: // use device for strategy phone // 2: The Strategy sonification Is active on the hardware output: // use device for strategy sonification // 3: The Strategy media is active on the hardware output: // use device for strategy media // 4: the Strategy DTMF is active on the hardware output: // use device for strategy DTMF // the function of isincall is used to determine whether the current status is called by phone, or if (isincall () | // The isusedbystrategy function is used to return the reference sum of all streams corresponding to the specified strategy in the output. // Simply, determine whether the specified strategy is used in the output. Outputdesc-> strategy (strategy_phone) {Device = getdeviceforstrategy (strategy_phone, fromcache);} else if (outputdesc-> strategy (strategy_sonification) {Device = strategy (strategy_sonification, fromcache);} else if (outputdesc-> isusedbystrategy (strategy_media) {Device = getdeviceforstrategy (strategy_media, fromcache);} else if (outputdesc-> isusedbystrategy (strate Gy_dtmf) {Device = getdeviceforstrategy (strategy_dtmf, fromcache);} logv ("getnewdevice () selected device % x", device); return device;} void audiopolicymanagerbase :: setoutputdevice (audio_io_handle_t output, uint32_t device, bool force, int delayms) {logv ("setoutputdevice () Output % d device % x delayms % d", output, device, delayms ); audiooutputdescriptor * outputdesc = moutputs. valuefor (output); If (Outputdesc-> isduplicated () {setoutputdevice (outputdesc-> moutput1-> mid, device, force, delayms); setoutputdevice (outputdesc-> moutput2-> mid, device, force, delayms); Return ;}# ifdef with_a2dp // filter devices according to output selected if (output = ma2dpoutput) {Device & = audiosystem: device_out_all_a2dp;} else {Device & = ~ Audiosystem: Member ;}# endif // Function Device returns its member variable mdevice // The mdevice's constructor or function audiopolicymanagerbase: getoutput is assigned uint32_t prevdevice = (uint32_t) outputdesc-> device (); // do not change the routing if: //-The requestede device is 0 //-the requested device is the same as current device and force is not specified. // doing this check here allows the caller Call setoutputdevice () without conditions // if the available device only has headphones, you are listening to the songs. If a call is made, the device you find is also a headset, // so there is no route switch, but we need to stop the music when making a call. This process is not here if (device = 0 | device = prevdevice) &&! Force) {logv ("setoutputdevice () setting same device % x or null device for output % d", device, output); Return ;}outputdesc-> mdevice = device; // mute media streams if both speaker and headset are selected if (output = mhardwareoutput & audiosystem: popcount (device) = 2) {setstrategymute (strategy_media, true, output); // wait for the PCM output buffers to empty before proceeding with the rest Of the command usleep (outputdesc-> mlatency x 2*1000);} // do the routing audioparameter Param = audioparameter (); Param. addint (string8 (audioparameter: keyrouting), (INT) device); // if you change the route, the set function in alsacontrol is used to set the switch or widget of codec. Mpclientinterface-> setparameters (mhardwareoutput, Param. tostring (), delayms); // update stream volumes according to new device // you can specify the volume of each stream on the device. // You can traverse each stream, call the checkandsetvolume function to set the volume of each stream stored by the audiooutputdescriptor. // The Implementation of The checkandsetvolume function is described later in applystreamvolumes (output, device, delayms ); // If changing from a combined headset + speaker route, unmute media streams if (o Utput = mhardwareoutput & audiosystem: popcount (prevdevice) = 2) {setstrategymute (strategy_media, false, output, delayms) ;}} status_t volume: checkandsetvolume (INT stream, int index, audio_io_handle_t output, uint32_t device, int delayms, bool force) {// do not change actual stream volume if the stream is muted if (moutputs. valuefor (output)-> mmutecount [stream]! = 0) {logv ("checkandsetvolume () stream % d muted count % d", stream, moutputs. valuefor (output)-> mmutecount [stream]); Return no_error;} // do not change in call volume if Bluetooth is connected and vice versa if (Stream = audiosystem :: voice_call & mforceuse [audiosystem: for_communication] = audiosystem: force_bt_sco) | (Stream = audiosystem: effecth_sco & mforceuse [audiosystem: for_communic Ation]! = Audiosystem: force_bt_sco) {logv ("checkandsetvolume () cannot set stream % d volume with force use = % d for comm", stream, mforceuse [audiosystem :: for_communication]); Return invalid_operation;} float volume = computevolume (stream, index, output, device); // we actually change the volume if: //-the float value returned by computevolume () changed //-the force flag is set if (volume! = Moutputs. valuefor (output)-> mcurvolume [stream] | force) {moutputs. valuefor (output)-> mcurvolume [stream] = volume; logv ("setstreamvolume () for output % d stream % d, volume % F, delay % d", output, stream, volume, delayms); If (Stream = audiosystem: voice_call | stream = audiosystem: DTMF | stream = audiosystem: bluetooth_sco) {// offset value to reflect actual hardware volume that never reaches 0 // 1% corresponds roughly to first step in voice_call stream volume setting (see audioservice. java) volume = 0.01 + 0.99 * volume;} mpclientinterface-> setstreamvolume (audiosystem: stream_type) stream, volume, output, delayms);} If (Stream = audiosystem :: voice_call | stream = audiosystem: effecth_sco) {float voicevolume; // force voice volume to Max for Bluetooth SCO as volume is managed By the headset if (Stream = audiosystem: voice_call) {voicevolume = (float) index/(float) mstreams [stream]. mindexmax ;}else {voicevolume = 1.0;} If (voicevolume! = Volume & Output = mhardwareoutput) {mpclientinterface-> setvoicevolume (voicevolume, delayms); volume = voicevolume ;}} return no_error;} float volume: computevolume (INT stream, int index, audio_io_handle_t output, uint32_t device) {float volume = 1.0; audiooutputdescriptor * outputdesc = moutputs. valuefor (output); streamdescriptor & streamdesc = mstreams [stream ]; If (device = 0) {Device = outputdesc-> device ();} int volint = (100 * (index-streamdesc. mindexmin)/(streamdesc. mindexmax-streamdesc. mindexmin); volume = audiosystem: lineartolog (volint); // If a headset is connected, apply the following rules to ring tones and notifications // to avoid sound level bursts in user's ears: //-always attenuate ring tones and restrictions volume by 6db/ /-If music is playing, always limit the volume to current Music volume, // with a minimum threshold at-36db so that notification is always perceived. if (Device & (audiosystem: device_out_effecth_a2dp | audiosystem: audio | audiosystem: device_out_wired_headphone) & (getstrategy (audiosystem: stream_type) stream) = Str Ategy_sonification) | (Stream = audiosystem: System) & streamdesc. mcanbemuted) {VOLUME * = sonification_headset_volume_factor; // when the phone is ringing we must consider that music cocould have been paused just before // by the music application and behave as if music was active if the last music track was // just stopped if (outputdesc-> mrefcount [audiosystem:: Music] | mlimitringtonevolume) {Float musicvol = computevolume (audiosystem: Music, mstreams [audiosystem: Music]. mindexcur, output, device); float minvol = (musicvol> sonification_headset_volume_min )? Musicvol: sonification_headset_volume_min; If (volume> minvol) {volume = minvol; logv ("computevolume limiting volume to % F musicvol % F", minvol, musicvol );}}} return volume ;}
1. The priority between strategy takes effect only when different strategy can find different devices.
For example, when listening to music, the speaker is used. At this time, a call is made and another device is used. In this case, you need to change the route.
If you are on a phone call and turn on the music, the device used is actually the device used by phone strategy.
When a call is made, the playing music is stopped or mute, And the native code does not seem to process it.
2. The volume of each stream is not prioritized in native.
The volume of strategy_sonification and system stream will be processed only when the headset is connected.