IAudioTrack.cpp revision 9fc8b5cd4a64ef07e84c69112461324d5c13a0b0
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
29namespace android {
30
31enum {
32    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
33    START,
34    STOP,
35    FLUSH,
36    RESERVED, // was MUTE
37    PAUSE,
38    ATTACH_AUX_EFFECT,
39    SET_PARAMETERS,
40    GET_TIMESTAMP,
41    SIGNAL,
42    APPLY_VOLUME_SHAPER,
43    GET_VOLUME_SHAPER_STATE,
44};
45
46class BpAudioTrack : public BpInterface<IAudioTrack>
47{
48public:
49    explicit BpAudioTrack(const sp<IBinder>& impl)
50        : BpInterface<IAudioTrack>(impl)
51    {
52    }
53
54    virtual sp<IMemory> getCblk() const
55    {
56        Parcel data, reply;
57        sp<IMemory> cblk;
58        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
59        status_t status = remote()->transact(GET_CBLK, data, &reply);
60        if (status == NO_ERROR) {
61            cblk = interface_cast<IMemory>(reply.readStrongBinder());
62            if (cblk != 0 && cblk->pointer() == NULL) {
63                cblk.clear();
64            }
65        }
66        return cblk;
67    }
68
69    virtual status_t start()
70    {
71        Parcel data, reply;
72        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
73        status_t status = remote()->transact(START, data, &reply);
74        if (status == NO_ERROR) {
75            status = reply.readInt32();
76        } else {
77            ALOGW("start() error: %s", strerror(-status));
78        }
79        return status;
80    }
81
82    virtual void stop()
83    {
84        Parcel data, reply;
85        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
86        remote()->transact(STOP, data, &reply);
87    }
88
89    virtual void flush()
90    {
91        Parcel data, reply;
92        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
93        remote()->transact(FLUSH, data, &reply);
94    }
95
96    virtual void pause()
97    {
98        Parcel data, reply;
99        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
100        remote()->transact(PAUSE, data, &reply);
101    }
102
103    virtual status_t attachAuxEffect(int effectId)
104    {
105        Parcel data, reply;
106        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
107        data.writeInt32(effectId);
108        status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
109        if (status == NO_ERROR) {
110            status = reply.readInt32();
111        } else {
112            ALOGW("attachAuxEffect() error: %s", strerror(-status));
113        }
114        return status;
115    }
116
117    virtual status_t setParameters(const String8& keyValuePairs) {
118        Parcel data, reply;
119        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
120        data.writeString8(keyValuePairs);
121        status_t status = remote()->transact(SET_PARAMETERS, data, &reply);
122        if (status == NO_ERROR) {
123            status = reply.readInt32();
124        }
125        return status;
126    }
127
128    virtual status_t getTimestamp(AudioTimestamp& timestamp) {
129        Parcel data, reply;
130        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
131        status_t status = remote()->transact(GET_TIMESTAMP, data, &reply);
132        if (status == NO_ERROR) {
133            status = reply.readInt32();
134            if (status == NO_ERROR) {
135                timestamp.mPosition = reply.readInt32();
136                timestamp.mTime.tv_sec = reply.readInt32();
137                timestamp.mTime.tv_nsec = reply.readInt32();
138            }
139        }
140        return status;
141    }
142
143    virtual void signal() {
144        Parcel data, reply;
145        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
146        remote()->transact(SIGNAL, data, &reply);
147    }
148
149    virtual VolumeShaper::Status applyVolumeShaper(
150            const sp<VolumeShaper::Configuration>& configuration,
151            const sp<VolumeShaper::Operation>& operation) {
152        Parcel data, reply;
153        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
154
155        status_t status = configuration.get() == nullptr
156                ? data.writeInt32(0)
157                :  data.writeInt32(1)
158                    ?: configuration->writeToParcel(&data);
159        if (status != NO_ERROR) {
160            return VolumeShaper::Status(status);
161        }
162
163        status = operation.get() == nullptr
164                ? status = data.writeInt32(0)
165                : data.writeInt32(1)
166                    ?: operation->writeToParcel(&data);
167        if (status != NO_ERROR) {
168            return VolumeShaper::Status(status);
169        }
170
171        int32_t remoteVolumeShaperStatus;
172        status = remote()->transact(APPLY_VOLUME_SHAPER, data, &reply)
173                 ?: reply.readInt32(&remoteVolumeShaperStatus);
174
175        return VolumeShaper::Status(status ?: remoteVolumeShaperStatus);
176    }
177
178    virtual sp<VolumeShaper::State> getVolumeShaperState(int id) {
179        Parcel data, reply;
180        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
181
182        data.writeInt32(id);
183        status_t status = remote()->transact(GET_VOLUME_SHAPER_STATE, data, &reply);
184        if (status != NO_ERROR) {
185            return nullptr;
186        }
187        sp<VolumeShaper::State> state = new VolumeShaper::State;
188        status = state->readFromParcel(reply);
189        if (status != NO_ERROR) {
190            return nullptr;
191        }
192        return state;
193    }
194};
195
196IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
197
198// ----------------------------------------------------------------------
199
200status_t BnAudioTrack::onTransact(
201    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
202{
203    switch (code) {
204        case GET_CBLK: {
205            CHECK_INTERFACE(IAudioTrack, data, reply);
206            reply->writeStrongBinder(IInterface::asBinder(getCblk()));
207            return NO_ERROR;
208        } break;
209        case START: {
210            CHECK_INTERFACE(IAudioTrack, data, reply);
211            reply->writeInt32(start());
212            return NO_ERROR;
213        } break;
214        case STOP: {
215            CHECK_INTERFACE(IAudioTrack, data, reply);
216            stop();
217            return NO_ERROR;
218        } break;
219        case FLUSH: {
220            CHECK_INTERFACE(IAudioTrack, data, reply);
221            flush();
222            return NO_ERROR;
223        } break;
224        case PAUSE: {
225            CHECK_INTERFACE(IAudioTrack, data, reply);
226            pause();
227            return NO_ERROR;
228        }
229        case ATTACH_AUX_EFFECT: {
230            CHECK_INTERFACE(IAudioTrack, data, reply);
231            reply->writeInt32(attachAuxEffect(data.readInt32()));
232            return NO_ERROR;
233        } break;
234        case SET_PARAMETERS: {
235            CHECK_INTERFACE(IAudioTrack, data, reply);
236            String8 keyValuePairs(data.readString8());
237            reply->writeInt32(setParameters(keyValuePairs));
238            return NO_ERROR;
239        } break;
240        case GET_TIMESTAMP: {
241            CHECK_INTERFACE(IAudioTrack, data, reply);
242            AudioTimestamp timestamp;
243            status_t status = getTimestamp(timestamp);
244            reply->writeInt32(status);
245            if (status == NO_ERROR) {
246                reply->writeInt32(timestamp.mPosition);
247                reply->writeInt32(timestamp.mTime.tv_sec);
248                reply->writeInt32(timestamp.mTime.tv_nsec);
249            }
250            return NO_ERROR;
251        } break;
252        case SIGNAL: {
253            CHECK_INTERFACE(IAudioTrack, data, reply);
254            signal();
255            return NO_ERROR;
256        } break;
257        case APPLY_VOLUME_SHAPER: {
258            CHECK_INTERFACE(IAudioTrack, data, reply);
259            sp<VolumeShaper::Configuration> configuration;
260            sp<VolumeShaper::Operation> operation;
261
262            int32_t present;
263            status_t status = data.readInt32(&present);
264            if (status == NO_ERROR && present != 0) {
265                configuration = new VolumeShaper::Configuration();
266                status = configuration->readFromParcel(data);
267            }
268            status = status ?: data.readInt32(&present);
269            if (status == NO_ERROR && present != 0) {
270                operation = new VolumeShaper::Operation();
271                status = operation->readFromParcel(data);
272            }
273            if (status == NO_ERROR) {
274                status = (status_t)applyVolumeShaper(configuration, operation);
275            }
276            reply->writeInt32(status);
277            return NO_ERROR;
278        } break;
279        case GET_VOLUME_SHAPER_STATE: {
280            CHECK_INTERFACE(IAudioTrack, data, reply);
281            int id;
282            status_t status = data.readInt32(&id);
283            if (status == NO_ERROR) {
284                sp<VolumeShaper::State> state = getVolumeShaperState(id);
285                if (state.get() != nullptr) {
286                     status = state->writeToParcel(reply);
287                }
288            }
289            return NO_ERROR;
290        } break;
291        default:
292            return BBinder::onTransact(code, data, reply, flags);
293    }
294}
295
296} // namespace android
297