Home | History | Annotate | Download | only in driver
      1 /*
      2  * Copyright (C) 2018 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_TAG "audio_hw_generic"
     18 
     19 #include <errno.h>
     20 #include <stdlib.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include <log/log.h>
     25 #include <cutils/str_parms.h>
     26 
     27 #include "ext_pcm.h"
     28 
     29 static pthread_mutex_t ext_pcm_init_lock = PTHREAD_MUTEX_INITIALIZER;
     30 static struct ext_pcm *shared_ext_pcm = NULL;
     31 
     32 // Sleep 10ms between each mixing, this interval value is arbitrary chosen
     33 #define MIXER_INTERVAL_MS 10
     34 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
     35 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
     36 
     37 /* copied from libcutils/str_parms.c */
     38 static bool str_eq(void *key_a, void *key_b) {
     39   return !strcmp((const char *)key_a, (const char *)key_b);
     40 }
     41 
     42 /**
     43  * use djb hash unless we find it inadequate.
     44  * copied from libcutils/str_parms.c
     45  */
     46 #ifdef __clang__
     47 __attribute__((no_sanitize("integer")))
     48 #endif
     49 static int str_hash_fn(void *str) {
     50   uint32_t hash = 5381;
     51   char *p;
     52   for (p = str; p && *p; p++) {
     53     hash = ((hash << 5) + hash) + *p;
     54   }
     55   return (int)hash;
     56 }
     57 
     58 static bool mixer_thread_mix(__unused void *key, void *value, void *context) {
     59   struct ext_mixer_pipeline *pipeline_out = (struct ext_mixer_pipeline *)context;
     60   struct ext_mixer_pipeline *pipeline_in = (struct ext_mixer_pipeline *)value;
     61   pipeline_out->position = MAX(pipeline_out->position, pipeline_in->position);
     62   for (int i = 0; i < pipeline_out->position; i++) {
     63     float mixed = pipeline_out->buffer[i] + pipeline_in->buffer[i];
     64     if (mixed > INT16_MAX) pipeline_out->buffer[i] = INT16_MAX;
     65     else if (mixed < INT16_MIN) pipeline_out->buffer[i] = INT16_MIN;
     66     else pipeline_out->buffer[i] = (int16_t)mixed;
     67   }
     68   memset(pipeline_in, 0, sizeof(struct ext_mixer_pipeline));
     69   return true;
     70 }
     71 
     72 static void *mixer_thread_loop(void *context) {
     73   ALOGD("%s: __enter__", __func__);
     74   struct ext_pcm *ext_pcm = (struct ext_pcm *)context;
     75   do {
     76     pthread_mutex_lock(&ext_pcm->mixer_lock);
     77     ext_pcm->mixer_pipeline.position = 0;
     78     // Combine the output from every pipeline into one output buffer
     79     hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_thread_mix,
     80         &ext_pcm->mixer_pipeline);
     81     if (ext_pcm->mixer_pipeline.position > 0) {
     82       pcm_write(ext_pcm->pcm, (void *)ext_pcm->mixer_pipeline.buffer,
     83           ext_pcm->mixer_pipeline.position * sizeof(int16_t));
     84     }
     85     memset(&ext_pcm->mixer_pipeline, 0, sizeof(struct ext_mixer_pipeline));
     86     pthread_mutex_unlock(&ext_pcm->mixer_lock);
     87     usleep(MIXER_INTERVAL_MS * 1000);
     88   } while (1);
     89 }
     90 
     91 static int mixer_pipeline_write(struct ext_pcm *ext_pcm, const char *bus_address,
     92                                 const void *data, unsigned int count) {
     93   pthread_mutex_lock(&ext_pcm->mixer_lock);
     94   struct ext_mixer_pipeline *pipeline = hashmapGet(
     95       ext_pcm->mixer_pipeline_map, bus_address);
     96   if (!pipeline) {
     97     pipeline = calloc(1, sizeof(struct ext_mixer_pipeline));
     98     hashmapPut(ext_pcm->mixer_pipeline_map, bus_address, pipeline);
     99   }
    100   unsigned int byteCount = MIN(count,
    101       (MIXER_BUFFER_SIZE - pipeline->position) * sizeof(int16_t));
    102   unsigned int int16Count = byteCount / sizeof(int16_t);
    103   if (int16Count > 0) {
    104     memcpy(&pipeline->buffer[pipeline->position], data, byteCount);
    105     pipeline->position += int16Count;
    106   }
    107   pthread_mutex_unlock(&ext_pcm->mixer_lock);
    108   return 0;
    109 }
    110 
    111 struct ext_pcm *ext_pcm_open(unsigned int card, unsigned int device,
    112                              unsigned int flags, struct pcm_config *config) {
    113   pthread_mutex_lock(&ext_pcm_init_lock);
    114   if (shared_ext_pcm == NULL) {
    115     shared_ext_pcm = calloc(1, sizeof(struct ext_pcm));
    116     pthread_mutex_init(&shared_ext_pcm->lock, (const pthread_mutexattr_t *) NULL);
    117     shared_ext_pcm->pcm = pcm_open(card, device, flags, config);
    118     pthread_mutex_init(&shared_ext_pcm->mixer_lock, (const pthread_mutexattr_t *)NULL);
    119     pthread_create(&shared_ext_pcm->mixer_thread, (const pthread_attr_t *)NULL,
    120             mixer_thread_loop, shared_ext_pcm);
    121     shared_ext_pcm->mixer_pipeline_map = hashmapCreate(8, str_hash_fn, str_eq);
    122   }
    123   pthread_mutex_unlock(&ext_pcm_init_lock);
    124 
    125   pthread_mutex_lock(&shared_ext_pcm->lock);
    126   shared_ext_pcm->ref_count += 1;
    127   pthread_mutex_unlock(&shared_ext_pcm->lock);
    128 
    129   return shared_ext_pcm;
    130 }
    131 
    132 static bool mixer_free_pipeline(__unused void *key, void *value, void *context) {
    133   struct ext_mixer_pipeline *pipeline = (struct ext_mixer_pipeline *)value;
    134   free(pipeline);
    135   return true;
    136 }
    137 
    138 int ext_pcm_close(struct ext_pcm *ext_pcm) {
    139   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
    140     return -EINVAL;
    141   }
    142 
    143   pthread_mutex_lock(&ext_pcm->lock);
    144   ext_pcm->ref_count -= 1;
    145   pthread_mutex_unlock(&ext_pcm->lock);
    146 
    147   pthread_mutex_lock(&ext_pcm_init_lock);
    148   if (ext_pcm->ref_count <= 0) {
    149     pthread_mutex_destroy(&ext_pcm->lock);
    150     pcm_close(ext_pcm->pcm);
    151     pthread_mutex_destroy(&ext_pcm->mixer_lock);
    152     hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_free_pipeline,
    153         (void *)NULL);
    154     hashmapFree(ext_pcm->mixer_pipeline_map);
    155     pthread_kill(ext_pcm->mixer_thread, SIGINT);
    156     free(ext_pcm);
    157     shared_ext_pcm = NULL;
    158   }
    159   pthread_mutex_unlock(&ext_pcm_init_lock);
    160   return 0;
    161 }
    162 
    163 int ext_pcm_is_ready(struct ext_pcm *ext_pcm) {
    164   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
    165     return 0;
    166   }
    167 
    168   return pcm_is_ready(ext_pcm->pcm);
    169 }
    170 
    171 int ext_pcm_write(struct ext_pcm *ext_pcm, const char *address,
    172                   const void *data, unsigned int count) {
    173   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
    174     return -EINVAL;
    175   }
    176 
    177   return mixer_pipeline_write(ext_pcm, address, data, count);
    178 }
    179 
    180 const char *ext_pcm_get_error(struct ext_pcm *ext_pcm) {
    181   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
    182     return NULL;
    183   }
    184 
    185   return pcm_get_error(ext_pcm->pcm);
    186 }
    187 
    188 unsigned int ext_pcm_frames_to_bytes(struct ext_pcm *ext_pcm,
    189                                      unsigned int frames) {
    190   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
    191     return -EINVAL;
    192   }
    193 
    194   return pcm_frames_to_bytes(ext_pcm->pcm, frames);
    195 }
    196