Home | History | Annotate | Download | only in accessorytest
      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     char *buffer;
    168     int index, err;
    169 
    170     fprintf(stderr, "play_thread start\n");
    171 
    172     while (1) {
    173         index = get_full();
    174 
    175         err = pcm_write(pcm, buffers[index], BUFFER_SIZE);
    176         if (err)
    177             fprintf(stderr, "pcm_write err: %d\n", err);
    178 
    179         put_empty(index);
    180     }
    181 
    182     fprintf(stderr, "play_thread done\n");
    183     pcm_close(pcm);
    184     free(buffer);
    185 
    186     return NULL;
    187 }
    188 
    189 int init_audio(unsigned int ic, unsigned int id, unsigned int oc, unsigned int od)
    190 {
    191     pthread_t tid;
    192     struct pcm_config config;
    193     struct pcm *pcm;
    194     int i;
    195 
    196     input_card = ic;
    197     input_device = id;
    198 
    199     for (i = 0; i < BUFFER_COUNT; i++) {
    200         buffers[i] = malloc(BUFFER_SIZE);
    201         buffer_states[i] = BUFFER_EMPTY;
    202     }
    203 
    204     memset(&config, 0, sizeof(config));
    205     config.channels = 2;
    206     config.rate = 44100;
    207     config.period_size = 1024;
    208     config.period_count = 4;
    209     config.format = PCM_FORMAT_S16_LE;
    210 
    211     pcm = pcm_open(oc, od, PCM_OUT, &config);
    212     if (!pcm || !pcm_is_ready(pcm)) {
    213         fprintf(stderr, "Unable to open PCM device %d/%d for output (%s)\n",
    214                oc, od, pcm_get_error(pcm));
    215         return -1;
    216     }
    217 
    218     pthread_create(&tid, NULL, capture_thread, NULL);
    219     pthread_create(&tid, NULL, play_thread, pcm);
    220     return 0;
    221 }
    222