/* LGE_CHANGE_E [email protected] 2010.01.27 */ 
status_t AudioPolicyManagerALSA::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream)
{
        LOGV("stopOutput() output %d, stream %d", output, stream);
        ssize_t index = mOutputs.indexOfKey(output);
        if (index < 0) {
        LOGW("stopOutput() unknow output %d", output);
        return BAD_VALUE;
        }
        AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
        routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);

        // handle special case for sonification while in call
        if (mPhoneState == AudioSystem::MODE_IN_CALL) {
        handleIncallSonification(stream, false, false);
        }
        if (outputDesc->isUsedByStrategy(strategy)) {
        // decrement usage count of this stream on the output
        outputDesc->changeRefCount(stream, -1);
        if (!outputDesc->isUsedByStrategy(strategy)) {
        // if the stream is the last of its strategy to use this output, change routing
        // in the following order or priority:
        // PHONE > SONIFICATION > MEDIA > DTMF
        uint32_t newDevice = 0;
        if (outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
            newDevice = getDeviceForStrategy(STRATEGY_PHONE);
        } else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
            newDevice = getDeviceForStrategy(STRATEGY_SONIFICATION);
        } else if (mPhoneState == AudioSystem::MODE_IN_CALL) {
            newDevice = getDeviceForStrategy(STRATEGY_PHONE);
        } else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
            newDevice = getDeviceForStrategy(STRATEGY_MEDIA);
        } else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
            newDevice = getDeviceForStrategy(STRATEGY_DTMF);
        }
              // apply routing change if necessary.
              // insert a delay of 2 times the audio hardware latency to ensure PCM
              // buffers in audio flinger and audio hardware are emptied before the
              // routing change is executed.
              setOutputDevice(mHardwareOutput, newDevice, false, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
        }
        // store time at which the last music track was stopped - see computeVolume()
	   if (stream == AudioSystem::MUSIC) {
               mMusicStopTime = systemTime();
           }
           return NO_ERROR;
           } else {
              LOGW("stopOutput() refcount is already 0 for output %d", output);
              return INVALID_OPERATION;
       }
}
void AudioPolicyManager::setPhoneState(int state) {
    ALOGV("setPhoneState() state %d", state);
    audio_devices_t newDevice = AUDIO_DEVICE_NONE;
    if (state < 0 || state >= AudioSystem::NUM_MODES) {
        ALOGW("setPhoneState() invalid state %d", state);
        return;
    }

    if (state == mPhoneState) {
        ALOGW("setPhoneState() setting same state %d", state);
        return;
    }

    // if leaving call state, handle special case of active streams
    // pertaining to sonification strategy see handleIncallSonification()
    if (isInCall()) {
        ALOGV("setPhoneState() in call state management: new state is %d", state);
        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
            handleIncallSonification(stream, false, true);
        }
    }

    // store previous phone state for management of sonification strategy below
    int oldState = mPhoneState;
    mPhoneState = state;
    bool force = false;

    // are we entering or starting a call
    if (!isStateInCall(oldState) && isStateInCall(state)) {
        ALOGV("  Entering call in setPhoneState()");
        // force routing command to audio hardware when starting a call
        // even if no device change is needed
        force = true;
    } else if (isStateInCall(oldState) && !isStateInCall(state)) {
        ALOGV("  Exiting call in setPhoneState()");
        // force routing command to audio hardware when exiting a call
        // even if no device change is needed
        force = true;
    } else if (isStateInCall(state) && (state != oldState)) {
        ALOGV("  Switching between telephony and VoIP in setPhoneState()");
        // force routing command to audio hardware when switching between telephony and VoIP
        // even if no device change is needed
        force = true;
    }

    // check for device and output changes triggered by new phone state
    newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
    checkA2dpSuspend();
    checkOutputForAllStrategies();
    updateDevicesAndOutputs();

    AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);

    // force routing command to audio hardware when ending call
    // even if no device change is needed
    if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
        newDevice = hwOutputDesc->device();
    }

    // when changing from ring tone to in call mode, mute the ringing tone
    // immediately and delay the route change to avoid sending the ring tone
    // tail into the earpiece or headset.
    int delayMs = 0;
    if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) {
        // delay the device change command by twice the output latency to have some margin
        // and be sure that audio buffers not yet affected by the mute are out when
        // we actually apply the route change
        delayMs = hwOutputDesc->mLatency*2;
        setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
    }

    if (isStateInCall(state)) {
        for (size_t i = 0; i < mOutputs.size(); i++) {
            AudioOutputDescriptor *desc = mOutputs.valueAt(i);
            //take the biggest latency for all outputs
            if (delayMs < desc->mLatency*2) {
                delayMs = desc->mLatency*2;
            }
            //mute STRATEGY_MEDIA on all outputs
            if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) {
                setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
                setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
                    getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
            }
        }
    }

    // Ignore the delay to enable voice call on this target as the enabling the
    // voice call has enough delay to make sure the ringtone audio completely
    // played out
    if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) {
        delayMs = 40;
    }

    // change routing is necessary
    setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);

    // if entering in call state, handle special case of active streams
    // pertaining to sonification strategy see handleIncallSonification()
    if (isStateInCall(state)) {
        ALOGV("setPhoneState() in call state management: new state is %d", state);
        // unmute the ringing tone after a sufficient delay if it was muted before
        // setting output device above
        if (oldState == AudioSystem::MODE_RINGTONE) {
            setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS);
        }
        for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
            handleIncallSonification(stream, true, true);
        }
    }

    // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
    if (state == AudioSystem::MODE_RINGTONE &&
        isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
        mLimitRingtoneVolume = true;
    } else {
        mLimitRingtoneVolume = false;
    }
}