Home | History | Annotate | Download | only in src
      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 
    156