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: 52 explicit BpAudioTrack(const sp<IBinder>& impl) 53 : BpInterface<IAudioTrack>(impl) 54 { 55 } 56 57 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 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 85 virtual void stop() 86 { 87 Parcel data, reply; 88 data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); 89 remote()->transact(STOP, data, &reply); 90 } 91 92 virtual void flush() 93 { 94 Parcel data, reply; 95 data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); 96 remote()->transact(FLUSH, data, &reply); 97 } 98 99 virtual void pause() 100 { 101 Parcel data, reply; 102 data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); 103 remote()->transact(PAUSE, data, &reply); 104 } 105 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 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) */ 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 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 159 virtual void signal() { 160 Parcel data, reply; 161 data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); 162 remote()->transact(SIGNAL, data, &reply); 163 } 164 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 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 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