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 
AudioDumpInterface(AudioHardwareInterface * hw)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 
~AudioDumpInterface()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 
openOutputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status)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 
closeOutputStream(AudioStreamOut * out)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 
openInputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status,AudioSystem::audio_in_acoustics acoustics)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 }
closeInputStream(AudioStreamIn * in)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 
setParameters(const String8 & keyValuePairs)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 
getParameters(const String8 & keys)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 
setMode(int mode)246 status_t AudioDumpInterface::setMode(int mode)
247 {
248     return mFinalInterface->setMode(mode);
249 }
250 
getInputBufferSize(uint32_t sampleRate,int format,int channelCount)251 size_t AudioDumpInterface::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
252 {
253     return mFinalInterface->getInputBufferSize(sampleRate, format, channelCount);
254 }
255 
256 // ----------------------------------------------------------------------------
257 
AudioStreamOutDump(AudioDumpInterface * interface,int id,AudioStreamOut * finalStream,uint32_t devices,int format,uint32_t channels,uint32_t sampleRate)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 
~AudioStreamOutDump()273 AudioStreamOutDump::~AudioStreamOutDump()
274 {
275     ALOGV("AudioStreamOutDump destructor");
276     Close();
277 }
278 
write(const void * buffer,size_t bytes)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 
standby()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 
sampleRate() const312 uint32_t AudioStreamOutDump::sampleRate() const
313 {
314     if (mFinalStream != 0 ) return mFinalStream->sampleRate();
315     return mSampleRate;
316 }
317 
bufferSize() const318 size_t AudioStreamOutDump::bufferSize() const
319 {
320     if (mFinalStream != 0 ) return mFinalStream->bufferSize();
321     return mBufferSize;
322 }
323 
channels() const324 uint32_t AudioStreamOutDump::channels() const
325 {
326     if (mFinalStream != 0 ) return mFinalStream->channels();
327     return mChannels;
328 }
format() const329 int AudioStreamOutDump::format() const
330 {
331     if (mFinalStream != 0 ) return mFinalStream->format();
332     return mFormat;
333 }
latency() const334 uint32_t AudioStreamOutDump::latency() const
335 {
336     if (mFinalStream != 0 ) return mFinalStream->latency();
337     return 0;
338 }
setVolume(float left,float right)339 status_t AudioStreamOutDump::setVolume(float left, float right)
340 {
341     if (mFinalStream != 0 ) return mFinalStream->setVolume(left, right);
342     return NO_ERROR;
343 }
setParameters(const String8 & keyValuePairs)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 
getParameters(const String8 & keys)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 
dump(int fd,const Vector<String16> & args)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 
Close()403 void AudioStreamOutDump::Close()
404 {
405     if(mFile) {
406         fclose(mFile);
407         mFile = 0;
408     }
409 }
410 
getRenderPosition(uint32_t * dspFrames)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 
AudioStreamInDump(AudioDumpInterface * interface,int id,AudioStreamIn * finalStream,uint32_t devices,int format,uint32_t channels,uint32_t sampleRate)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 
~AudioStreamInDump()434 AudioStreamInDump::~AudioStreamInDump()
435 {
436     Close();
437 }
438 
read(void * buffer,ssize_t bytes)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 
standby()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 
setGain(float gain)509 status_t AudioStreamInDump::setGain(float gain)
510 {
511     if (mFinalStream != 0 ) return mFinalStream->setGain(gain);
512     return NO_ERROR;
513 }
514 
sampleRate() const515 uint32_t AudioStreamInDump::sampleRate() const
516 {
517     if (mFinalStream != 0 ) return mFinalStream->sampleRate();
518     return mSampleRate;
519 }
520 
bufferSize() const521 size_t AudioStreamInDump::bufferSize() const
522 {
523     if (mFinalStream != 0 ) return mFinalStream->bufferSize();
524     return mBufferSize;
525 }
526 
channels() const527 uint32_t AudioStreamInDump::channels() const
528 {
529     if (mFinalStream != 0 ) return mFinalStream->channels();
530     return mChannels;
531 }
532 
format() const533 int AudioStreamInDump::format() const
534 {
535     if (mFinalStream != 0 ) return mFinalStream->format();
536     return mFormat;
537 }
538 
setParameters(const String8 & keyValuePairs)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 
getParameters(const String8 & keys)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 
getInputFramesLost() const554 unsigned int AudioStreamInDump::getInputFramesLost() const
555 {
556     if (mFinalStream != 0 ) return mFinalStream->getInputFramesLost();
557     return 0;
558 }
559 
dump(int fd,const Vector<String16> & args)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 
Close()566 void AudioStreamInDump::Close()
567 {
568     if(mFile) {
569         fclose(mFile);
570         mFile = 0;
571     }
572 }
573 }; // namespace android
574