Home | History | Annotate | Download | only in libaudio-qdsp5v2
      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         LOGW("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     LOGV("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     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 
    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     // LOGD("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         LOGV("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         LOGV("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         LOGV("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         LOGV("buffer_size: %u", config.buffer_size);
    253         LOGV("buffer_count: %u", config.buffer_count);
    254         LOGV("channel_count: %u", config.channel_count);
    255         LOGV("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 
    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     LOGI("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     LOGV("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