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 */
str_eq(void * key_a,void * key_b)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
str_hash_fn(void * str)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
mixer_thread_mix(__unused void * key,void * value,void * context)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
mixer_thread_loop(void * context)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_cond_broadcast(&ext_pcm->mixer_wake);
87 pthread_mutex_unlock(&ext_pcm->mixer_lock);
88 usleep(MIXER_INTERVAL_MS * 1000);
89 } while (1);
90 }
91
mixer_pipeline_write(struct ext_pcm * ext_pcm,const char * bus_address,const void * data,unsigned int count)92 static int mixer_pipeline_write(struct ext_pcm *ext_pcm, const char *bus_address,
93 const void *data, unsigned int count) {
94 pthread_mutex_lock(&ext_pcm->mixer_lock);
95 struct ext_mixer_pipeline *pipeline = hashmapGet(
96 ext_pcm->mixer_pipeline_map, bus_address);
97 if (!pipeline) {
98 pipeline = calloc(1, sizeof(struct ext_mixer_pipeline));
99 hashmapPut(ext_pcm->mixer_pipeline_map, bus_address, pipeline);
100 }
101 unsigned int byteWritten = 0;
102 bool write_incomplete = true;
103 do {
104 const unsigned int byteCount = MIN(count - byteWritten,
105 (MIXER_BUFFER_SIZE - pipeline->position) * sizeof(int16_t));
106 const unsigned int int16Count = byteCount / sizeof(int16_t);
107 if (int16Count > 0) {
108 memcpy(&pipeline->buffer[pipeline->position], (const char*)data + byteWritten, byteCount);
109 pipeline->position += int16Count;
110 }
111 byteWritten += byteCount;
112 write_incomplete = byteWritten < count;
113 if (write_incomplete) {
114 // wait for mixer thread to consume the pipeline buffer
115 pthread_cond_wait(&ext_pcm->mixer_wake, &ext_pcm->mixer_lock);
116 }
117 } while (write_incomplete);
118 pthread_mutex_unlock(&ext_pcm->mixer_lock);
119 return 0;
120 }
121
ext_pcm_open(unsigned int card,unsigned int device,unsigned int flags,struct pcm_config * config)122 struct ext_pcm *ext_pcm_open(unsigned int card, unsigned int device,
123 unsigned int flags, struct pcm_config *config) {
124 pthread_mutex_lock(&ext_pcm_init_lock);
125 if (shared_ext_pcm == NULL) {
126 shared_ext_pcm = calloc(1, sizeof(struct ext_pcm));
127 pthread_mutex_init(&shared_ext_pcm->lock, (const pthread_mutexattr_t *) NULL);
128 shared_ext_pcm->pcm = pcm_open(card, device, flags, config);
129 pthread_mutex_init(&shared_ext_pcm->mixer_lock, (const pthread_mutexattr_t *)NULL);
130 pthread_create(&shared_ext_pcm->mixer_thread, (const pthread_attr_t *)NULL,
131 mixer_thread_loop, shared_ext_pcm);
132 shared_ext_pcm->mixer_pipeline_map = hashmapCreate(8, str_hash_fn, str_eq);
133 }
134 pthread_mutex_unlock(&ext_pcm_init_lock);
135
136 pthread_mutex_lock(&shared_ext_pcm->lock);
137 shared_ext_pcm->ref_count += 1;
138 pthread_mutex_unlock(&shared_ext_pcm->lock);
139
140 return shared_ext_pcm;
141 }
142
mixer_free_pipeline(__unused void * key,void * value,void * context)143 static bool mixer_free_pipeline(__unused void *key, void *value, void *context) {
144 struct ext_mixer_pipeline *pipeline = (struct ext_mixer_pipeline *)value;
145 free(pipeline);
146 return true;
147 }
148
ext_pcm_close(struct ext_pcm * ext_pcm)149 int ext_pcm_close(struct ext_pcm *ext_pcm) {
150 if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
151 return -EINVAL;
152 }
153
154 pthread_mutex_lock(&ext_pcm->lock);
155 ext_pcm->ref_count -= 1;
156 pthread_mutex_unlock(&ext_pcm->lock);
157
158 pthread_mutex_lock(&ext_pcm_init_lock);
159 if (ext_pcm->ref_count <= 0) {
160 pthread_mutex_destroy(&ext_pcm->lock);
161 pcm_close(ext_pcm->pcm);
162 pthread_mutex_destroy(&ext_pcm->mixer_lock);
163 hashmapForEach(ext_pcm->mixer_pipeline_map, mixer_free_pipeline,
164 (void *)NULL);
165 hashmapFree(ext_pcm->mixer_pipeline_map);
166 pthread_kill(ext_pcm->mixer_thread, SIGINT);
167 free(ext_pcm);
168 shared_ext_pcm = NULL;
169 }
170 pthread_mutex_unlock(&ext_pcm_init_lock);
171 return 0;
172 }
173
ext_pcm_is_ready(struct ext_pcm * ext_pcm)174 int ext_pcm_is_ready(struct ext_pcm *ext_pcm) {
175 if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
176 return 0;
177 }
178
179 return pcm_is_ready(ext_pcm->pcm);
180 }
181
ext_pcm_write(struct ext_pcm * ext_pcm,const char * address,const void * data,unsigned int count)182 int ext_pcm_write(struct ext_pcm *ext_pcm, const char *address,
183 const void *data, unsigned int count) {
184 if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
185 return -EINVAL;
186 }
187
188 return mixer_pipeline_write(ext_pcm, address, data, count);
189 }
190
ext_pcm_get_error(struct ext_pcm * ext_pcm)191 const char *ext_pcm_get_error(struct ext_pcm *ext_pcm) {
192 if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
193 return NULL;
194 }
195
196 return pcm_get_error(ext_pcm->pcm);
197 }
198
ext_pcm_frames_to_bytes(struct ext_pcm * ext_pcm,unsigned int frames)199 unsigned int ext_pcm_frames_to_bytes(struct ext_pcm *ext_pcm,
200 unsigned int frames) {
201 if (ext_pcm == NULL || ext_pcm->pcm == NULL) {
202 return -EINVAL;
203 }
204
205 return pcm_frames_to_bytes(ext_pcm->pcm, frames);
206 }
207