Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 // TODO remove all the headers upto asound.h after removing pcm_drain hack
     18 #include <errno.h>
     19 #include <unistd.h>
     20 #include <poll.h>
     21 #include <sys/ioctl.h>
     22 #include <sys/mman.h>
     23 #include <sys/time.h>
     24 #include <limits.h>
     25 #include <linux/ioctl.h>
     26 #define __force
     27 #define __bitwise
     28 #define __user
     29 #include <sound/asound.h>
     30 
     31 #include <string.h>
     32 #include <tinyalsa/asoundlib.h>
     33 
     34 #include "audio/AudioHardware.h"
     35 #include "audio/Buffer.h"
     36 #include "Log.h"
     37 
     38 #include "audio/AudioPlaybackLocal.h"
     39 
     40 
     41 AudioPlaybackLocal::AudioPlaybackLocal(int hwId)
     42     : mHwId(hwId),
     43       mPcmHandle(NULL)
     44 {
     45     LOGV("AudioPlaybackLocal %x", (unsigned int)this);
     46 }
     47 
     48 AudioPlaybackLocal::~AudioPlaybackLocal()
     49 {
     50     LOGV("~AudioPlaybackLocal %x", (unsigned int)this);
     51     releaseHw();
     52 }
     53 
     54 bool AudioPlaybackLocal::doPrepare(AudioHardware::SamplingRate samplingRate, int samplesInOneGo)
     55 {
     56     releaseHw();
     57 
     58     struct pcm_config config;
     59 
     60     memset(&config, 0, sizeof(config));
     61     config.channels = 2;
     62     config.rate = samplingRate;
     63     config.period_size = 1024;
     64     config.period_count = 64;
     65     config.format = PCM_FORMAT_S16_LE;
     66     config.start_threshold = 0;
     67     config.stop_threshold =  0;
     68     config.silence_threshold = 0;
     69 
     70     mPcmHandle = pcm_open(mHwId, 0, PCM_OUT, &config);
     71     if (!mPcmHandle || !pcm_is_ready(mPcmHandle)) {
     72        LOGE("Unable to open PCM device(%d) (%s)\n", mHwId, pcm_get_error(mPcmHandle));
     73        return false;
     74     }
     75 
     76     mSamples = samplesInOneGo;
     77     mSizes = samplesInOneGo * 4; // stereo, 16bit
     78 
     79     return true;
     80 }
     81 
     82 bool AudioPlaybackLocal::doPlaybackOrRecord(android::sp<Buffer>& buffer)
     83 {
     84     if (buffer->amountToHandle() < (size_t)mSizes) {
     85         mSizes = buffer->amountToHandle();
     86     }
     87     if (pcm_write(mPcmHandle, buffer->getUnhanledData(), mSizes)) {
     88         LOGE("AudioPlaybackLocal error %s", pcm_get_error(mPcmHandle));
     89         return false;
     90     }
     91     buffer->increaseHandled(mSizes);
     92     LOGV("AudioPlaybackLocal::doPlaybackOrRecord %d", buffer->amountHandled());
     93     return true;
     94 }
     95 
     96 void AudioPlaybackLocal::doStop()
     97 {
     98     // TODO: remove when pcm_stop does pcm_drain
     99     // hack to have snd_pcm_drain equivalent
    100     struct pcm_ {
    101         int fd;
    102     };
    103     pcm_* pcm = (pcm_*)mPcmHandle;
    104     ioctl(pcm->fd, SNDRV_PCM_IOCTL_DRAIN);
    105     pcm_stop(mPcmHandle);
    106 }
    107 
    108 void AudioPlaybackLocal::releaseHw()
    109 {
    110     if (mPcmHandle != NULL) {
    111         LOGV("releaseHw %x", (unsigned int)this);
    112         doStop();
    113         pcm_close(mPcmHandle);
    114         mPcmHandle = NULL;
    115     }
    116 }
    117