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 #define LOG_TAG "VehicleNetworkAudioHelper"
     17 
     18 #include <VehicleNetwork.h>
     19 #include <vehicle-internal.h>
     20 #include <utils/SystemClock.h>
     21 #include "VehicleNetworkAudioHelper.h"
     22 
     23 //#define DBG
     24 #ifdef DBG
     25 #define LOGD(x...) ALOGD(x)
     26 #else
     27 #define LOGD(x...)
     28 #endif
     29 namespace android {
     30 
     31 // ----------------------------------------------------------------------------
     32 
     33 VehicleNetworkAudioHelper::VehicleNetworkAudioHelper(int64_t timeoutNs)
     34     : mTimeoutNs(timeoutNs),
     35       mListener(NULL),
     36       mHasFocusProperty(false) {
     37 }
     38 
     39 VehicleNetworkAudioHelper::VehicleNetworkAudioHelper(int64_t timeoutNs,
     40         sp<VehicleNetworkAudioFocusListener> listener)
     41     : mTimeoutNs(timeoutNs),
     42       mListener(listener),
     43       mHasFocusProperty(false) {
     44 }
     45 
     46 VehicleNetworkAudioHelper::~VehicleNetworkAudioHelper() {
     47     // nothing to do
     48 }
     49 
     50 status_t VehicleNetworkAudioHelper::init() {
     51     Mutex::Autolock autoLock(mLock);
     52     sp<VehicleNetworkListener> listener(this);
     53     mService = VehicleNetwork::createVehicleNetwork(listener);
     54     mScratchValueStreamState.prop = VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE;
     55     mScratchValueStreamState.value_type = VEHICLE_VALUE_TYPE_INT32_VEC2;
     56     mScratchValueStreamState.timestamp = 0;
     57     mScratchValueFocus.prop = VEHICLE_PROPERTY_AUDIO_FOCUS;
     58     mScratchValueFocus.value_type = VEHICLE_VALUE_TYPE_INT32_VEC4;
     59     mScratchValueFocus.timestamp = 0;
     60     updatePropertiesLocked();
     61     return NO_ERROR;
     62 }
     63 
     64 void VehicleNetworkAudioHelper::updatePropertiesLocked() {
     65     sp<VehiclePropertiesHolder> holder = mService->listProperties(VEHICLE_PROPERTY_AUDIO_FOCUS);
     66     if (holder.get() != NULL && holder->getList().size() == 1) {
     67         mHasFocusProperty = true;
     68         mService->subscribe(VEHICLE_PROPERTY_AUDIO_FOCUS, 0);
     69         mService->getProperty(&mScratchValueFocus);
     70         mAllowedStreams = mScratchValueFocus.value.int32_array[VEHICLE_AUDIO_FOCUS_INDEX_STREAMS];
     71         ALOGI("initial focus state 0x%x", mAllowedStreams);
     72     } else {
     73         ALOGW("No focus property, assume focus always granted");
     74         mHasFocusProperty = false;
     75         mAllowedStreams = 0xffffffff;
     76     }
     77     for (size_t i = 0; i < mStreamStates.size(); i++) {
     78         mStreamStates.editItemAt(i).timeoutStartNs = 0;
     79     }
     80 }
     81 
     82 void VehicleNetworkAudioHelper::release() {
     83     Mutex::Autolock autoLock(mLock);
     84     if (mService.get() == NULL) {
     85         return;
     86     }
     87     mService = NULL;
     88 }
     89 
     90 static int32_t streamFlagToStreamNumber(int32_t streamFlag) {
     91     int32_t flag = 0x1;
     92     for (int32_t i = 0; i < 32; i++) {
     93         if ((flag & streamFlag) != 0) {
     94             return i;
     95         }
     96         flag = flag << 1;
     97     }
     98     return -1;
     99 }
    100 
    101 void VehicleNetworkAudioHelper::notifyStreamStarted(int32_t stream) {
    102     Mutex::Autolock autoLock(mLock);
    103     if (!mHasFocusProperty) {
    104         return;
    105     }
    106     int32_t streamNumber = streamFlagToStreamNumber(stream);
    107     if (streamNumber < 0) {
    108         ALOGE("notifyStreamStarted, wrong stream:0x%x", stream);
    109         return;
    110     }
    111     StreamState& state = getStreamStateLocked(streamNumber);
    112     if (state.started) {
    113         return;
    114     }
    115     state.started = true;
    116     state.timeoutStartNs = elapsedRealtimeNano();
    117     mScratchValueStreamState.value.int32_array[VEHICLE_AUDIO_STREAM_STATE_INDEX_STATE] =
    118             VEHICLE_AUDIO_STREAM_STATE_STARTED;
    119     mScratchValueStreamState.value.int32_array[VEHICLE_AUDIO_STREAM_STATE_INDEX_STREAM] =
    120             streamNumber;
    121     mScratchValueStreamState.timestamp = android::elapsedRealtimeNano();
    122     mService->setProperty(mScratchValueStreamState);
    123 }
    124 
    125 void VehicleNetworkAudioHelper::notifyStreamStopped(int32_t stream) {
    126     Mutex::Autolock autoLock(mLock);
    127     if (!mHasFocusProperty) {
    128         return;
    129     }
    130     int32_t streamNumber = streamFlagToStreamNumber(stream);
    131     if (streamNumber < 0) {
    132         ALOGE("notifyStreamStopped, wrong stream:0x%x", stream);
    133         return;
    134     }
    135     StreamState& state = getStreamStateLocked(streamNumber);
    136     if (!state.started) {
    137         return;
    138     }
    139     state.started = false;
    140     state.timeoutStartNs = 0;
    141     mScratchValueStreamState.value.int32_array[VEHICLE_AUDIO_STREAM_STATE_INDEX_STATE] =
    142             VEHICLE_AUDIO_STREAM_STATE_STOPPED;
    143     mScratchValueStreamState.value.int32_array[VEHICLE_AUDIO_STREAM_STATE_INDEX_STREAM] =
    144             streamNumber;
    145     mScratchValueStreamState.timestamp = android::elapsedRealtimeNano();
    146     mService->setProperty(mScratchValueStreamState);
    147 }
    148 
    149 VehicleNetworkAudioHelper::StreamState& VehicleNetworkAudioHelper::getStreamStateLocked(
    150         int32_t streamNumber) {
    151     if (streamNumber >= (int32_t) mStreamStates.size()) {
    152         mStreamStates.insertAt(mStreamStates.size(), streamNumber - mStreamStates.size() + 1);
    153     }
    154     return mStreamStates.editItemAt(streamNumber);
    155 }
    156 
    157 vehicle_network_audio_helper_focus_state VehicleNetworkAudioHelper::getStreamFocusState(
    158         int32_t stream) {
    159     Mutex::Autolock autoLock(mLock);
    160     if ((mAllowedStreams & stream) == stream) {
    161         return VEHICLE_NETWORK_AUDIO_HELPER_FOCUS_STATE_FOCUS;
    162     }
    163     int32_t streamNumber = streamFlagToStreamNumber(stream);
    164     if (streamNumber < 0) {
    165         ALOGE("getStreamFocusState, wrong stream:0x%x", stream);
    166         return VEHICLE_NETWORK_AUDIO_HELPER_FOCUS_STATE_TIMEOUT;
    167     }
    168     StreamState& state = getStreamStateLocked(streamNumber);
    169     if (state.timeoutStartNs == 0) {
    170         if (state.started) {
    171             state.timeoutStartNs = elapsedRealtimeNano();
    172         }
    173     } else {
    174         int64_t now = elapsedRealtimeNano();
    175         if ((state.timeoutStartNs + mTimeoutNs) < now) {
    176             return VEHICLE_NETWORK_AUDIO_HELPER_FOCUS_STATE_TIMEOUT;
    177         }
    178     }
    179     return VEHICLE_NETWORK_AUDIO_HELPER_FOCUS_STATE_NO_FOCUS;
    180 }
    181 
    182 bool VehicleNetworkAudioHelper::waitForStreamFocus(int32_t stream, nsecs_t waitTimeNs) {
    183     LOGD("waitForStreamFocus");
    184     Mutex::Autolock autoLock(mLock);
    185     int64_t currentTime = android::elapsedRealtimeNano();
    186     int64_t finishTime = currentTime + waitTimeNs;
    187     while (true) {
    188         if ((stream & mAllowedStreams) == stream) {
    189             LOGD("waitForStreamFocus, has focus");
    190             return true;
    191         }
    192         currentTime = android::elapsedRealtimeNano();
    193         if (currentTime >= finishTime) {
    194             break;
    195         }
    196         nsecs_t waitTime = finishTime - currentTime;
    197         mFocusWait.waitRelative(mLock, waitTime);
    198     }
    199     LOGD("waitForStreamFocus, no focus");
    200     return false;
    201 }
    202 
    203 void VehicleNetworkAudioHelper::onEvents(sp<VehiclePropValueListHolder>& events) {
    204     sp<VehicleNetworkAudioFocusListener> listener;
    205     int32_t allowedStreams;
    206     bool changed = false;
    207     do {
    208         Mutex::Autolock autoLock(mLock);
    209         if (mService.get() == NULL) { // already released
    210             return;
    211         }
    212         for (vehicle_prop_value_t* value : events->getList()) {
    213             if (value->prop == VEHICLE_PROPERTY_AUDIO_FOCUS) {
    214                 mAllowedStreams = value->value.int32_array[VEHICLE_AUDIO_FOCUS_INDEX_STREAMS];
    215                 ALOGI("audio focus change 0x%x", mAllowedStreams);
    216                 changed = true;
    217             }
    218         }
    219         listener = mListener;
    220         allowedStreams = mAllowedStreams;
    221         if (changed) {
    222             mFocusWait.signal();
    223         }
    224     } while (false);
    225     if (listener.get() != NULL && changed) {
    226         listener->onFocusChange(allowedStreams);
    227     }
    228 }
    229 
    230 void VehicleNetworkAudioHelper::onHalError(int32_t /*errorCode*/, int32_t /*property*/,
    231         int32_t /*operation*/) {
    232     // not used
    233 }
    234 
    235 void VehicleNetworkAudioHelper::onHalRestart(bool /*inMocking*/) {
    236     LOGD("onHalRestart");
    237     Mutex::Autolock autoLock(mLock);
    238     if (mService.get() == NULL) { // already released
    239         return;
    240     }
    241     updatePropertiesLocked();
    242     mFocusWait.signal();
    243 }
    244 
    245 void VehicleNetworkAudioHelper::onPropertySet(const vehicle_prop_value_t &value __attribute__((unused))) {
    246 }
    247 
    248 }; // namespace android
    249