| François Gaffie | 20f06f9 | 2015-03-24 09:01:14 +0100 | [diff] [blame^] | 1 | /* | 
 | 2 |  * Copyright (C) 2015 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
 | 17 | #define LOG_TAG "APM::AudioPolicyEngine/Stream" | 
 | 18 |  | 
 | 19 | #include "Stream.h" | 
 | 20 | #include <system/audio.h> | 
 | 21 |  | 
 | 22 | using std::string; | 
 | 23 |  | 
 | 24 | namespace android | 
 | 25 | { | 
 | 26 | namespace audio_policy | 
 | 27 | { | 
 | 28 |  | 
 | 29 | status_t Element<audio_stream_type_t>::setIdentifier(audio_stream_type_t identifier) | 
 | 30 | { | 
 | 31 |     if (identifier > AUDIO_STREAM_CNT) { | 
 | 32 |         return BAD_VALUE; | 
 | 33 |     } | 
 | 34 |     mIdentifier = identifier; | 
 | 35 |     ALOGD("%s: Stream %s identifier 0x%X", __FUNCTION__, getName().c_str(), identifier); | 
 | 36 |     return NO_ERROR; | 
 | 37 | } | 
 | 38 |  | 
 | 39 | /** | 
 | 40 | * Set the strategy to follow for this stream. | 
 | 41 | * It checks if the strategy is valid. | 
 | 42 | * | 
 | 43 | * @param[in] strategy to be followed. | 
 | 44 | * | 
 | 45 | * @return NO_ERROR if the strategy is set correctly, error code otherwise. | 
 | 46 | */ | 
 | 47 | template <> | 
 | 48 | status_t Element<audio_stream_type_t>::set<routing_strategy>(routing_strategy strategy) | 
 | 49 | { | 
 | 50 |     if (strategy >= NUM_STRATEGIES) { | 
 | 51 |         return BAD_VALUE; | 
 | 52 |     } | 
 | 53 |     mApplicableStrategy = strategy; | 
 | 54 |     ALOGD("%s: 0x%X for Stream %s", __FUNCTION__, strategy, getName().c_str()); | 
 | 55 |     return NO_ERROR; | 
 | 56 | } | 
 | 57 |  | 
 | 58 | template <> | 
 | 59 | routing_strategy Element<audio_stream_type_t>::get<routing_strategy>() const | 
 | 60 | { | 
 | 61 |     ALOGV("%s: 0x%X for Stream %s", __FUNCTION__, mApplicableStrategy, getName().c_str()); | 
 | 62 |     return mApplicableStrategy; | 
 | 63 | } | 
 | 64 |  | 
 | 65 | status_t Element<audio_stream_type_t>::setVolumeProfile(Volume::device_category category, | 
 | 66 |                                                         const VolumeCurvePoints &points) | 
 | 67 | { | 
 | 68 |     ALOGD("%s: adding volume profile for %s for device category %d, points nb =%d", __FUNCTION__, | 
 | 69 |           getName().c_str(), category, points.size()); | 
 | 70 |     mVolumeProfiles[category] = points; | 
 | 71 |  | 
 | 72 |     for (size_t i = 0; i < points.size(); i++) { | 
 | 73 |         ALOGV("%s: %s cat=%d curve index =%d Index=%d dBAttenuation=%f", | 
 | 74 |               __FUNCTION__, getName().c_str(), category, i, points[i].mIndex, | 
 | 75 |              points[i].mDBAttenuation); | 
 | 76 |     } | 
 | 77 |     return NO_ERROR; | 
 | 78 | } | 
 | 79 |  | 
 | 80 | status_t Element<audio_stream_type_t>::initVolume(int indexMin, int indexMax) | 
 | 81 | { | 
 | 82 |     ALOGV("initStreamVolume() stream %s, min %d, max %d", getName().c_str(), indexMin, indexMax); | 
 | 83 |     if (indexMin < 0 || indexMin >= indexMax) { | 
 | 84 |         ALOGW("initStreamVolume() invalid index limits for stream %s, min %d, max %d", | 
 | 85 |               getName().c_str(), indexMin, indexMax); | 
 | 86 |         return BAD_VALUE; | 
 | 87 |     } | 
 | 88 |     mIndexMin = indexMin; | 
 | 89 |     mIndexMax = indexMax; | 
 | 90 |  | 
 | 91 |     return NO_ERROR; | 
 | 92 | } | 
 | 93 |  | 
 | 94 | float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceCategory, | 
 | 95 |                                                    int indexInUi) | 
 | 96 | { | 
 | 97 |     VolumeProfileConstIterator it = mVolumeProfiles.find(deviceCategory); | 
 | 98 |     if (it == mVolumeProfiles.end()) { | 
 | 99 |         ALOGE("%s: device category %d not found for stream %s", __FUNCTION__, deviceCategory, | 
 | 100 |               getName().c_str()); | 
 | 101 |         return 1.0f; | 
 | 102 |     } | 
 | 103 |     const VolumeCurvePoints curve = mVolumeProfiles[deviceCategory]; | 
 | 104 |     if (curve.size() != Volume::VOLCNT) { | 
 | 105 |         ALOGE("%s: invalid profile for category %d and for stream %s", __FUNCTION__, deviceCategory, | 
 | 106 |               getName().c_str()); | 
 | 107 |         return 1.0f; | 
 | 108 |     } | 
 | 109 |  | 
 | 110 |     // the volume index in the UI is relative to the min and max volume indices for this stream type | 
 | 111 |     int nbSteps = 1 + curve[Volume::VOLMAX].mIndex - | 
 | 112 |             curve[Volume::VOLMIN].mIndex; | 
 | 113 |  | 
 | 114 |     if (mIndexMax - mIndexMin == 0) { | 
 | 115 |         ALOGE("%s: Invalid volume indexes Min=Max=%d", __FUNCTION__, mIndexMin); | 
 | 116 |         return 1.0f; | 
 | 117 |     } | 
 | 118 |     int volIdx = (nbSteps * (indexInUi - mIndexMin)) / | 
 | 119 |             (mIndexMax - mIndexMin); | 
 | 120 |  | 
 | 121 |     // find what part of the curve this index volume belongs to, or if it's out of bounds | 
 | 122 |     int segment = 0; | 
 | 123 |     if (volIdx < curve[Volume::VOLMIN].mIndex) {         // out of bounds | 
 | 124 |         return 0.0f; | 
 | 125 |     } else if (volIdx < curve[Volume::VOLKNEE1].mIndex) { | 
 | 126 |         segment = 0; | 
 | 127 |     } else if (volIdx < curve[Volume::VOLKNEE2].mIndex) { | 
 | 128 |         segment = 1; | 
 | 129 |     } else if (volIdx <= curve[Volume::VOLMAX].mIndex) { | 
 | 130 |         segment = 2; | 
 | 131 |     } else {                                                               // out of bounds | 
 | 132 |         return 1.0f; | 
 | 133 |     } | 
 | 134 |  | 
 | 135 |     // linear interpolation in the attenuation table in dB | 
 | 136 |     float decibels = curve[segment].mDBAttenuation + | 
 | 137 |             ((float)(volIdx - curve[segment].mIndex)) * | 
 | 138 |                 ( (curve[segment+1].mDBAttenuation - | 
 | 139 |                         curve[segment].mDBAttenuation) / | 
 | 140 |                     ((float)(curve[segment+1].mIndex - | 
 | 141 |                             curve[segment].mIndex)) ); | 
 | 142 |  | 
 | 143 |     ALOGV("VOLUME vol index=[%d %d %d], dB=[%.1f %.1f %.1f]", | 
 | 144 |             curve[segment].mIndex, volIdx, | 
 | 145 |             curve[segment+1].mIndex, | 
 | 146 |             curve[segment].mDBAttenuation, | 
 | 147 |             decibels, | 
 | 148 |             curve[segment+1].mDBAttenuation); | 
 | 149 |  | 
 | 150 |     return decibels; | 
 | 151 | } | 
 | 152 |  | 
 | 153 | } // namespace audio_policy | 
 | 154 | } // namespace android | 
 | 155 |  |