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 45 AudioHardware::AudioHardware() : 46 mInit(false), mMicMute(true), mOutput(0) 47 { 48 mInit = true; 49 } 50 51 AudioHardware::~AudioHardware() 52 { 53 closeOutputStream((AudioStreamOut*)mOutput); 54 mInit = false; 55 } 56 57 status_t AudioHardware::initCheck() 58 { 59 return mInit ? NO_ERROR : NO_INIT; 60 } 61 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 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 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 109 void AudioHardware::closeInputStream(AudioStreamIn* in) { 110 } 111 112 status_t AudioHardware::setMode(int mode) 113 { 114 return NO_ERROR; 115 } 116 117 status_t AudioHardware::setMicMute(bool state) 118 { 119 return NO_ERROR; 120 } 121 122 status_t AudioHardware::getMicMute(bool* state) 123 { 124 *state = mMicMute; 125 return NO_ERROR; 126 } 127 128 status_t AudioHardware::setParameters(const String8& keyValuePairs) 129 { 130 return NO_ERROR; 131 } 132 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 143 size_t AudioHardware::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) 144 { 145 return 4096; 146 } 147 148 status_t AudioHardware::setVoiceVolume(float v) 149 { 150 return NO_ERROR; 151 } 152 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 162 status_t AudioHardware::dump(int fd, const Vector<String16>& args) 163 { 164 return NO_ERROR; 165 } 166 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 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 210 AudioHardware::AudioStreamOutQ5V2::~AudioStreamOutQ5V2() 211 { 212 standby(); 213 } 214 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 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 310 status_t AudioHardware::AudioStreamOutQ5V2::dump(int fd, const Vector<String16>& args) 311 { 312 return NO_ERROR; 313 } 314 315 bool AudioHardware::AudioStreamOutQ5V2::checkStandby() 316 { 317 return mStandby; 318 } 319 320 status_t AudioHardware::AudioStreamOutQ5V2::setParameters(const String8& keyValuePairs) 321 { 322 return NO_ERROR; 323 } 324 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 332 status_t AudioHardware::AudioStreamOutQ5V2::getRenderPosition(uint32_t *dspFrames) 333 { 334 return INVALID_OPERATION; 335 } 336 337 extern "C" AudioHardwareInterface* createAudioHardware(void) { 338 return new AudioHardware(); 339 } 340 341 }; // namespace android 342