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_caremu"
18 // #define LOG_NDEBUG 0
19 
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 
26 #include <log/log.h>
27 #include <cutils/str_parms.h>
28 
29 #include "ext_pcm.h"
30 
31 static pthread_mutex_t ext_pcm_init_lock = PTHREAD_MUTEX_INITIALIZER;
32 static struct ext_pcm *shared_ext_pcm = NULL;
33 
34 // Sleep 10ms between each mixing, this interval value is arbitrary chosen
35 #define MIXER_INTERVAL_MS 10
36 #define MS_TO_US 1000
37 
38 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
39 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
40 
41 /* copied from libcutils/str_parms.c */
str_eq(void * key_a,void * key_b)42 static bool str_eq(void *key_a, void *key_b) {
43   return !strcmp((const char *)key_a, (const char *)key_b);
44 }
45 
46 /**
47  * use djb hash unless we find it inadequate.
48  * copied from libcutils/str_parms.c
49  */
50 #ifdef __clang__
51 __attribute__((no_sanitize("integer")))
52 #endif
str_hash_fn(void * str)53 static int str_hash_fn(void *str) {
54   uint32_t hash = 5381;
55   char *p;
56   for (p = str; p && *p; p++) {
57     hash = ((hash << 5) + hash) + *p;
58   }
59   return (int)hash;
60 }
61 
mixer_thread_mix(__unused void * key,void * value,void * context)62 static bool mixer_thread_mix(__unused void *key, void *value, void *context) {
63   struct ext_mixer_pipeline *pipeline_out = (struct ext_mixer_pipeline *)context;
64   struct ext_mixer_pipeline *pipeline_in = (struct ext_mixer_pipeline *)value;
65   pipeline_out->position = MAX(pipeline_out->position, pipeline_in->position);
66   for (int i = 0; i < pipeline_out->position; i++) {
67     float mixed = pipeline_out->buffer[i] + pipeline_in->buffer[i];
68     if (mixed > INT16_MAX) pipeline_out->buffer[i] = INT16_MAX;
69     else if (mixed < INT16_MIN) pipeline_out->buffer[i] = INT16_MIN;
70     else pipeline_out->buffer[i] = (int16_t)mixed;
71   }
72   memset(pipeline_in, 0, sizeof(struct ext_mixer_pipeline));
73   return true;
74 }
75 
mixer_thread_loop(void * context)76 static void *mixer_thread_loop(void *context) {
77   pthread_setname_np(pthread_self(), "car_mixer_loop");
78   ALOGD("%s: starting mixer loop", __func__);
79   struct ext_pcm *ext_pcm = (struct ext_pcm *)context;
80   do {
81     pthread_mutex_lock(&ext_pcm->mixer_lock);
82     ext_pcm->mixer_pipeline.position = 0;
83     // Combine the output from every pipeline into one output buffer
84     hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_thread_mix,
85         &ext_pcm->mixer_pipeline);
86     if (ext_pcm->mixer_pipeline.position > 0) {
87       int ret = pcm_write(ext_pcm->pcm, (void *)ext_pcm->mixer_pipeline.buffer,
88           ext_pcm->mixer_pipeline.position * sizeof(int16_t));
89       if (ret != 0) {
90         ALOGE("%s error[%d] writing data to pcm", __func__, ret);
91       }
92     }
93     memset(&ext_pcm->mixer_pipeline, 0, sizeof(struct ext_mixer_pipeline));
94     pthread_cond_broadcast(&ext_pcm->mixer_wake);
95     pthread_mutex_unlock(&ext_pcm->mixer_lock);
96     pthread_mutex_lock(&ext_pcm_init_lock);
97     bool keep_running = ext_pcm->run_mixer;
98     pthread_mutex_unlock(&ext_pcm_init_lock);
99     if (!keep_running) {
100       break;
101     }
102     usleep(MIXER_INTERVAL_MS * MS_TO_US);
103   } while (1);
104   ALOGD("%s: exiting mixer loop", __func__);
105   return NULL;
106 }
107 
mixer_pipeline_write(struct ext_pcm * ext_pcm,const char * bus_address,const void * data,unsigned int count)108 static int mixer_pipeline_write(struct ext_pcm *ext_pcm, const char *bus_address,
109                                 const void *data, unsigned int count) {
110   pthread_mutex_lock(&ext_pcm->mixer_lock);
111   struct ext_mixer_pipeline *pipeline = hashmapGet(
112       ext_pcm->mixer_pipeline_map, bus_address);
113   if (!pipeline) {
114     pipeline = calloc(1, sizeof(struct ext_mixer_pipeline));
115     hashmapPut(ext_pcm->mixer_pipeline_map, bus_address, pipeline);
116   }
117   unsigned int byteWritten = 0;
118   bool write_incomplete = true;
119   do {
120     const unsigned int byteCount = MIN(count - byteWritten,
121         (MIXER_BUFFER_SIZE - pipeline->position) * sizeof(int16_t));
122     const unsigned int int16Count = byteCount / sizeof(int16_t);
123     if (int16Count > 0) {
124       memcpy(&pipeline->buffer[pipeline->position], (const char*)data + byteWritten, byteCount);
125       pipeline->position += int16Count;
126     }
127     byteWritten += byteCount;
128     write_incomplete = byteWritten < count;
129     if (write_incomplete) {
130       // wait for mixer thread to consume the pipeline buffer
131       pthread_cond_wait(&ext_pcm->mixer_wake, &ext_pcm->mixer_lock);
132     }
133   } while (write_incomplete);
134   pthread_mutex_unlock(&ext_pcm->mixer_lock);
135   return 0;
136 }
137 
ext_pcm_open(unsigned int card,unsigned int device,unsigned int flags,struct pcm_config * config)138 struct ext_pcm *ext_pcm_open(unsigned int card, unsigned int device,
139                              unsigned int flags, struct pcm_config *config) {
140   pthread_mutex_lock(&ext_pcm_init_lock);
141   if (shared_ext_pcm == NULL) {
142     shared_ext_pcm = calloc(1, sizeof(struct ext_pcm));
143     pthread_mutex_init(&shared_ext_pcm->lock, (const pthread_mutexattr_t *) NULL);
144     shared_ext_pcm->pcm = pcm_open(card, device, flags, config);
145     pthread_mutex_init(&shared_ext_pcm->mixer_lock, (const pthread_mutexattr_t *)NULL);
146     pthread_create(&shared_ext_pcm->mixer_thread, (const pthread_attr_t *)NULL,
147             mixer_thread_loop, shared_ext_pcm);
148     shared_ext_pcm->mixer_pipeline_map = hashmapCreate(8, str_hash_fn, str_eq);
149     shared_ext_pcm->run_mixer = true;
150   }
151   shared_ext_pcm->ref_count += 1;
152   pthread_mutex_unlock(&ext_pcm_init_lock);
153 
154   return shared_ext_pcm;
155 }
156 
mixer_free_pipeline(__unused void * key,void * value,void * context)157 static bool mixer_free_pipeline(__unused void *key, void *value, void *context) {
158   struct ext_mixer_pipeline *pipeline = (struct ext_mixer_pipeline *)value;
159   free(pipeline);
160   return true;
161 }
162 
ext_pcm_close(struct ext_pcm * ext_pcm)163 int ext_pcm_close(struct ext_pcm *ext_pcm) {
164   ALOGD("%s closing pcm", __func__);
165   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
166     return -EINVAL;
167   }
168 
169   pthread_mutex_lock(&ext_pcm_init_lock);
170   int count = ext_pcm->ref_count -= 1;
171   if (count <= 0) {
172     ext_pcm->run_mixer = false;
173     // On pcm open new shared_ext_pcm will be created
174     shared_ext_pcm = NULL;
175     pthread_mutex_unlock(&ext_pcm_init_lock);
176     void* ret_val = NULL;
177     int ret = pthread_join(ext_pcm->mixer_thread, &ret_val);
178     if (ret != 0) {
179       ALOGE("%s error[%d] when joining thread",
180         __func__, ret);
181       // Try killing if timeout failed
182       pthread_kill(ext_pcm->mixer_thread, SIGINT);
183     }
184     pthread_mutex_lock(&ext_pcm_init_lock);
185     pthread_mutex_destroy(&ext_pcm->lock);
186     pcm_close(ext_pcm->pcm);
187     pthread_mutex_destroy(&ext_pcm->mixer_lock);
188     hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_free_pipeline,
189         (void *)NULL);
190     hashmapFree(ext_pcm->mixer_pipeline_map);
191     free(ext_pcm);
192   }
193   pthread_mutex_unlock(&ext_pcm_init_lock);
194   ALOGD("%s finished closing pcm", __func__);
195   return 0;
196 }
197 
ext_pcm_is_ready(struct ext_pcm * ext_pcm)198 int ext_pcm_is_ready(struct ext_pcm *ext_pcm) {
199   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
200     return 0;
201   }
202 
203   return pcm_is_ready(ext_pcm->pcm);
204 }
205 
ext_pcm_write(struct ext_pcm * ext_pcm,const char * address,const void * data,unsigned int count)206 int ext_pcm_write(struct ext_pcm *ext_pcm, const char *address,
207                   const void *data, unsigned int count) {
208   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
209     return -EINVAL;
210   }
211 
212   return mixer_pipeline_write(ext_pcm, address, data, count);
213 }
214 
ext_pcm_get_error(struct ext_pcm * ext_pcm)215 const char *ext_pcm_get_error(struct ext_pcm *ext_pcm) {
216   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
217     return NULL;
218   }
219 
220   return pcm_get_error(ext_pcm->pcm);
221 }
222 
ext_pcm_frames_to_bytes(struct ext_pcm * ext_pcm,unsigned int frames)223 unsigned int ext_pcm_frames_to_bytes(struct ext_pcm *ext_pcm,
224                                      unsigned int frames) {
225   if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
226     return -EINVAL;
227   }
228 
229   return pcm_frames_to_bytes(ext_pcm->pcm, frames);
230 }
231