1 /* //device/servers/AudioFlinger/AudioDumpInterface.cpp 2 ** 3 ** Copyright 2008, 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 "AudioFlingerDump" 19 //#define LOG_NDEBUG 0 20 21 #include <stdint.h> 22 #include <sys/types.h> 23 #include <utils/Log.h> 24 25 #include <stdlib.h> 26 #include <unistd.h> 27 28 #include "AudioDumpInterface.h" 29 30 namespace android { 31 32 // ---------------------------------------------------------------------------- 33 34 AudioDumpInterface::AudioDumpInterface(AudioHardwareInterface* hw) 35 : mFirstHwOutput(true), mPolicyCommands(String8("")), mFileName(String8("")) 36 { 37 if(hw == 0) { 38 LOGE("Dump construct hw = 0"); 39 } 40 mFinalInterface = hw; 41 LOGV("Constructor %p, mFinalInterface %p", this, mFinalInterface); 42 } 43 44 45 AudioDumpInterface::~AudioDumpInterface() 46 { 47 for (size_t i = 0; i < mOutputs.size(); i++) { 48 closeOutputStream((AudioStreamOut *)mOutputs[i]); 49 } 50 if(mFinalInterface) delete mFinalInterface; 51 } 52 53 54 AudioStreamOut* AudioDumpInterface::openOutputStream( 55 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status) 56 { 57 AudioStreamOut* outFinal = NULL; 58 int lFormat = AudioSystem::PCM_16_BIT; 59 uint32_t lChannels = AudioSystem::CHANNEL_OUT_STEREO; 60 uint32_t lRate = 44100; 61 62 63 if (AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices) || mFirstHwOutput) { 64 outFinal = mFinalInterface->openOutputStream(devices, format, channels, sampleRate, status); 65 if (outFinal != 0) { 66 lFormat = outFinal->format(); 67 lChannels = outFinal->channels(); 68 lRate = outFinal->sampleRate(); 69 if (!AudioSystem::isA2dpDevice((AudioSystem::audio_devices)devices)) { 70 mFirstHwOutput = false; 71 } 72 } 73 } else { 74 if (format != 0 && *format != 0) { 75 lFormat = *format; 76 } else { 77 lFormat = AudioSystem::PCM_16_BIT; 78 } 79 if (channels != 0 && *channels != 0) { 80 lChannels = *channels; 81 } else { 82 lChannels = AudioSystem::CHANNEL_OUT_STEREO; 83 } 84 if (sampleRate != 0 && *sampleRate != 0) { 85 lRate = *sampleRate; 86 } else { 87 lRate = 44100; 88 } 89 if (status) *status = NO_ERROR; 90 } 91 LOGV("openOutputStream(), outFinal %p", outFinal); 92 93 AudioStreamOutDump *dumOutput = new AudioStreamOutDump(this, mOutputs.size(), outFinal, 94 devices, lFormat, lChannels, lRate); 95 mOutputs.add(dumOutput); 96 97 return dumOutput; 98 } 99 100 void AudioDumpInterface::closeOutputStream(AudioStreamOut* out) 101 { 102 AudioStreamOutDump *dumpOut = (AudioStreamOutDump *)out; 103 104 if (mOutputs.indexOf(dumpOut) < 0) { 105 LOGW("Attempt to close invalid output stream"); 106 return; 107 } 108 109 LOGV("closeOutputStream() output %p", out); 110 111 dumpOut->standby(); 112 if (dumpOut->finalStream() != NULL) { 113 mFinalInterface->closeOutputStream(dumpOut->finalStream()); 114 mFirstHwOutput = true; 115 } 116 117 mOutputs.remove(dumpOut); 118 delete dumpOut; 119 } 120 121 AudioStreamIn* AudioDumpInterface::openInputStream(uint32_t devices, int *format, uint32_t *channels, 122 uint32_t *sampleRate, status_t *status, AudioSystem::audio_in_acoustics acoustics) 123 { 124 AudioStreamIn* inFinal = NULL; 125 int lFormat = AudioSystem::PCM_16_BIT; 126 uint32_t lChannels = AudioSystem::CHANNEL_IN_MONO; 127 uint32_t lRate = 8000; 128 129 130 if (mInputs.size() == 0) { 131 inFinal = mFinalInterface->openInputStream(devices, format, channels, sampleRate, status, acoustics); 132 if (inFinal == 0) return 0; 133 134 lFormat = inFinal->format(); 135 lChannels = inFinal->channels(); 136 lRate = inFinal->sampleRate(); 137 } else { 138 if (format != 0 && *format != 0) lFormat = *format; 139 if (channels != 0 && *channels != 0) lChannels = *channels; 140 if (sampleRate != 0 && *sampleRate != 0) lRate = *sampleRate; 141 if (status) *status = NO_ERROR; 142 } 143 LOGV("openInputStream(), inFinal %p", inFinal); 144 145 AudioStreamInDump *dumInput = new AudioStreamInDump(this, mInputs.size(), inFinal, 146 devices, lFormat, lChannels, lRate); 147 mInputs.add(dumInput); 148 149 return dumInput; 150 } 151 void AudioDumpInterface::closeInputStream(AudioStreamIn* in) 152 { 153 AudioStreamInDump *dumpIn = (AudioStreamInDump *)in; 154 155 if (mInputs.indexOf(dumpIn) < 0) { 156 LOGW("Attempt to close invalid input stream"); 157 return; 158 } 159 dumpIn->standby(); 160 if (dumpIn->finalStream() != NULL) { 161 mFinalInterface->closeInputStream(dumpIn->finalStream()); 162 } 163 164 mInputs.remove(dumpIn); 165 delete dumpIn; 166 } 167 168 169 status_t AudioDumpInterface::setParameters(const String8& keyValuePairs) 170 { 171 AudioParameter param = AudioParameter(keyValuePairs); 172 String8 value; 173 int valueInt; 174 LOGV("setParameters %s", keyValuePairs.string()); 175 176 if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { 177 mFileName = value; 178 param.remove(String8("test_cmd_file_name")); 179 } 180 if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { 181 Mutex::Autolock _l(mLock); 182 param.remove(String8("test_cmd_policy")); 183 mPolicyCommands = param.toString(); 184 LOGV("test_cmd_policy command %s written", mPolicyCommands.string()); 185 return NO_ERROR; 186 } 187 188 if (mFinalInterface != 0 ) return mFinalInterface->setParameters(keyValuePairs); 189 return NO_ERROR; 190 } 191 192 String8 AudioDumpInterface::getParameters(const String8& keys) 193 { 194 AudioParameter param = AudioParameter(keys); 195 AudioParameter response; 196 String8 value; 197 198 // LOGV("getParameters %s", keys.string()); 199 if (param.get(String8("test_cmd_policy"), value) == NO_ERROR) { 200 Mutex::Autolock _l(mLock); 201 if (mPolicyCommands.length() != 0) { 202 response = AudioParameter(mPolicyCommands); 203 response.addInt(String8("test_cmd_policy"), 1); 204 } else { 205 response.addInt(String8("test_cmd_policy"), 0); 206 } 207 param.remove(String8("test_cmd_policy")); 208 // LOGV("test_cmd_policy command %s read", mPolicyCommands.string()); 209 } 210 211 if (param.get(String8("test_cmd_file_name"), value) == NO_ERROR) { 212 response.add(String8("test_cmd_file_name"), mFileName); 213 param.remove(String8("test_cmd_file_name")); 214 } 215 216 String8 keyValuePairs = response.toString(); 217 218 if (param.size() && mFinalInterface != 0 ) { 219 keyValuePairs += ";"; 220 keyValuePairs += mFinalInterface->getParameters(param.toString()); 221 } 222 223 return keyValuePairs; 224 } 225 226 227 // ---------------------------------------------------------------------------- 228 229 AudioStreamOutDump::AudioStreamOutDump(AudioDumpInterface *interface, 230 int id, 231 AudioStreamOut* finalStream, 232 uint32_t devices, 233 int format, 234 uint32_t channels, 235 uint32_t sampleRate) 236 : mInterface(interface), mId(id), 237 mSampleRate(sampleRate), mFormat(format), mChannels(channels), mLatency(0), mDevice(devices), 238 mBufferSize(1024), mFinalStream(finalStream), mOutFile(0), mFileCount(0) 239 { 240 LOGV("AudioStreamOutDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); 241 } 242 243 244 AudioStreamOutDump::~AudioStreamOutDump() 245 { 246 LOGV("AudioStreamOutDump destructor"); 247 Close(); 248 } 249 250 ssize_t AudioStreamOutDump::write(const void* buffer, size_t bytes) 251 { 252 ssize_t ret; 253 254 if (mFinalStream) { 255 ret = mFinalStream->write(buffer, bytes); 256 } else { 257 usleep((bytes * 1000000) / frameSize() / sampleRate()); 258 ret = bytes; 259 } 260 if(!mOutFile) { 261 if (mInterface->fileName() != "") { 262 char name[255]; 263 sprintf(name, "%s_%d_%d.pcm", mInterface->fileName().string(), mId, ++mFileCount); 264 mOutFile = fopen(name, "wb"); 265 LOGV("Opening dump file %s, fh %p", name, mOutFile); 266 } 267 } 268 if (mOutFile) { 269 fwrite(buffer, bytes, 1, mOutFile); 270 } 271 return ret; 272 } 273 274 status_t AudioStreamOutDump::standby() 275 { 276 LOGV("AudioStreamOutDump standby(), mOutFile %p, mFinalStream %p", mOutFile, mFinalStream); 277 278 Close(); 279 if (mFinalStream != 0 ) return mFinalStream->standby(); 280 return NO_ERROR; 281 } 282 283 uint32_t AudioStreamOutDump::sampleRate() const 284 { 285 if (mFinalStream != 0 ) return mFinalStream->sampleRate(); 286 return mSampleRate; 287 } 288 289 size_t AudioStreamOutDump::bufferSize() const 290 { 291 if (mFinalStream != 0 ) return mFinalStream->bufferSize(); 292 return mBufferSize; 293 } 294 295 uint32_t AudioStreamOutDump::channels() const 296 { 297 if (mFinalStream != 0 ) return mFinalStream->channels(); 298 return mChannels; 299 } 300 int AudioStreamOutDump::format() const 301 { 302 if (mFinalStream != 0 ) return mFinalStream->format(); 303 return mFormat; 304 } 305 uint32_t AudioStreamOutDump::latency() const 306 { 307 if (mFinalStream != 0 ) return mFinalStream->latency(); 308 return 0; 309 } 310 status_t AudioStreamOutDump::setVolume(float left, float right) 311 { 312 if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right); 313 return NO_ERROR; 314 } 315 status_t AudioStreamOutDump::setParameters(const String8& keyValuePairs) 316 { 317 LOGV("AudioStreamOutDump::setParameters %s", keyValuePairs.string()); 318 319 if (mFinalStream != 0 ) { 320 return mFinalStream->setParameters(keyValuePairs); 321 } 322 323 AudioParameter param = AudioParameter(keyValuePairs); 324 String8 value; 325 int valueInt; 326 status_t status = NO_ERROR; 327 328 if (param.getInt(String8("set_id"), valueInt) == NO_ERROR) { 329 mId = valueInt; 330 } 331 332 if (param.getInt(String8("format"), valueInt) == NO_ERROR) { 333 if (mOutFile == 0) { 334 mFormat = valueInt; 335 } else { 336 status = INVALID_OPERATION; 337 } 338 } 339 if (param.getInt(String8("channels"), valueInt) == NO_ERROR) { 340 if (valueInt == AudioSystem::CHANNEL_OUT_STEREO || valueInt == AudioSystem::CHANNEL_OUT_MONO) { 341 mChannels = valueInt; 342 } else { 343 status = BAD_VALUE; 344 } 345 } 346 if (param.getInt(String8("sampling_rate"), valueInt) == NO_ERROR) { 347 if (valueInt > 0 && valueInt <= 48000) { 348 if (mOutFile == 0) { 349 mSampleRate = valueInt; 350 } else { 351 status = INVALID_OPERATION; 352 } 353 } else { 354 status = BAD_VALUE; 355 } 356 } 357 return status; 358 } 359 360 String8 AudioStreamOutDump::getParameters(const String8& keys) 361 { 362 if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); 363 364 AudioParameter param = AudioParameter(keys); 365 return param.toString(); 366 } 367 368 status_t AudioStreamOutDump::dump(int fd, const Vector<String16>& args) 369 { 370 if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); 371 return NO_ERROR; 372 } 373 374 void AudioStreamOutDump::Close() 375 { 376 if(mOutFile) { 377 fclose(mOutFile); 378 mOutFile = 0; 379 } 380 } 381 382 status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames) 383 { 384 if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames); 385 return INVALID_OPERATION; 386 } 387 388 // ---------------------------------------------------------------------------- 389 390 AudioStreamInDump::AudioStreamInDump(AudioDumpInterface *interface, 391 int id, 392 AudioStreamIn* finalStream, 393 uint32_t devices, 394 int format, 395 uint32_t channels, 396 uint32_t sampleRate) 397 : mInterface(interface), mId(id), 398 mSampleRate(sampleRate), mFormat(format), mChannels(channels), mDevice(devices), 399 mBufferSize(1024), mFinalStream(finalStream), mInFile(0) 400 { 401 LOGV("AudioStreamInDump Constructor %p, mInterface %p, mFinalStream %p", this, mInterface, mFinalStream); 402 } 403 404 405 AudioStreamInDump::~AudioStreamInDump() 406 { 407 Close(); 408 } 409 410 ssize_t AudioStreamInDump::read(void* buffer, ssize_t bytes) 411 { 412 if (mFinalStream) { 413 return mFinalStream->read(buffer, bytes); 414 } 415 416 usleep((bytes * 1000000) / frameSize() / sampleRate()); 417 418 if(!mInFile) { 419 char name[255]; 420 strcpy(name, "/sdcard/music/sine440"); 421 if (channels() == AudioSystem::CHANNEL_IN_MONO) { 422 strcat(name, "_mo"); 423 } else { 424 strcat(name, "_st"); 425 } 426 if (format() == AudioSystem::PCM_16_BIT) { 427 strcat(name, "_16b"); 428 } else { 429 strcat(name, "_8b"); 430 } 431 if (sampleRate() < 16000) { 432 strcat(name, "_8k"); 433 } else if (sampleRate() < 32000) { 434 strcat(name, "_22k"); 435 } else if (sampleRate() < 48000) { 436 strcat(name, "_44k"); 437 } else { 438 strcat(name, "_48k"); 439 } 440 strcat(name, ".wav"); 441 mInFile = fopen(name, "rb"); 442 LOGV("Opening dump file %s, fh %p", name, mInFile); 443 if (mInFile) { 444 fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); 445 } 446 447 } 448 if (mInFile) { 449 ssize_t bytesRead = fread(buffer, bytes, 1, mInFile); 450 if (bytesRead != bytes) { 451 fseek(mInFile, AUDIO_DUMP_WAVE_HDR_SIZE, SEEK_SET); 452 fread((uint8_t *)buffer+bytesRead, bytes-bytesRead, 1, mInFile); 453 } 454 } 455 return bytes; 456 } 457 458 status_t AudioStreamInDump::standby() 459 { 460 LOGV("AudioStreamInDump standby(), mInFile %p, mFinalStream %p", mInFile, mFinalStream); 461 462 Close(); 463 if (mFinalStream != 0 ) return mFinalStream->standby(); 464 return NO_ERROR; 465 } 466 467 status_t AudioStreamInDump::setGain(float gain) 468 { 469 if (mFinalStream != 0 ) return mFinalStream->setGain(gain); 470 return NO_ERROR; 471 } 472 473 uint32_t AudioStreamInDump::sampleRate() const 474 { 475 if (mFinalStream != 0 ) return mFinalStream->sampleRate(); 476 return mSampleRate; 477 } 478 479 size_t AudioStreamInDump::bufferSize() const 480 { 481 if (mFinalStream != 0 ) return mFinalStream->bufferSize(); 482 return mBufferSize; 483 } 484 485 uint32_t AudioStreamInDump::channels() const 486 { 487 if (mFinalStream != 0 ) return mFinalStream->channels(); 488 return mChannels; 489 } 490 491 int AudioStreamInDump::format() const 492 { 493 if (mFinalStream != 0 ) return mFinalStream->format(); 494 return mFormat; 495 } 496 497 status_t AudioStreamInDump::setParameters(const String8& keyValuePairs) 498 { 499 LOGV("AudioStreamInDump::setParameters()"); 500 if (mFinalStream != 0 ) return mFinalStream->setParameters(keyValuePairs); 501 return NO_ERROR; 502 } 503 504 String8 AudioStreamInDump::getParameters(const String8& keys) 505 { 506 if (mFinalStream != 0 ) return mFinalStream->getParameters(keys); 507 508 AudioParameter param = AudioParameter(keys); 509 return param.toString(); 510 } 511 512 unsigned int AudioStreamInDump::getInputFramesLost() const 513 { 514 if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost(); 515 return 0; 516 } 517 518 status_t AudioStreamInDump::dump(int fd, const Vector<String16>& args) 519 { 520 if (mFinalStream != 0 ) return mFinalStream->dump(fd, args); 521 return NO_ERROR; 522 } 523 524 void AudioStreamInDump::Close() 525 { 526 if(mInFile) { 527 fclose(mInFile); 528 mInFile = 0; 529 } 530 } 531 }; // namespace android 532