16b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood/*
26b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Copyright (C) 2012 The Android Open Source Project
36b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood *
46b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
56b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * you may not use this file except in compliance with the License.
66b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * You may obtain a copy of the License at
76b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood *
86b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
96b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood *
106b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * Unless required by applicable law or agreed to in writing, software
116b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
126b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * See the License for the specific language governing permissions and
146b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood * limitations under the License.
156b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood */
166b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
176b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <stdio.h>
186b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <stdlib.h>
196b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <stdint.h>
206b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <signal.h>
216b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <unistd.h>
226b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <pthread.h>
236b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <errno.h>
246b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <string.h>
256b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
266b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <tinyalsa/asoundlib.h>
276b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
286b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/types.h>
296b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/stat.h>
306b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <fcntl.h>
316b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include <sys/ioctl.h>
326b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
336b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#include "accessory.h"
346b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
356b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#define BUFFER_COUNT 2
366b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#define BUFFER_SIZE 16384
376b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
386b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#define BUFFER_EMPTY 0
396b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#define BUFFER_BUSY 1
406b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood#define BUFFER_FULL 2
416b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
426b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic char* buffers[BUFFER_COUNT];
436b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int buffer_states[BUFFER_COUNT];
446b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int empty_index = 0;
456b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int full_index = -1;
466b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
476b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
486b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic pthread_cond_t empty_cond = PTHREAD_COND_INITIALIZER;
496b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic pthread_cond_t full_cond = PTHREAD_COND_INITIALIZER;
506b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
516b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic unsigned int input_card;
526b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic unsigned int input_device;
536b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
546b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int get_empty()
556b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
566b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    int index, other;
576b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
586b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_lock(&mutex);
596b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
606b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    while (empty_index == -1)
616b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        pthread_cond_wait(&empty_cond, &mutex);
626b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
636b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    index = empty_index;
646b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    other = (index == 0 ? 1 : 0);
656b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    buffer_states[index] = BUFFER_BUSY;
666b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    if (buffer_states[other] == BUFFER_EMPTY)
676b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        empty_index = other;
686b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    else
696b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        empty_index = -1;
706b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
716b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_unlock(&mutex);
726b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    return index;
736b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
746b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
756b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void put_empty(int index)
766b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
776b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_lock(&mutex);
786b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
796b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    buffer_states[index] = BUFFER_EMPTY;
806b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    if (empty_index == -1) {
816b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        empty_index = index;
826b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        pthread_cond_signal(&empty_cond);
836b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
846b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
856b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_unlock(&mutex);
866b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
876b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
886b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic int get_full()
896b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
906b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    int index, other;
916b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
926b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_lock(&mutex);
936b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
946b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    while (full_index == -1)
956b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        pthread_cond_wait(&full_cond, &mutex);
966b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
976b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    index = full_index;
986b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    other = (index == 0 ? 1 : 0);
996b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    buffer_states[index] = BUFFER_BUSY;
1006b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    if (buffer_states[other] == BUFFER_FULL)
1016b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        full_index = other;
1026b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    else
1036b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        full_index = -1;
1046b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1056b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_unlock(&mutex);
1066b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    return index;
1076b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
1086b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1096b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void put_full(int index)
1106b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
1116b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_lock(&mutex);
1126b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1136b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    buffer_states[index] = BUFFER_FULL;
1146b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    if (full_index == -1) {
1156b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        full_index = index;
1166b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        pthread_cond_signal(&full_cond);
1176b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
1186b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1196b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_mutex_unlock(&mutex);
1206b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
1216b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1226b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void* capture_thread(void* arg)
1236b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
1246b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    struct pcm_config config;
1256b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    struct pcm *pcm = NULL;
1266b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1276b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    fprintf(stderr, "capture_thread start\n");
1286b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1296b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    memset(&config, 0, sizeof(config));
1306b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1316b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.channels = 2;
1326b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.rate = 44100;
1336b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.period_size = 1024;
1346b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.period_count = 4;
1356b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.format = PCM_FORMAT_S16_LE;
1366b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1376b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    while (1) {
1386b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        while (!pcm) {
1396b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            pcm = pcm_open(input_card, input_device, PCM_IN, &config);
1406b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            if (pcm && !pcm_is_ready(pcm)) {
1416b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                pcm_close(pcm);
1426b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                pcm = NULL;
1436b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            }
1446b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            if (!pcm)
1456b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                sleep(1);
1466b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        }
1476b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1486b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        while (pcm) {
1496b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            int index = get_empty();
1506b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            if (pcm_read(pcm, buffers[index], BUFFER_SIZE)) {
1516b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                put_empty(index);
1526b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                pcm_close(pcm);
1536b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                pcm = NULL;
1546b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            } else {
1556b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood                put_full(index);
1566b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            }
1576b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        }
1586b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
1596b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1606b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    fprintf(stderr, "capture_thread done\n");
1616b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    return NULL;
1626b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
1636b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1646b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodstatic void* play_thread(void* arg)
1656b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
1666b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    struct pcm *pcm = arg;
1676b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    char *buffer;
1686b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    int index, err;
1696b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1706b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    fprintf(stderr, "play_thread start\n");
1716b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1726b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    while (1) {
1736b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        index = get_full();
1746b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1756b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        err = pcm_write(pcm, buffers[index], BUFFER_SIZE);
1766b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        if (err)
1776b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood            fprintf(stderr, "pcm_write err: %d\n", err);
1786b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1796b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        put_empty(index);
1806b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
1816b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1826b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    fprintf(stderr, "play_thread done\n");
1836b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pcm_close(pcm);
1846b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    free(buffer);
1856b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1866b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    return NULL;
1876b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
1886b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1896b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwoodint init_audio(unsigned int ic, unsigned int id, unsigned int oc, unsigned int od)
1906b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood{
1916b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_t tid;
1926b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    struct pcm_config config;
1936b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    struct pcm *pcm;
1946b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    int i;
1956b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1966b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    input_card = ic;
1976b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    input_device = id;
1986b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
1996b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    for (i = 0; i < BUFFER_COUNT; i++) {
2006b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        buffers[i] = malloc(BUFFER_SIZE);
2016b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        buffer_states[i] = BUFFER_EMPTY;
2026b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
2036b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
2046b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    memset(&config, 0, sizeof(config));
2056b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.channels = 2;
2066b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.rate = 44100;
2076b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.period_size = 1024;
2086b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.period_count = 4;
2096b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    config.format = PCM_FORMAT_S16_LE;
2106b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
2116b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pcm = pcm_open(oc, od, PCM_OUT, &config);
2126b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    if (!pcm || !pcm_is_ready(pcm)) {
2136b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        fprintf(stderr, "Unable to open PCM device %d/%d for output (%s)\n",
2146b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood               oc, od, pcm_get_error(pcm));
2156b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood        return -1;
2166b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    }
2176b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood
2186b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_create(&tid, NULL, capture_thread, NULL);
2196b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    pthread_create(&tid, NULL, play_thread, pcm);
2206b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood    return 0;
2216b524d9b4552f20e4e689178bdb954a94daf7ab8Mike Lockwood}
222