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