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