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 30namespace android { 31 32// ---------------------------------------------------------------------------- 33 34AudioDumpInterface::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 45AudioDumpInterface::~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 59AudioStreamOut* 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 106void 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 126AudioStreamIn* 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} 171void 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 189status_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 212String8 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 246status_t AudioDumpInterface::setMode(int mode) 247{ 248 return mFinalInterface->setMode(mode); 249} 250 251size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) 252{ 253 return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount); 254} 255 256// ---------------------------------------------------------------------------- 257 258AudioStreamOutDump::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 273AudioStreamOutDump::~AudioStreamOutDump() 274{ 275 ALOGV("AudioStreamOutDump destructor"); 276 Close(); 277} 278 279ssize_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 303status_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 312uint32_t AudioStreamOutDump::sampleRate() const 313{ 314 if (mFinalStream != 0 ) return mFinalStream->sampleRate(); 315 return mSampleRate; 316} 317 318size_t AudioStreamOutDump::bufferSize() const 319{ 320 if (mFinalStream != 0 ) return mFinalStream->bufferSize(); 321 return mBufferSize; 322} 323 324uint32_t AudioStreamOutDump::channels() const 325{ 326 if (mFinalStream != 0 ) return mFinalStream->channels(); 327 return mChannels; 328} 329int AudioStreamOutDump::format() const 330{ 331 if (mFinalStream != 0 ) return mFinalStream->format(); 332 return mFormat; 333} 334uint32_t AudioStreamOutDump::latency() const 335{ 336 if (mFinalStream != 0 ) return mFinalStream->latency(); 337 return 0; 338} 339status_t AudioStreamOutDump::setVolume(float left, float right) 340{ 341 if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right); 342 return NO_ERROR; 343} 344status_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 389String8 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 397status_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 403void AudioStreamOutDump::Close() 404{ 405 if(mFile) { 406 fclose(mFile); 407 mFile = 0; 408 } 409} 410 411status_t AudioStreamOutDump::getRenderPosition(uint32_t *dspFrames) 412{ 413 if (mFinalStream != 0 ) return mFinalStream->getRenderPosition(dspFrames); 414 return INVALID_OPERATION; 415} 416 417// ---------------------------------------------------------------------------- 418 419AudioStreamInDump::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 434AudioStreamInDump::~AudioStreamInDump() 435{ 436 Close(); 437} 438 439ssize_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 500status_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 509status_t AudioStreamInDump::setGain(float gain) 510{ 511 if (mFinalStream != 0 ) return mFinalStream->setGain(gain); 512 return NO_ERROR; 513} 514 515uint32_t AudioStreamInDump::sampleRate() const 516{ 517 if (mFinalStream != 0 ) return mFinalStream->sampleRate(); 518 return mSampleRate; 519} 520 521size_t AudioStreamInDump::bufferSize() const 522{ 523 if (mFinalStream != 0 ) return mFinalStream->bufferSize(); 524 return mBufferSize; 525} 526 527uint32_t AudioStreamInDump::channels() const 528{ 529 if (mFinalStream != 0 ) return mFinalStream->channels(); 530 return mChannels; 531} 532 533int AudioStreamInDump::format() const 534{ 535 if (mFinalStream != 0 ) return mFinalStream->format(); 536 return mFormat; 537} 538 539status_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 546String8 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 554unsigned int AudioStreamInDump::getInputFramesLost() const 555{ 556 if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost(); 557 return 0; 558} 559 560status_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 566void AudioStreamInDump::Close() 567{ 568 if(mFile) { 569 fclose(mFile); 570 mFile = 0; 571 } 572} 573}; // namespace android 574