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
VehicleNetworkAudioHelper(int64_t timeoutNs)33 VehicleNetworkAudioHelper::VehicleNetworkAudioHelper(int64_t timeoutNs)
34 : mTimeoutNs(timeoutNs),
35 mListener(NULL),
36 mHasFocusProperty(false) {
37 }
38
VehicleNetworkAudioHelper(int64_t timeoutNs,sp<VehicleNetworkAudioFocusListener> listener)39 VehicleNetworkAudioHelper::VehicleNetworkAudioHelper(int64_t timeoutNs,
40 sp<VehicleNetworkAudioFocusListener> listener)
41 : mTimeoutNs(timeoutNs),
42 mListener(listener),
43 mHasFocusProperty(false) {
44 }
45
~VehicleNetworkAudioHelper()46 VehicleNetworkAudioHelper::~VehicleNetworkAudioHelper() {
47 // nothing to do
48 }
49
init()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
updatePropertiesLocked()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
release()82 void VehicleNetworkAudioHelper::release() {
83 Mutex::Autolock autoLock(mLock);
84 if (mService.get() == NULL) {
85 return;
86 }
87 mService = NULL;
88 }
89
streamFlagToStreamNumber(int32_t streamFlag)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
notifyStreamStarted(int32_t stream)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
notifyStreamStopped(int32_t stream)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
getStreamStateLocked(int32_t streamNumber)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
getStreamFocusState(int32_t stream)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
waitForStreamFocus(int32_t stream,nsecs_t waitTimeNs)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
onEvents(sp<VehiclePropValueListHolder> & events)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
onHalError(int32_t,int32_t,int32_t)230 void VehicleNetworkAudioHelper::onHalError(int32_t /*errorCode*/, int32_t /*property*/,
231 int32_t /*operation*/) {
232 // not used
233 }
234
onHalRestart(bool)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