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