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