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 %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