alsa_device_proxy.c revision 8785fe142d519d8e011eecdc340a638978fb9272
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 5398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.format = 5498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format) 5598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ? config->format : profile->default_config.format; 5698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.rate = 5798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate) 5898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ? config->rate : profile->default_config.rate; 5998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.channels = 6098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean config->channels != 0 && profile_is_channel_count_valid(profile, config->channels) 6198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ? config->channels : profile->default_config.channels; 6298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 6398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = profile->default_config.period_count; 6498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_size = 6598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile_get_period_size(proxy->profile, proxy->alsa_config.rate); 6698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 6798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Hack for USB accessory audio. 6898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Here we set the correct value for period_count if tinyalsa fails to get it from the 6998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // f_audio_source driver. 7098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->alsa_config.period_count == 0) { 7198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = 4; 7298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 7398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 7498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 758785fe142d519d8e011eecdc340a638978fb9272Andy Hung // config format should be checked earlier against profile. 768785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (config->format >= 0 && (size_t)config->format < ARRAY_SIZE(format_byte_size_map)) { 778785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = format_byte_size_map[config->format] * proxy->alsa_config.channels; 788785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 798785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = 1; 808785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 8198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 8298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 8398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_open(alsa_device_proxy * proxy) 8498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 8598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean alsa_device_profile* profile = proxy->profile; 8698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_open(card:%d device:%d %s)", profile->card, profile->device, 8798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile->direction == PCM_OUT ? "PCM_OUT" : "PCM_IN"); 8898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 8998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (profile->card < 0 || profile->device < 0) { 9098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -EINVAL; 9198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 9298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 938785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->pcm = pcm_open(profile->card, profile->device, 948785fe142d519d8e011eecdc340a638978fb9272Andy Hung profile->direction | PCM_MONOTONIC, &proxy->alsa_config); 9598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm == NULL) { 9698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 9798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 9898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 9998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (!pcm_is_ready(proxy->pcm)) { 10098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGE(" proxy_open() pcm_open() failed: %s", pcm_get_error(proxy->pcm)); 10198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#if defined(LOG_PCM_PARAMS) 10298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean log_pcm_config(&proxy->alsa_config, "config"); 10398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#endif 10498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 10598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 10698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 10798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 10898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 10998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return 0; 11098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 11198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 11298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanvoid proxy_close(alsa_device_proxy * proxy) 11398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 11498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_close() [pcm:%p]", proxy->pcm); 11598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 11698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm != NULL) { 11798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 11898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 11998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 12098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 12198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 12298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 12398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Sample Rate 12498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 12598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_sample_rate(const alsa_device_proxy * proxy) 12698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 12798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.rate; 12898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 12998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 13098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 13198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Format 13298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 13398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanenum pcm_format proxy_get_format(const alsa_device_proxy * proxy) 13498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 13598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.format; 13698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 13798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 13898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 13998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Channel Count 14098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 14198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_channel_count(const alsa_device_proxy * proxy) 14298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 14398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.channels; 14498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 14598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 14698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 14798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Other 14898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 14998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_size(const alsa_device_proxy * proxy) 15098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 15198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_size; 15298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 15398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 15498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_count(const alsa_device_proxy * proxy) 15598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 15698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_count; 15798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 15898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 15998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_latency(const alsa_device_proxy * proxy) 16098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 16198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return (proxy_get_period_size(proxy) * proxy_get_period_count(proxy) * 1000) 16298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean / proxy_get_sample_rate(proxy); 16398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 16498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 1658785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_get_presentation_position(const alsa_device_proxy * proxy, 1668785fe142d519d8e011eecdc340a638978fb9272Andy Hung uint64_t *frames, struct timespec *timestamp) 1678785fe142d519d8e011eecdc340a638978fb9272Andy Hung{ 1688785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = -EPERM; // -1 1698785fe142d519d8e011eecdc340a638978fb9272Andy Hung unsigned int avail; 1708785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (proxy->pcm != NULL 1718785fe142d519d8e011eecdc340a638978fb9272Andy Hung && pcm_get_htimestamp(proxy->pcm, &avail, timestamp) == 0) { 1728785fe142d519d8e011eecdc340a638978fb9272Andy Hung const size_t kernel_buffer_size = 1738785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->alsa_config.period_size * proxy->alsa_config.period_count; 1748785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (avail > kernel_buffer_size) { 1758785fe142d519d8e011eecdc340a638978fb9272Andy Hung ALOGE("available frames(%u) > buffer size(%zu)", avail, kernel_buffer_size); 1768785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 1778785fe142d519d8e011eecdc340a638978fb9272Andy Hung int64_t signed_frames = proxy->transferred - kernel_buffer_size + avail; 1788785fe142d519d8e011eecdc340a638978fb9272Andy Hung // It is possible to compensate for additional driver and device delay 1798785fe142d519d8e011eecdc340a638978fb9272Andy Hung // by changing signed_frames. Example: 1808785fe142d519d8e011eecdc340a638978fb9272Andy Hung // signed_frames -= 20 /* ms */ * proxy->alsa_config.rate / 1000; 1818785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (signed_frames >= 0) { 1828785fe142d519d8e011eecdc340a638978fb9272Andy Hung *frames = signed_frames; 1838785fe142d519d8e011eecdc340a638978fb9272Andy Hung ret = 0; 1848785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 1858785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 1868785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 1878785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 1888785fe142d519d8e011eecdc340a638978fb9272Andy Hung} 1898785fe142d519d8e011eecdc340a638978fb9272Andy Hung 19098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 19198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * I/O 19298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 1938785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_write(alsa_device_proxy * proxy, const void *data, unsigned int count) 19498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 1958785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = pcm_write(proxy->pcm, data, count); 1968785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (ret == 0) { 1978785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->transferred += count / proxy->frame_size; 1988785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 1998785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 20098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 20198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 20298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count) 20398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 20498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return pcm_read(proxy->pcm, data, count); 20598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 206