1 /*
2 **
3 ** Copyright 2007, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "IAudioTrack"
19 //#define LOG_NDEBUG 0
20 #include <utils/Log.h>
21 
22 #include <stdint.h>
23 #include <sys/types.h>
24 
25 #include <binder/Parcel.h>
26 
27 #include <media/IAudioTrack.h>
28 
29 namespace android {
30 
31 using media::VolumeShaper;
32 
33 enum {
34     GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
35     START,
36     STOP,
37     FLUSH,
38     RESERVED, // was MUTE
39     PAUSE,
40     ATTACH_AUX_EFFECT,
41     SET_PARAMETERS,
42     SELECT_PRESENTATION,
43     GET_TIMESTAMP,
44     SIGNAL,
45     APPLY_VOLUME_SHAPER,
46     GET_VOLUME_SHAPER_STATE,
47 };
48 
49 class BpAudioTrack : public BpInterface<IAudioTrack>
50 {
51 public:
BpAudioTrack(const sp<IBinder> & impl)52     explicit BpAudioTrack(const sp<IBinder>& impl)
53         : BpInterface<IAudioTrack>(impl)
54     {
55     }
56 
getCblk() const57     virtual sp<IMemory> getCblk() const
58     {
59         Parcel data, reply;
60         sp<IMemory> cblk;
61         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
62         status_t status = remote()->transact(GET_CBLK, data, &reply);
63         if (status == NO_ERROR) {
64             cblk = interface_cast<IMemory>(reply.readStrongBinder());
65             if (cblk != 0 && cblk->pointer() == NULL) {
66                 cblk.clear();
67             }
68         }
69         return cblk;
70     }
71 
start()72     virtual status_t start()
73     {
74         Parcel data, reply;
75         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
76         status_t status = remote()->transact(START, data, &reply);
77         if (status == NO_ERROR) {
78             status = reply.readInt32();
79         } else {
80             ALOGW("start() error: %s", strerror(-status));
81         }
82         return status;
83     }
84 
stop()85     virtual void stop()
86     {
87         Parcel data, reply;
88         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
89         remote()->transact(STOP, data, &reply);
90     }
91 
flush()92     virtual void flush()
93     {
94         Parcel data, reply;
95         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
96         remote()->transact(FLUSH, data, &reply);
97     }
98 
pause()99     virtual void pause()
100     {
101         Parcel data, reply;
102         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
103         remote()->transact(PAUSE, data, &reply);
104     }
105 
attachAuxEffect(int effectId)106     virtual status_t attachAuxEffect(int effectId)
107     {
108         Parcel data, reply;
109         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
110         data.writeInt32(effectId);
111         status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
112         if (status == NO_ERROR) {
113             status = reply.readInt32();
114         } else {
115             ALOGW("attachAuxEffect() error: %s", strerror(-status));
116         }
117         return status;
118     }
119 
setParameters(const String8 & keyValuePairs)120     virtual status_t setParameters(const String8& keyValuePairs) {
121         Parcel data, reply;
122         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
123         data.writeString8(keyValuePairs);
124         status_t status = remote()->transact(SET_PARAMETERS, data, &reply);
125         if (status == NO_ERROR) {
126             status = reply.readInt32();
127         }
128         return status;
129     }
130 
131     /* Selects the presentation (if available) */
selectPresentation(int presentationId,int programId)132     virtual status_t selectPresentation(int presentationId, int programId) {
133         Parcel data, reply;
134         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
135         data.writeInt32(presentationId);
136         data.writeInt32(programId);
137         status_t status = remote()->transact(SELECT_PRESENTATION, data, &reply);
138         if (status == NO_ERROR) {
139             status = reply.readInt32();
140         }
141         return status;
142     }
143 
getTimestamp(AudioTimestamp & timestamp)144     virtual status_t getTimestamp(AudioTimestamp& timestamp) {
145         Parcel data, reply;
146         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
147         status_t status = remote()->transact(GET_TIMESTAMP, data, &reply);
148         if (status == NO_ERROR) {
149             status = reply.readInt32();
150             if (status == NO_ERROR) {
151                 timestamp.mPosition = reply.readInt32();
152                 timestamp.mTime.tv_sec = reply.readInt32();
153                 timestamp.mTime.tv_nsec = reply.readInt32();
154             }
155         }
156         return status;
157     }
158 
signal()159     virtual void signal() {
160         Parcel data, reply;
161         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
162         remote()->transact(SIGNAL, data, &reply);
163     }
164 
applyVolumeShaper(const sp<VolumeShaper::Configuration> & configuration,const sp<VolumeShaper::Operation> & operation)165     virtual VolumeShaper::Status applyVolumeShaper(
166             const sp<VolumeShaper::Configuration>& configuration,
167             const sp<VolumeShaper::Operation>& operation) {
168         Parcel data, reply;
169         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
170 
171         status_t status = configuration.get() == nullptr
172                 ? data.writeInt32(0)
173                 :  data.writeInt32(1)
174                     ?: configuration->writeToParcel(&data);
175         if (status != NO_ERROR) {
176             return VolumeShaper::Status(status);
177         }
178 
179         status = operation.get() == nullptr
180                 ? status = data.writeInt32(0)
181                 : data.writeInt32(1)
182                     ?: operation->writeToParcel(&data);
183         if (status != NO_ERROR) {
184             return VolumeShaper::Status(status);
185         }
186 
187         int32_t remoteVolumeShaperStatus;
188         status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply)
189                  ?: reply.readInt32(&remoteVolumeShaperStatus);
190 
191         return VolumeShaper::Status(status ?: remoteVolumeShaperStatus);
192     }
193 
getVolumeShaperState(int id)194     virtual sp<VolumeShaper::State> getVolumeShaperState(int id) {
195         Parcel data, reply;
196         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
197 
198         data.writeInt32(id);
199         status_t status = remote()->transact(GET_VOLUME_SHAPER_STATE, data, &reply);
200         if (status != NO_ERROR) {
201             return nullptr;
202         }
203         sp<VolumeShaper::State> state = new VolumeShaper::State;
204         status = state->readFromParcel(&reply);
205         if (status != NO_ERROR) {
206             return nullptr;
207         }
208         return state;
209     }
210 };
211 
212 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
213 
214 // ----------------------------------------------------------------------
215 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)216 status_t BnAudioTrack::onTransact(
217     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
218 {
219     switch (code) {
220         case GET_CBLK: {
221             CHECK_INTERFACE(IAudioTrack, data, reply);
222             reply->writeStrongBinder(IInterface::asBinder(getCblk()));
223             return NO_ERROR;
224         } break;
225         case START: {
226             CHECK_INTERFACE(IAudioTrack, data, reply);
227             reply->writeInt32(start());
228             return NO_ERROR;
229         } break;
230         case STOP: {
231             CHECK_INTERFACE(IAudioTrack, data, reply);
232             stop();
233             return NO_ERROR;
234         } break;
235         case FLUSH: {
236             CHECK_INTERFACE(IAudioTrack, data, reply);
237             flush();
238             return NO_ERROR;
239         } break;
240         case PAUSE: {
241             CHECK_INTERFACE(IAudioTrack, data, reply);
242             pause();
243             return NO_ERROR;
244         }
245         case ATTACH_AUX_EFFECT: {
246             CHECK_INTERFACE(IAudioTrack, data, reply);
247             reply->writeInt32(attachAuxEffect(data.readInt32()));
248             return NO_ERROR;
249         } break;
250         case SET_PARAMETERS: {
251             CHECK_INTERFACE(IAudioTrack, data, reply);
252             String8 keyValuePairs(data.readString8());
253             reply->writeInt32(setParameters(keyValuePairs));
254             return NO_ERROR;
255         } break;
256         case SELECT_PRESENTATION: {
257             CHECK_INTERFACE(IAudioTrack, data, reply);
258             reply->writeInt32(selectPresentation(data.readInt32(), data.readInt32()));
259             return NO_ERROR;
260         } break;
261         case GET_TIMESTAMP: {
262             CHECK_INTERFACE(IAudioTrack, data, reply);
263             AudioTimestamp timestamp;
264             status_t status = getTimestamp(timestamp);
265             reply->writeInt32(status);
266             if (status == NO_ERROR) {
267                 reply->writeInt32(timestamp.mPosition);
268                 reply->writeInt32(timestamp.mTime.tv_sec);
269                 reply->writeInt32(timestamp.mTime.tv_nsec);
270             }
271             return NO_ERROR;
272         } break;
273         case SIGNAL: {
274             CHECK_INTERFACE(IAudioTrack, data, reply);
275             signal();
276             return NO_ERROR;
277         } break;
278         case APPLY_VOLUME_SHAPER: {
279             CHECK_INTERFACE(IAudioTrack, data, reply);
280             sp<VolumeShaper::Configuration> configuration;
281             sp<VolumeShaper::Operation> operation;
282 
283             int32_t present;
284             status_t status = data.readInt32(&present);
285             if (status == NO_ERROR && present != 0) {
286                 configuration = new VolumeShaper::Configuration();
287                 status = configuration->readFromParcel(&data);
288             }
289             status = status ?: data.readInt32(&present);
290             if (status == NO_ERROR && present != 0) {
291                 operation = new VolumeShaper::Operation();
292                 status = operation->readFromParcel(&data);
293             }
294             if (status == NO_ERROR) {
295                 status = (status_t)applyVolumeShaper(configuration, operation);
296             }
297             reply->writeInt32(status);
298             return NO_ERROR;
299         } break;
300         case GET_VOLUME_SHAPER_STATE: {
301             CHECK_INTERFACE(IAudioTrack, data, reply);
302             int id;
303             status_t status = data.readInt32(&id);
304             if (status == NO_ERROR) {
305                 sp<VolumeShaper::State> state = getVolumeShaperState(id);
306                 if (state.get() != nullptr) {
307                      status = state->writeToParcel(reply);
308                 }
309             }
310             return NO_ERROR;
311         } break;
312         default:
313             return BBinder::onTransact(code, data, reply, flags);
314     }
315 }
316 
317 } // namespace android
318