AudioHardware.cpp revision f9452ed4a7c7bbde537f3f2690fc124e5a1beaff
1/*
2** Copyright 2008, The Android Open-Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8**     http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#include <math.h>
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "AudioHardware"
21
22#include <utils/Log.h>
23#include <utils/String8.h>
24//#include <hardware_legacy/power.h>
25
26#include <stdio.h>
27#include <unistd.h>
28#include <sys/ioctl.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <dlfcn.h>
32#include <fcntl.h>
33
34#include "AudioHardware.h"
35#include <media/AudioRecord.h>
36
37extern "C" {
38#include "msm_audio.h"
39}
40
41
42namespace android {
43// ----------------------------------------------------------------------------
44
45AudioHardware::AudioHardware() :
46    mInit(false), mMicMute(true), mOutput(0)
47{
48    mInit = true;
49}
50
51AudioHardware::~AudioHardware()
52{
53    closeOutputStream((AudioStreamOut*)mOutput);
54    mInit = false;
55}
56
57status_t AudioHardware::initCheck()
58{
59    return mInit ? NO_ERROR : NO_INIT;
60}
61
62AudioStreamOut* AudioHardware::openOutputStream(
63        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status)
64{
65    { // scope for the lock
66        Mutex::Autolock lock(mLock);
67
68        // only one output stream allowed
69        if (mOutput) {
70            if (status) {
71                *status = INVALID_OPERATION;
72            }
73            return 0;
74        }
75
76        AudioStreamOutQ5V2* out = new AudioStreamOutQ5V2();
77
78        status_t rc = out->set(this, devices, format, channels, sampleRate);
79        if (rc) {
80            *status = rc;
81        }
82        if (rc == NO_ERROR) {
83            mOutput = out;
84        } else {
85            delete out;
86        }
87    }
88    return mOutput;
89}
90
91void AudioHardware::closeOutputStream(AudioStreamOut* out) {
92    Mutex::Autolock lock(mLock);
93    if (mOutput == 0 || mOutput != out) {
94        LOGW("Attempt to close invalid output stream");
95    }
96    else {
97        delete mOutput;
98        mOutput = 0;
99    }
100}
101
102AudioStreamIn* AudioHardware::openInputStream(
103        uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
104        AudioSystem::audio_in_acoustics acoustic_flags)
105{
106    return 0;
107}
108
109void AudioHardware::closeInputStream(AudioStreamIn* in) {
110}
111
112status_t AudioHardware::setMode(int mode)
113{
114    return NO_ERROR;
115}
116
117status_t AudioHardware::setMicMute(bool state)
118{
119    return NO_ERROR;
120}
121
122status_t AudioHardware::getMicMute(bool* state)
123{
124    *state = mMicMute;
125    return NO_ERROR;
126}
127
128status_t AudioHardware::setParameters(const String8& keyValuePairs)
129{
130    return NO_ERROR;
131}
132
133String8 AudioHardware::getParameters(const String8& keys)
134{
135    AudioParameter request = AudioParameter(keys);
136    AudioParameter reply = AudioParameter();
137
138    ALOGV("getParameters() %s", keys.string());
139
140    return reply.toString();
141}
142
143size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
144{
145    return 4096;
146}
147
148status_t AudioHardware::setVoiceVolume(float v)
149{
150    return NO_ERROR;
151}
152
153status_t AudioHardware::setMasterVolume(float v)
154{
155    LOGI("Set master volume to %f.\n", v);
156    // We return an error code here to let the audioflinger do in-software
157    // volume on top of the maximum volume that we set through the SND API.
158    // return error - software mixer will handle it
159    return -1;
160}
161
162status_t AudioHardware::dump(int fd, const Vector<String16>& args)
163{
164    return NO_ERROR;
165}
166
167AudioHardware::AudioStreamOutQ5V2::AudioStreamOutQ5V2() :
168    mHardware(0), mFd(-1), mStartCount(0), mRetryCount(0), mStandby(true),
169    mDevices(0), mChannels(AUDIO_HW_OUT_CHANNELS), mSampleRate(AUDIO_HW_OUT_SAMPLERATE),
170    mBufferSize(AUDIO_HW_OUT_BUFSZ)
171{
172}
173
174status_t AudioHardware::AudioStreamOutQ5V2::set(
175        AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate)
176{
177    int lFormat = pFormat ? *pFormat : 0;
178    uint32_t lChannels = pChannels ? *pChannels : 0;
179    uint32_t lRate = pRate ? *pRate : 0;
180
181    mHardware = hw;
182    mDevices = devices;
183
184    // fix up defaults
185    if (lFormat == 0) lFormat = format();
186    if (lChannels == 0) lChannels = channels();
187    if (lRate == 0) lRate = sampleRate();
188
189    // check values
190    if ((lFormat != format()) ||
191        (lChannels != channels()) ||
192        (lRate != sampleRate())) {
193        if (pFormat) *pFormat = format();
194        if (pChannels) *pChannels = channels();
195        if (pRate) *pRate = sampleRate();
196        return BAD_VALUE;
197    }
198
199    if (pFormat) *pFormat = lFormat;
200    if (pChannels) *pChannels = lChannels;
201    if (pRate) *pRate = lRate;
202
203    mChannels = lChannels;
204    mSampleRate = lRate;
205    mBufferSize = 4096;
206
207    return NO_ERROR;
208}
209
210AudioHardware::AudioStreamOutQ5V2::~AudioStreamOutQ5V2()
211{
212    standby();
213}
214
215ssize_t AudioHardware::AudioStreamOutQ5V2::write(const void* buffer, size_t bytes)
216{
217    // ALOGD("AudioStreamOutQ5V2::write(%p, %u)", buffer, bytes);
218    status_t status = NO_INIT;
219    size_t count = bytes;
220    const uint8_t* p = static_cast<const uint8_t*>(buffer);
221
222    if (mStandby) {
223        ALOGV("open pcm_out driver");
224        status = ::open("/dev/msm_pcm_out", O_RDWR);
225        if (status < 0) {
226                LOGE("Cannot open /dev/msm_pcm_out errno: %d", errno);
227            goto Error;
228        }
229        mFd = status;
230
231        // configuration
232        ALOGV("get config");
233        struct msm_audio_config config;
234        status = ioctl(mFd, AUDIO_GET_CONFIG, &config);
235        if (status < 0) {
236            LOGE("Cannot read pcm_out config");
237            goto Error;
238        }
239
240        ALOGV("set pcm_out config");
241        config.channel_count = AudioSystem::popCount(channels());
242        config.sample_rate = mSampleRate;
243        config.buffer_size = mBufferSize;
244        config.buffer_count = AUDIO_HW_NUM_OUT_BUF;
245//        config.codec_type = CODEC_TYPE_PCM;
246        status = ioctl(mFd, AUDIO_SET_CONFIG, &config);
247        if (status < 0) {
248            LOGE("Cannot set config");
249            goto Error;
250        }
251
252        ALOGV("buffer_size: %u", config.buffer_size);
253        ALOGV("buffer_count: %u", config.buffer_count);
254        ALOGV("channel_count: %u", config.channel_count);
255        ALOGV("sample_rate: %u", config.sample_rate);
256
257#if 0
258        status = ioctl(mFd, AUDIO_START, &acdb_id);
259        if (status < 0) {
260            LOGE("Cannot start pcm playback");
261            goto Error;
262        }
263
264        status = ioctl(mFd, AUDIO_SET_VOLUME, &stream_volume);
265        if (status < 0) {
266            LOGE("Cannot start pcm playback");
267            goto Error;
268        }
269#endif
270        mStandby = false;
271    }
272
273    while (count) {
274        ssize_t written = ::write(mFd, p, count);
275        if (written >= 0) {
276            count -= written;
277            p += written;
278        } else {
279            if (errno != EAGAIN) return written;
280            mRetryCount++;
281            LOGW("EAGAIN - retry");
282        }
283    }
284
285    return bytes;
286
287Error:
288    if (mFd >= 0) {
289        ::close(mFd);
290        mFd = -1;
291    }
292    // Simulate audio output timing in case of error
293    usleep(bytes * 1000000 / frameSize() / sampleRate());
294
295    return status;
296}
297
298status_t AudioHardware::AudioStreamOutQ5V2::standby()
299{
300    status_t status = NO_ERROR;
301    if (!mStandby && mFd >= 0) {
302        ::close(mFd);
303        mFd = -1;
304    }
305    mStandby = true;
306    LOGI("AudioHardware pcm playback is going to standby.");
307    return status;
308}
309
310status_t AudioHardware::AudioStreamOutQ5V2::dump(int fd, const Vector<String16>& args)
311{
312    return NO_ERROR;
313}
314
315bool AudioHardware::AudioStreamOutQ5V2::checkStandby()
316{
317    return mStandby;
318}
319
320status_t AudioHardware::AudioStreamOutQ5V2::setParameters(const String8& keyValuePairs)
321{
322    return NO_ERROR;
323}
324
325String8 AudioHardware::AudioStreamOutQ5V2::getParameters(const String8& keys)
326{
327    AudioParameter param = AudioParameter(keys);
328    ALOGV("AudioStreamOutQ5V2::getParameters() %s", param.toString().string());
329    return param.toString();
330}
331
332status_t AudioHardware::AudioStreamOutQ5V2::getRenderPosition(uint32_t *dspFrames)
333{
334    return INVALID_OPERATION;
335}
336
337extern "C" AudioHardwareInterface* createAudioHardware(void) {
338    return new AudioHardware();
339}
340
341}; // namespace android
342