Home | History | Annotate | Download | only in bootanimation
      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 %s", values, 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 %s", values, 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(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     int bufferSize;
    211     const uint8_t* wavData;
    212     size_t wavLength;
    213     const struct riff_wave_header* wavHeader;
    214 
    215     if (mCurrentFile == NULL) {
    216         ALOGE("mCurrentFile is NULL");
    217         return false;
    218      }
    219 
    220     wavData = (const uint8_t *)mCurrentFile->getDataPtr();
    221     if (!wavData) {
    222         ALOGE("Could not access WAV file data");
    223         goto exit;
    224     }
    225     wavLength = mCurrentFile->getDataLength();
    226 
    227     wavHeader = (const struct riff_wave_header *)wavData;
    228     if (wavLength < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
    229         (wavHeader->wave_id != ID_WAVE)) {
    230         ALOGE("Error: audio file is not a riff/wave file\n");
    231         goto exit;
    232     }
    233     wavData += sizeof(*wavHeader);
    234     wavLength -= sizeof(*wavHeader);
    235 
    236     do {
    237         const struct chunk_header* chunkHeader = (const struct chunk_header*)wavData;
    238         if (wavLength < sizeof(*chunkHeader)) {
    239             ALOGE("EOF reading chunk headers");
    240             goto exit;
    241         }
    242 
    243         wavData += sizeof(*chunkHeader);
    244         wavLength -=  sizeof(*chunkHeader);
    245 
    246         switch (chunkHeader->id) {
    247             case ID_FMT:
    248                 chunkFmt = (const struct chunk_fmt *)wavData;
    249                 wavData += chunkHeader->sz;
    250                 wavLength -= chunkHeader->sz;
    251                 break;
    252             case ID_DATA:
    253                 /* Stop looking for chunks */
    254                 moreChunks = 0;
    255                 break;
    256             default:
    257                 /* Unknown chunk, skip bytes */
    258                 wavData += chunkHeader->sz;
    259                 wavLength -= chunkHeader->sz;
    260         }
    261     } while (moreChunks);
    262 
    263     if (!chunkFmt) {
    264         ALOGE("format not found in WAV file");
    265         goto exit;
    266     }
    267 
    268 
    269     memset(&config, 0, sizeof(config));
    270     config.channels = chunkFmt->num_channels;
    271     config.rate = chunkFmt->sample_rate;
    272     config.period_size = mPeriodSize;
    273     config.period_count = mPeriodCount;
    274     config.start_threshold = mPeriodSize / 4;
    275     config.stop_threshold = INT_MAX;
    276     config.avail_min = config.start_threshold;
    277     if (chunkFmt->bits_per_sample != 16) {
    278         ALOGE("only 16 bit WAV files are supported");
    279         goto exit;
    280     }
    281     config.format = PCM_FORMAT_S16_LE;
    282 
    283     pcm = pcm_open(mCard, mDevice, PCM_OUT, &config);
    284     if (!pcm || !pcm_is_ready(pcm)) {
    285         ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(pcm));
    286         goto exit;
    287     }
    288 
    289     bufferSize = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
    290 
    291     while (wavLength > 0) {
    292         if (exitPending()) goto exit;
    293         size_t count = bufferSize;
    294         if (count > wavLength)
    295             count = wavLength;
    296 
    297         if (pcm_write(pcm, wavData, count)) {
    298             ALOGE("pcm_write failed (%s)", pcm_get_error(pcm));
    299             goto exit;
    300         }
    301         wavData += count;
    302         wavLength -= count;
    303     }
    304 
    305 exit:
    306     if (pcm)
    307         pcm_close(pcm);
    308     delete mCurrentFile;
    309     mCurrentFile = NULL;
    310     return false;
    311 }
    312 
    313 } // namespace android
    314