AudioHardware: Dispatch setParameters to input and output
[tinyalsa-audio.git] / AudioStreamIn.cpp
1 /*
2  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
3  *
4  * This is based on TinyHardware:
5  * Copyright 2011 Wolfson Microelectronics plc
6  *
7  * This is based on Nexus S AudioHardware implementation:
8  * Copyright 2010, The Android Open-Source Project
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #define LOG_TAG "AudioHardware"
24
25 #include "tinyalsa/asoundlib.h"
26
27 #include "AudioHardware.h"
28 #include "AudioStreamIn.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <fcntl.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <poll.h>
37
38 namespace android {
39
40 TinyALSAAudioStreamIn::TinyALSAAudioStreamIn() :
41         mAudioHardware(NULL),
42         mAudioResampler(NULL),
43         mMixer(NULL),
44         mPcm(NULL),
45         mDevice(0)
46 {
47         LOGD("TinyALSAAudioStreamIn()");
48
49         memset(&mPcmConfig, 0, sizeof(struct pcm_config));
50
51         mMixer = new TinyALSAMixer();
52 }
53
54 TinyALSAAudioStreamIn::~TinyALSAAudioStreamIn()
55 {
56         LOGD("~TinyALSAAudioStreamIn()");
57
58         if(mPcm)
59                 pcm_close(mPcm);
60         if(mAudioResampler)
61                 delete mAudioResampler;
62
63         delete mMixer;
64 }
65
66 status_t TinyALSAAudioStreamIn::set(AudioHardware *hw, uint32_t devices,
67         int *pFormat, uint32_t *pChannels, uint32_t *pRate,
68         AudioSystem::audio_in_acoustics acoustics)
69 {
70         struct pcm *Pcm;
71         struct pcm_config PcmConfig;
72
73         LOGD("TinyALSAAudioStreamIn::set()");
74
75         // Setting globals
76         mAudioHardware = hw;
77         mDevice = devices;
78
79         // Setting PcmConfig
80         memset(&PcmConfig, 0, sizeof(struct pcm_config));
81         PcmConfig.channels = AudioSystem::popCount(*pChannels);
82         PcmConfig.rate = *pRate;
83         PcmConfig.format = PCM_FORMAT_S16_LE;
84         PcmConfig.period_size = 1056;
85         PcmConfig.period_count = 2;
86
87         Pcm = pcm_open(0, 0, PCM_IN, &PcmConfig);
88
89         if(!Pcm || !pcm_is_ready(Pcm)) {
90                 LOGE("TinyALSAAudioStreamIn::set() failed: %s",
91                         pcm_get_error(Pcm));
92
93                 pcm_close(Pcm);
94
95                 LOGD("TinyALSAAudioStreamIn::set(): trying output params");
96
97                 PcmConfig.channels =
98                         AudioSystem::popCount(hw->mOutput->channels());
99                 PcmConfig.rate = hw->mOutput->sampleRate();
100
101                 Pcm = pcm_open(0, 0, PCM_IN, &PcmConfig);
102
103                 if(!Pcm || !pcm_is_ready(Pcm)) {
104                         LOGE("TinyALSAAudioStreamIn::set() failed: %s",
105                                 pcm_get_error(Pcm));
106
107                         return BAD_VALUE;
108                 }
109
110                 mAudioResampler = new TinyALSAAudioResampler(Pcm,
111                         PcmConfig.period_size * PcmConfig.period_count,
112                         PcmConfig.rate, PcmConfig.channels,
113                         *pRate, AudioSystem::popCount(*pChannels));
114         }
115
116         // Do the routing
117         mDevice = devices;
118         mMixer->route(mDevice);
119
120         // Copy the PCM infos
121         mPcm = Pcm;
122         memcpy(&mPcmConfig, &PcmConfig, sizeof(struct pcm_config));
123
124         *pRate = sampleRate();
125         *pFormat = format();
126         *pChannels = channels();
127
128         return NO_ERROR;
129 }
130
131 uint32_t TinyALSAAudioStreamIn::sampleRate(void) const
132 {
133         if(mAudioResampler != NULL)
134                 return mAudioResampler->sampleRate();
135
136         return (uint32_t) mPcmConfig.rate;
137 }
138
139 size_t TinyALSAAudioStreamIn::bufferSize(void) const
140 {
141         if(mAudioResampler != NULL)
142                 return mAudioResampler->bufferSize();
143
144         return (size_t) pcm_get_buffer_size(mPcm);
145 }
146
147 uint32_t TinyALSAAudioStreamIn::channels(void) const
148 {
149         if(mAudioResampler != NULL)
150                 return mAudioResampler->channels();
151
152         switch(mPcmConfig.channels) {
153                 case 1:
154                         return AudioSystem::CHANNEL_OUT_MONO;
155                 case 2:
156                         return AudioSystem::CHANNEL_OUT_STEREO;
157                 case 4:
158                         return AudioSystem::CHANNEL_OUT_QUAD;
159                 case 6:
160                         return AudioSystem::CHANNEL_OUT_5POINT1;
161                 default:
162                         return AudioSystem::CHANNEL_OUT_STEREO;
163         }
164 }
165
166 int TinyALSAAudioStreamIn::format(void) const
167 {
168         switch(mPcmConfig.format) {
169                 case PCM_FORMAT_S16_LE:
170                         return AudioSystem::PCM_16_BIT;
171                 default:
172                         return AudioSystem::PCM_16_BIT;
173         }
174 }
175
176 ssize_t TinyALSAAudioStreamIn::read(void* buffer, ssize_t bytes)
177 {
178         return mAudioResampler->resample(buffer, bytes);
179 }
180
181 status_t TinyALSAAudioStreamIn::standby()
182 {
183         return NO_ERROR;
184 }
185
186 status_t TinyALSAAudioStreamIn::setParameters(const String8& keyValuePairs)
187 {
188         AudioParameter param = AudioParameter(keyValuePairs);
189         String8 key = String8(AudioParameter::keyRouting);
190         int device;
191
192         LOGD("TinyALSAAudioStreamIn::setParameters(%s)",
193                 keyValuePairs.string());
194
195         if(param.getInt(key, device) == NO_ERROR) {
196                 mDevice = device;
197                 mMixer->route(mDevice);
198
199                 param.remove(key);
200         }
201
202         if(param.size()) {
203                 return BAD_VALUE;
204         }
205
206         return NO_ERROR;
207 }
208
209 String8 TinyALSAAudioStreamIn::getParameters(const String8& keys)
210 {
211         AudioParameter param = AudioParameter(keys);
212         String8 key = String8(AudioParameter::keyRouting);
213         String8 value;
214
215         LOGD("TinyALSAAudioStreamIn::getParameters()");
216
217         if(param.get(key, value) == NO_ERROR) {
218                 param.addInt(key, (int) mDevice);
219         }
220
221         return param.toString();
222 }
223
224 unsigned int TinyALSAAudioStreamIn::getInputFramesLost() const
225 {
226         return 0;
227 }
228
229 status_t TinyALSAAudioStreamIn::setGain(float gain)
230 {
231         return INVALID_OPERATION;
232 }
233
234 status_t TinyALSAAudioStreamIn::dump(int fd, const Vector<String16>& args)
235 {
236         return NO_ERROR;
237 }
238
239 }; // namespace android