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 }; // namespace android 246