1 /* 2 * Copyright (C) 2012 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 #include <stdio.h> 18 #include <stdlib.h> 19 #include <stdint.h> 20 #include <signal.h> 21 #include <unistd.h> 22 #include <pthread.h> 23 #include <errno.h> 24 #include <string.h> 25 26 #include <tinyalsa/asoundlib.h> 27 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <fcntl.h> 31 #include <sys/ioctl.h> 32 33 #include "accessory.h" 34 35 #define BUFFER_COUNT 2 36 #define BUFFER_SIZE 16384 37 38 #define BUFFER_EMPTY 0 39 #define BUFFER_BUSY 1 40 #define BUFFER_FULL 2 41 42 static char* buffers[BUFFER_COUNT]; 43 static int buffer_states[BUFFER_COUNT]; 44 static int empty_index = 0; 45 static int full_index = -1; 46 47 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 48 static pthread_cond_t empty_cond = PTHREAD_COND_INITIALIZER; 49 static pthread_cond_t full_cond = PTHREAD_COND_INITIALIZER; 50 51 static unsigned int input_card; 52 static unsigned int input_device; 53 54 static int get_empty() 55 { 56 int index, other; 57 58 pthread_mutex_lock(&mutex); 59 60 while (empty_index == -1) 61 pthread_cond_wait(&empty_cond, &mutex); 62 63 index = empty_index; 64 other = (index == 0 ? 1 : 0); 65 buffer_states[index] = BUFFER_BUSY; 66 if (buffer_states[other] == BUFFER_EMPTY) 67 empty_index = other; 68 else 69 empty_index = -1; 70 71 pthread_mutex_unlock(&mutex); 72 return index; 73 } 74 75 static void put_empty(int index) 76 { 77 pthread_mutex_lock(&mutex); 78 79 buffer_states[index] = BUFFER_EMPTY; 80 if (empty_index == -1) { 81 empty_index = index; 82 pthread_cond_signal(&empty_cond); 83 } 84 85 pthread_mutex_unlock(&mutex); 86 } 87 88 static int get_full() 89 { 90 int index, other; 91 92 pthread_mutex_lock(&mutex); 93 94 while (full_index == -1) 95 pthread_cond_wait(&full_cond, &mutex); 96 97 index = full_index; 98 other = (index == 0 ? 1 : 0); 99 buffer_states[index] = BUFFER_BUSY; 100 if (buffer_states[other] == BUFFER_FULL) 101 full_index = other; 102 else 103 full_index = -1; 104 105 pthread_mutex_unlock(&mutex); 106 return index; 107 } 108 109 static void put_full(int index) 110 { 111 pthread_mutex_lock(&mutex); 112 113 buffer_states[index] = BUFFER_FULL; 114 if (full_index == -1) { 115 full_index = index; 116 pthread_cond_signal(&full_cond); 117 } 118 119 pthread_mutex_unlock(&mutex); 120 } 121 122 static void* capture_thread(void* arg) 123 { 124 struct pcm_config config; 125 struct pcm *pcm = NULL; 126 127 fprintf(stderr, "capture_thread start\n"); 128 129 memset(&config, 0, sizeof(config)); 130 131 config.channels = 2; 132 config.rate = 44100; 133 config.period_size = 1024; 134 config.period_count = 4; 135 config.format = PCM_FORMAT_S16_LE; 136 137 while (1) { 138 while (!pcm) { 139 pcm = pcm_open(input_card, input_device, PCM_IN, &config); 140 if (pcm && !pcm_is_ready(pcm)) { 141 pcm_close(pcm); 142 pcm = NULL; 143 } 144 if (!pcm) 145 sleep(1); 146 } 147 148 while (pcm) { 149 int index = get_empty(); 150 if (pcm_read(pcm, buffers[index], BUFFER_SIZE)) { 151 put_empty(index); 152 pcm_close(pcm); 153 pcm = NULL; 154 } else { 155 put_full(index); 156 } 157 } 158 } 159 160 fprintf(stderr, "capture_thread done\n"); 161 return NULL; 162 } 163 164 static void* play_thread(void* arg) 165 { 166 struct pcm *pcm = arg; 167 int index, err; 168 169 fprintf(stderr, "play_thread start\n"); 170 171 while (1) { 172 index = get_full(); 173 174 err = pcm_write(pcm, buffers[index], BUFFER_SIZE); 175 if (err) 176 fprintf(stderr, "pcm_write err: %d\n", err); 177 178 put_empty(index); 179 } 180 181 fprintf(stderr, "play_thread done\n"); 182 pcm_close(pcm); 183 184 return NULL; 185 } 186 187 int init_audio(unsigned int ic, unsigned int id, unsigned int oc, unsigned int od) 188 { 189 pthread_t tid; 190 struct pcm_config config; 191 struct pcm *pcm; 192 int i; 193 194 input_card = ic; 195 input_device = id; 196 197 for (i = 0; i < BUFFER_COUNT; i++) { 198 buffers[i] = malloc(BUFFER_SIZE); 199 buffer_states[i] = BUFFER_EMPTY; 200 } 201 202 memset(&config, 0, sizeof(config)); 203 config.channels = 2; 204 config.rate = 44100; 205 config.period_size = 1024; 206 config.period_count = 4; 207 config.format = PCM_FORMAT_S16_LE; 208 209 pcm = pcm_open(oc, od, PCM_OUT, &config); 210 if (!pcm || !pcm_is_ready(pcm)) { 211 fprintf(stderr, "Unable to open PCM device %d/%d for output (%s)\n", 212 oc, od, pcm_get_error(pcm)); 213 return -1; 214 } 215 216 pthread_create(&tid, NULL, capture_thread, NULL); 217 pthread_create(&tid, NULL, play_thread, pcm); 218 return 0; 219 } 220