1 /* 2 * Copyright (C) 2014 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 #define LOG_NDEBUG 0 18 #define LOG_TAG "BootAnim_AudioPlayer" 19 20 #include "AudioPlayer.h" 21 22 #include <androidfw/ZipFileRO.h> 23 #include <tinyalsa/asoundlib.h> 24 #include <utils/Log.h> 25 #include <utils/String8.h> 26 27 #define ID_RIFF 0x46464952 28 #define ID_WAVE 0x45564157 29 #define ID_FMT 0x20746d66 30 #define ID_DATA 0x61746164 31 32 // Maximum line length for audio_conf.txt 33 // We only accept lines less than this length to avoid overflows using sscanf() 34 #define MAX_LINE_LENGTH 1024 35 36 struct riff_wave_header { 37 uint32_t riff_id; 38 uint32_t riff_sz; 39 uint32_t wave_id; 40 }; 41 42 struct chunk_header { 43 uint32_t id; 44 uint32_t sz; 45 }; 46 47 struct chunk_fmt { 48 uint16_t audio_format; 49 uint16_t num_channels; 50 uint32_t sample_rate; 51 uint32_t byte_rate; 52 uint16_t block_align; 53 uint16_t bits_per_sample; 54 }; 55 56 57 namespace android { 58 59 AudioPlayer::AudioPlayer() 60 : mCard(-1), 61 mDevice(-1), 62 mPeriodSize(0), 63 mPeriodCount(0), 64 mCurrentFile(NULL) 65 { 66 } 67 68 AudioPlayer::~AudioPlayer() { 69 } 70 71 static bool setMixerValue(struct mixer* mixer, const char* name, const char* values) 72 { 73 if (!mixer) { 74 ALOGE("no mixer in setMixerValue"); 75 return false; 76 } 77 struct mixer_ctl *ctl = mixer_get_ctl_by_name(mixer, name); 78 if (!ctl) { 79 ALOGE("mixer_get_ctl_by_name failed for %s", name); 80 return false; 81 } 82 83 enum mixer_ctl_type type = mixer_ctl_get_type(ctl); 84 int numValues = mixer_ctl_get_num_values(ctl); 85 int intValue; 86 char stringValue[MAX_LINE_LENGTH]; 87 88 for (int i = 0; i < numValues && values; i++) { 89 // strip leading space 90 while (*values == ' ') values++; 91 if (*values == 0) break; 92 93 switch (type) { 94 case MIXER_CTL_TYPE_BOOL: 95 case MIXER_CTL_TYPE_INT: 96 if (sscanf(values, "%d", &intValue) == 1) { 97 if (mixer_ctl_set_value(ctl, i, intValue) != 0) { 98 ALOGE("mixer_ctl_set_value failed for %s %d", name, intValue); 99 } 100 } else { 101 ALOGE("Could not parse %s as int for %d", intValue, name); 102 } 103 break; 104 case MIXER_CTL_TYPE_ENUM: 105 if (sscanf(values, "%s", stringValue) == 1) { 106 if (mixer_ctl_set_enum_by_string(ctl, stringValue) != 0) { 107 ALOGE("mixer_ctl_set_enum_by_string failed for %s %%s", name, stringValue); 108 } 109 } else { 110 ALOGE("Could not parse %s as enum for %d", stringValue, name); 111 } 112 break; 113 default: 114 ALOGE("unsupported mixer type %d for %s", type, name); 115 break; 116 } 117 118 values = strchr(values, ' '); 119 } 120 121 return true; 122 } 123 124 125 /* 126 * Parse the audio configuration file. 127 * The file is named audio_conf.txt and must begin with the following header: 128 * 129 * card=<ALSA card number> 130 * device=<ALSA device number> 131 * period_size=<period size> 132 * period_count=<period count> 133 * 134 * This header is followed by zero or more mixer settings, each with the format: 135 * mixer "<name>" = <value list> 136 * Since mixer names can contain spaces, the name must be enclosed in double quotes. 137 * The values in the value list can be integers, booleans (represented by 0 or 1) 138 * or strings for enum values. 139 */ 140 bool AudioPlayer::init(const char* config) 141 { 142 int tempInt; 143 struct mixer* mixer = NULL; 144 char name[MAX_LINE_LENGTH]; 145 146 for (;;) { 147 const char* endl = strstr(config, "\n"); 148 if (!endl) break; 149 String8 line(config, endl - config); 150 if (line.length() >= MAX_LINE_LENGTH) { 151 ALOGE("Line too long in audio_conf.txt"); 152 return false; 153 } 154 const char* l = line.string(); 155 156 if (sscanf(l, "card=%d", &tempInt) == 1) { 157 ALOGD("card=%d", tempInt); 158 mCard = tempInt; 159 160 mixer = mixer_open(mCard); 161 if (!mixer) { 162 ALOGE("could not open mixer for card %d", mCard); 163 return false; 164 } 165 } else if (sscanf(l, "device=%d", &tempInt) == 1) { 166 ALOGD("device=%d", tempInt); 167 mDevice = tempInt; 168 } else if (sscanf(l, "period_size=%d", &tempInt) == 1) { 169 ALOGD("period_size=%d", tempInt); 170 mPeriodSize = tempInt; 171 } else if (sscanf(l, "period_count=%d", &tempInt) == 1) { 172 ALOGD("period_count=%d", tempInt); 173 mPeriodCount = tempInt; 174 } else if (sscanf(l, "mixer \"%[0-9a-zA-Z _]s\"", name) == 1) { 175 const char* values = strchr(l, '='); 176 if (values) { 177 values++; // skip '=' 178 ALOGD("name: \"%s\" = %s", name, values); 179 setMixerValue(mixer, name, values); 180 } else { 181 ALOGE("values missing for name: \"%s\"", name); 182 } 183 } 184 config = ++endl; 185 } 186 187 mixer_close(mixer); 188 189 if (mCard >= 0 && mDevice >= 0) { 190 return true; 191 } 192 193 return false; 194 } 195 196 void AudioPlayer::playFile(struct FileMap* fileMap) { 197 // stop any currently playing sound 198 requestExitAndWait(); 199 200 mCurrentFile = fileMap; 201 run("bootanim audio", PRIORITY_URGENT_AUDIO); 202 } 203 204 bool AudioPlayer::threadLoop() 205 { 206 struct pcm_config config; 207 struct pcm *pcm = NULL; 208 bool moreChunks = true; 209 const struct chunk_fmt* chunkFmt = NULL; 210 void* buffer = NULL; 211 int bufferSize; 212 const uint8_t* wavData; 213 size_t wavLength; 214 const struct riff_wave_header* wavHeader; 215 216 if (mCurrentFile == NULL) { 217 ALOGE("mCurrentFile is NULL"); 218 return false; 219 } 220 221 wavData = (const uint8_t *)mCurrentFile->getDataPtr(); 222 if (!wavData) { 223 ALOGE("Could not access WAV file data"); 224 goto exit; 225 } 226 wavLength = mCurrentFile->getDataLength(); 227 228 wavHeader = (const struct riff_wave_header *)wavData; 229 if (wavLength < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) || 230 (wavHeader->wave_id != ID_WAVE)) { 231 ALOGE("Error: audio file is not a riff/wave file\n"); 232 goto exit; 233 } 234 wavData += sizeof(*wavHeader); 235 wavLength -= sizeof(*wavHeader); 236 237 do { 238 const struct chunk_header* chunkHeader = (const struct chunk_header*)wavData; 239 if (wavLength < sizeof(*chunkHeader)) { 240 ALOGE("EOF reading chunk headers"); 241 goto exit; 242 } 243 244 wavData += sizeof(*chunkHeader); 245 wavLength -= sizeof(*chunkHeader); 246 247 switch (chunkHeader->id) { 248 case ID_FMT: 249 chunkFmt = (const struct chunk_fmt *)wavData; 250 wavData += chunkHeader->sz; 251 wavLength -= chunkHeader->sz; 252 break; 253 case ID_DATA: 254 /* Stop looking for chunks */ 255 moreChunks = 0; 256 break; 257 default: 258 /* Unknown chunk, skip bytes */ 259 wavData += chunkHeader->sz; 260 wavLength -= chunkHeader->sz; 261 } 262 } while (moreChunks); 263 264 if (!chunkFmt) { 265 ALOGE("format not found in WAV file"); 266 goto exit; 267 } 268 269 270 memset(&config, 0, sizeof(config)); 271 config.channels = chunkFmt->num_channels; 272 config.rate = chunkFmt->sample_rate; 273 config.period_size = mPeriodSize; 274 config.period_count = mPeriodCount; 275 config.start_threshold = mPeriodSize / 4; 276 config.stop_threshold = INT_MAX; 277 config.avail_min = config.start_threshold; 278 if (chunkFmt->bits_per_sample != 16) { 279 ALOGE("only 16 bit WAV files are supported"); 280 goto exit; 281 } 282 config.format = PCM_FORMAT_S16_LE; 283 284 pcm = pcm_open(mCard, mDevice, PCM_OUT, &config); 285 if (!pcm || !pcm_is_ready(pcm)) { 286 ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(pcm)); 287 goto exit; 288 } 289 290 bufferSize = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); 291 292 while (wavLength > 0) { 293 if (exitPending()) goto exit; 294 size_t count = bufferSize; 295 if (count > wavLength) 296 count = wavLength; 297 298 if (pcm_write(pcm, wavData, count)) { 299 ALOGE("pcm_write failed (%s)", pcm_get_error(pcm)); 300 goto exit; 301 } 302 wavData += count; 303 wavLength -= count; 304 } 305 306 exit: 307 if (pcm) 308 pcm_close(pcm); 309 mCurrentFile->release(); 310 mCurrentFile = NULL; 311 return false; 312 } 313 314 } // namespace android 315