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