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
37 extern "C" {
38 #include "msm_audio.h"
39 }
40
41
42 namespace android {
43 // ----------------------------------------------------------------------------
44
AudioHardware()45 AudioHardware::AudioHardware() :
46 mInit(false), mMicMute(true), mOutput(0)
47 {
48 mInit = true;
49 }
50
~AudioHardware()51 AudioHardware::~AudioHardware()
52 {
53 closeOutputStream((AudioStreamOut*)mOutput);
54 mInit = false;
55 }
56
initCheck()57 status_t AudioHardware::initCheck()
58 {
59 return mInit ? NO_ERROR : NO_INIT;
60 }
61
openOutputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status)62 AudioStreamOut* 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
closeOutputStream(AudioStreamOut * out)91 void AudioHardware::closeOutputStream(AudioStreamOut* out) {
92 Mutex::Autolock lock(mLock);
93 if (mOutput == 0 || mOutput != out) {
94 ALOGW("Attempt to close invalid output stream");
95 }
96 else {
97 delete mOutput;
98 mOutput = 0;
99 }
100 }
101
openInputStream(uint32_t devices,int * format,uint32_t * channels,uint32_t * sampleRate,status_t * status,AudioSystem::audio_in_acoustics acoustic_flags)102 AudioStreamIn* 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
closeInputStream(AudioStreamIn * in)109 void AudioHardware::closeInputStream(AudioStreamIn* in) {
110 }
111
setMode(int mode)112 status_t AudioHardware::setMode(int mode)
113 {
114 return NO_ERROR;
115 }
116
setMicMute(bool state)117 status_t AudioHardware::setMicMute(bool state)
118 {
119 return NO_ERROR;
120 }
121
getMicMute(bool * state)122 status_t AudioHardware::getMicMute(bool* state)
123 {
124 *state = mMicMute;
125 return NO_ERROR;
126 }
127
setParameters(const String8 & keyValuePairs)128 status_t AudioHardware::setParameters(const String8& keyValuePairs)
129 {
130 return NO_ERROR;
131 }
132
getParameters(const String8 & keys)133 String8 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
getInputBufferSize(uint32_t sampleRate,int format,int channelCount)143 size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
144 {
145 return 4096;
146 }
147
setVoiceVolume(float v)148 status_t AudioHardware::setVoiceVolume(float v)
149 {
150 return NO_ERROR;
151 }
152
setMasterVolume(float v)153 status_t AudioHardware::setMasterVolume(float v)
154 {
155 ALOGI("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
dump(int fd,const Vector<String16> & args)162 status_t AudioHardware::dump(int fd, const Vector<String16>& args)
163 {
164 return NO_ERROR;
165 }
166
AudioStreamOutQ5V2()167 AudioHardware::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
set(AudioHardware * hw,uint32_t devices,int * pFormat,uint32_t * pChannels,uint32_t * pRate)174 status_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
~AudioStreamOutQ5V2()210 AudioHardware::AudioStreamOutQ5V2::~AudioStreamOutQ5V2()
211 {
212 standby();
213 }
214
write(const void * buffer,size_t bytes)215 ssize_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 ALOGE("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 ALOGE("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 ALOGE("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 ALOGE("Cannot start pcm playback");
261 goto Error;
262 }
263
264 status = ioctl(mFd, AUDIO_SET_VOLUME, &stream_volume);
265 if (status < 0) {
266 ALOGE("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 ALOGW("EAGAIN - retry");
282 }
283 }
284
285 return bytes;
286
287 Error:
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
standby()298 status_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 ALOGI("AudioHardware pcm playback is going to standby.");
307 return status;
308 }
309
dump(int fd,const Vector<String16> & args)310 status_t AudioHardware::AudioStreamOutQ5V2::dump(int fd, const Vector<String16>& args)
311 {
312 return NO_ERROR;
313 }
314
checkStandby()315 bool AudioHardware::AudioStreamOutQ5V2::checkStandby()
316 {
317 return mStandby;
318 }
319
setParameters(const String8 & keyValuePairs)320 status_t AudioHardware::AudioStreamOutQ5V2::setParameters(const String8& keyValuePairs)
321 {
322 return NO_ERROR;
323 }
324
getParameters(const String8 & keys)325 String8 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
getRenderPosition(uint32_t * dspFrames)332 status_t AudioHardware::AudioStreamOutQ5V2::getRenderPosition(uint32_t *dspFrames)
333 {
334 return INVALID_OPERATION;
335 }
336
createAudioHardware(void)337 extern "C" AudioHardwareInterface* createAudioHardware(void) {
338 return new AudioHardware();
339 }
340
341 }; // namespace android
342