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