198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Copyright (C) 2014 The Android Open Source Project 398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * 498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Licensed under the Apache License, Version 2.0 (the "License"); 598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * you may not use this file except in compliance with the License. 698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * You may obtain a copy of the License at 798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * 898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * http://www.apache.org/licenses/LICENSE-2.0 998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * 1098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Unless required by applicable law or agreed to in writing, software 1198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * distributed under the License is distributed on an "AS IS" BASIS, 1298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * See the License for the specific language governing permissions and 1498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * limitations under the License. 1598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 1698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 1798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#define LOG_TAG "alsa_device_proxy" 1898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/*#define LOG_NDEBUG 0*/ 1998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/*#define LOG_PCM_PARAMS 0*/ 2098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include <log/log.h> 2298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include <errno.h> 2498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include "include/alsa_device_proxy.h" 2698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include "include/alsa_logging.h" 2898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#define DEFAULT_PERIOD_SIZE 1024 3098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#define DEFAULT_PERIOD_COUNT 2 3198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 328785fe142d519d8e011eecdc340a638978fb9272Andy Hung#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 338785fe142d519d8e011eecdc340a638978fb9272Andy Hung 348785fe142d519d8e011eecdc340a638978fb9272Andy Hungstatic const unsigned format_byte_size_map[] = { 358785fe142d519d8e011eecdc340a638978fb9272Andy Hung 2, /* PCM_FORMAT_S16_LE */ 368785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4, /* PCM_FORMAT_S32_LE */ 378785fe142d519d8e011eecdc340a638978fb9272Andy Hung 1, /* PCM_FORMAT_S8 */ 388785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4, /* PCM_FORMAT_S24_LE */ 398785fe142d519d8e011eecdc340a638978fb9272Andy Hung 3, /* PCM_FORMAT_S24_3LE */ 408785fe142d519d8e011eecdc340a638978fb9272Andy Hung}; 418785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanvoid proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile, 4398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean struct pcm_config * config) 4498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 4598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_prepare(c:%d, d:%d)", profile->card, profile->device); 4698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 4798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->profile = profile; 4898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 4998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#ifdef LOG_PCM_PARAMS 5098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean log_pcm_config(config, "proxy_setup()"); 5198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#endif 5298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 53a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format)) { 54a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.format = config->format; 55a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 56a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean ALOGW("Invalid format %d - using default %d.", 57a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean config->format, profile->default_config.format); 58a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.format = profile->default_config.format; 59a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 60a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean 61a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate)) { 62a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.rate = config->rate; 63a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 64a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean ALOGW("Invalid sample rate %u - using default %u.", 65a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean config->rate, profile->default_config.rate); 66a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.rate = profile->default_config.rate; 67a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 68a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean 69a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->channels != 0 && profile_is_channel_count_valid(profile, config->channels)) { 70a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.channels = config->channels; 71a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 72a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean ALOGW("Invalid channel count %u - using default %u.", 73a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean config->channels, profile->default_config.channels); 74a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.channels = profile->default_config.channels; 75a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean 76a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 7798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 7898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = profile->default_config.period_count; 7998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_size = 8098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile_get_period_size(proxy->profile, proxy->alsa_config.rate); 8198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 8298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Hack for USB accessory audio. 8398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Here we set the correct value for period_count if tinyalsa fails to get it from the 8498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // f_audio_source driver. 8598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->alsa_config.period_count == 0) { 8698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = 4; 8798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 8898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 8998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 908785fe142d519d8e011eecdc340a638978fb9272Andy Hung // config format should be checked earlier against profile. 918785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (config->format >= 0 && (size_t)config->format < ARRAY_SIZE(format_byte_size_map)) { 928785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = format_byte_size_map[config->format] * proxy->alsa_config.channels; 938785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 948785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = 1; 958785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 9698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 9798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 9898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_open(alsa_device_proxy * proxy) 9998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 10098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean alsa_device_profile* profile = proxy->profile; 10198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_open(card:%d device:%d %s)", profile->card, profile->device, 10298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile->direction == PCM_OUT ? "PCM_OUT" : "PCM_IN"); 10398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 10498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (profile->card < 0 || profile->device < 0) { 10598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -EINVAL; 10698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 10798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 1088785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->pcm = pcm_open(profile->card, profile->device, 1098785fe142d519d8e011eecdc340a638978fb9272Andy Hung profile->direction | PCM_MONOTONIC, &proxy->alsa_config); 11098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm == NULL) { 11198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 11298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 11398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 11498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (!pcm_is_ready(proxy->pcm)) { 11598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGE(" proxy_open() pcm_open() failed: %s", pcm_get_error(proxy->pcm)); 11698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#if defined(LOG_PCM_PARAMS) 11798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean log_pcm_config(&proxy->alsa_config, "config"); 11898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#endif 11998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 12098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 12198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 12298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 12398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 12498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return 0; 12598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 12698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 12798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanvoid proxy_close(alsa_device_proxy * proxy) 12898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 12998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_close() [pcm:%p]", proxy->pcm); 13098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 13198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm != NULL) { 13298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 13398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 13498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 13598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 13698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 13798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 13898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Sample Rate 13998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 14098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_sample_rate(const alsa_device_proxy * proxy) 14198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 14298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.rate; 14398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 14498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 14598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 14698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Format 14798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 14898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanenum pcm_format proxy_get_format(const alsa_device_proxy * proxy) 14998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 15098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.format; 15198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 15298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 15398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 15498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Channel Count 15598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 15698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_channel_count(const alsa_device_proxy * proxy) 15798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 15898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.channels; 15998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 16098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 16198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 16298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Other 16398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 16498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_size(const alsa_device_proxy * proxy) 16598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 16698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_size; 16798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 16898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 16998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_count(const alsa_device_proxy * proxy) 17098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 17198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_count; 17298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 17398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 17498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_latency(const alsa_device_proxy * proxy) 17598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 17698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return (proxy_get_period_size(proxy) * proxy_get_period_count(proxy) * 1000) 17798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean / proxy_get_sample_rate(proxy); 17898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 17998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 1808785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_get_presentation_position(const alsa_device_proxy * proxy, 1818785fe142d519d8e011eecdc340a638978fb9272Andy Hung uint64_t *frames, struct timespec *timestamp) 1828785fe142d519d8e011eecdc340a638978fb9272Andy Hung{ 1838785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = -EPERM; // -1 1848785fe142d519d8e011eecdc340a638978fb9272Andy Hung unsigned int avail; 1858785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (proxy->pcm != NULL 1868785fe142d519d8e011eecdc340a638978fb9272Andy Hung && pcm_get_htimestamp(proxy->pcm, &avail, timestamp) == 0) { 1878785fe142d519d8e011eecdc340a638978fb9272Andy Hung const size_t kernel_buffer_size = 1888785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->alsa_config.period_size * proxy->alsa_config.period_count; 1898785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (avail > kernel_buffer_size) { 1908785fe142d519d8e011eecdc340a638978fb9272Andy Hung ALOGE("available frames(%u) > buffer size(%zu)", avail, kernel_buffer_size); 1918785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 1928785fe142d519d8e011eecdc340a638978fb9272Andy Hung int64_t signed_frames = proxy->transferred - kernel_buffer_size + avail; 1938785fe142d519d8e011eecdc340a638978fb9272Andy Hung // It is possible to compensate for additional driver and device delay 1948785fe142d519d8e011eecdc340a638978fb9272Andy Hung // by changing signed_frames. Example: 1958785fe142d519d8e011eecdc340a638978fb9272Andy Hung // signed_frames -= 20 /* ms */ * proxy->alsa_config.rate / 1000; 1968785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (signed_frames >= 0) { 1978785fe142d519d8e011eecdc340a638978fb9272Andy Hung *frames = signed_frames; 1988785fe142d519d8e011eecdc340a638978fb9272Andy Hung ret = 0; 1998785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2008785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2018785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2028785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 2038785fe142d519d8e011eecdc340a638978fb9272Andy Hung} 2048785fe142d519d8e011eecdc340a638978fb9272Andy Hung 20598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 20698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * I/O 20798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 2088785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_write(alsa_device_proxy * proxy, const void *data, unsigned int count) 20998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 2108785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = pcm_write(proxy->pcm, data, count); 2118785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (ret == 0) { 2128785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->transferred += count / proxy->frame_size; 2138785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2148785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 21598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 21698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 21798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count) 21898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 21998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return pcm_read(proxy->pcm, data, count); 22098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 221