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" 182a3925e95a9d4954be789dc4594233d4cc2d251cPaul 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 2582d945007ff47d7e7fa9390b8a8afe8620c1fc5eTri Vo#include <stdio.h> 2682d945007ff47d7e7fa9390b8a8afe8620c1fc5eTri Vo 2798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include "include/alsa_device_proxy.h" 2898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#include "include/alsa_logging.h" 3098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 3198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#define DEFAULT_PERIOD_SIZE 1024 3298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#define DEFAULT_PERIOD_COUNT 2 3398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 348785fe142d519d8e011eecdc340a638978fb9272Andy Hung#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 358785fe142d519d8e011eecdc340a638978fb9272Andy Hung 368785fe142d519d8e011eecdc340a638978fb9272Andy Hungstatic const unsigned format_byte_size_map[] = { 378785fe142d519d8e011eecdc340a638978fb9272Andy Hung 2, /* PCM_FORMAT_S16_LE */ 388785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4, /* PCM_FORMAT_S32_LE */ 398785fe142d519d8e011eecdc340a638978fb9272Andy Hung 1, /* PCM_FORMAT_S8 */ 408785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4, /* PCM_FORMAT_S24_LE */ 418785fe142d519d8e011eecdc340a638978fb9272Andy Hung 3, /* PCM_FORMAT_S24_3LE */ 428785fe142d519d8e011eecdc340a638978fb9272Andy Hung}; 438785fe142d519d8e011eecdc340a638978fb9272Andy Hung 4449bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurentint proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile, 4598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean struct pcm_config * config) 4698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 4749bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent int ret = 0; 4849bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent 4998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_prepare(c:%d, d:%d)", profile->card, profile->device); 502a3925e95a9d4954be789dc4594233d4cc2d251cPaul Mclean 5198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->profile = profile; 5298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 5398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#ifdef LOG_PCM_PARAMS 5498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean log_pcm_config(config, "proxy_setup()"); 5598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#endif 5698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 57a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format)) { 58a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.format = config->format; 59a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 6049bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent proxy->alsa_config.format = profile->default_config.format; 61a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean ALOGW("Invalid format %d - using default %d.", 62a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean config->format, profile->default_config.format); 6349bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent // Indicate override when default format was not requested 6449bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent if (config->format != PCM_FORMAT_INVALID) { 6549bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent ret = -EINVAL; 6649bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent } 67a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 68a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean 69a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate)) { 70a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.rate = config->rate; 71a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 7249bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent proxy->alsa_config.rate = profile->default_config.rate; 73a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean ALOGW("Invalid sample rate %u - using default %u.", 74a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean config->rate, profile->default_config.rate); 7549bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent // Indicate override when default rate was not requested 7649bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent if (config->rate != 0) { 7749bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent ret = -EINVAL; 7849bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent } 79a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 80a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean 81a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean if (config->channels != 0 && profile_is_channel_count_valid(profile, config->channels)) { 82a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean proxy->alsa_config.channels = config->channels; 83a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } else { 84eafa18a241f1e1f82f8586d7686f16470506640ePaul McLean proxy->alsa_config.channels = profile_get_closest_channel_count(profile, config->channels); 85eafa18a241f1e1f82f8586d7686f16470506640ePaul McLean ALOGW("Invalid channel count %u - using closest %u.", 86eafa18a241f1e1f82f8586d7686f16470506640ePaul McLean config->channels, proxy->alsa_config.channels); 8749bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent // Indicate override when default channel count was not requested 8849bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent if (config->channels != 0) { 8949bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent ret = -EINVAL; 9049bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent } 91a70650a4e01987a5f5096fdeef0c32e55ba45a09Paul McLean } 9298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 9398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = profile->default_config.period_count; 9498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_size = 9598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile_get_period_size(proxy->profile, proxy->alsa_config.rate); 9698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 9798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Hack for USB accessory audio. 9898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // Here we set the correct value for period_count if tinyalsa fails to get it from the 9998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean // f_audio_source driver. 10098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->alsa_config.period_count == 0) { 10198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->alsa_config.period_count = 4; 10298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 10398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 10498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 1058785fe142d519d8e011eecdc340a638978fb9272Andy Hung // config format should be checked earlier against profile. 1068785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (config->format >= 0 && (size_t)config->format < ARRAY_SIZE(format_byte_size_map)) { 1078785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = format_byte_size_map[config->format] * proxy->alsa_config.channels; 1088785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 1098785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->frame_size = 1; 1108785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 111948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 112948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean // let's check to make sure we can ACTUALLY use the maximum rate (with the channel count) 113948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean // Note that profile->sample_rates is sorted highest to lowest, so the scan will get 114948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean // us the highest working rate 115948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean int max_rate_index = proxy_scan_rates(proxy, profile->sample_rates); 116948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean if (max_rate_index >= 0) { 11749bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent if (proxy->alsa_config.rate > profile->sample_rates[max_rate_index]) { 11849bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent ALOGW("Limiting samplnig rate from %u to %u.", 11949bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent proxy->alsa_config.rate, profile->sample_rates[max_rate_index]); 12049bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent proxy->alsa_config.rate = profile->sample_rates[max_rate_index]; 12149bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent ret = -EINVAL; 12249bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent } 123948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean } 12449bc03cfdc9f748c53bd989a3aaf4cd7ec4f4692Eric Laurent return ret; 12598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 12698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 12798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_open(alsa_device_proxy * proxy) 12898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 12998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean alsa_device_profile* profile = proxy->profile; 13098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_open(card:%d device:%d %s)", profile->card, profile->device, 13198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean profile->direction == PCM_OUT ? "PCM_OUT" : "PCM_IN"); 13298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 13398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (profile->card < 0 || profile->device < 0) { 13498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -EINVAL; 13598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 13698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 1378785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->pcm = pcm_open(profile->card, profile->device, 1388785fe142d519d8e011eecdc340a638978fb9272Andy Hung profile->direction | PCM_MONOTONIC, &proxy->alsa_config); 13998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm == NULL) { 14098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 14198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 14298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 14398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (!pcm_is_ready(proxy->pcm)) { 144948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean ALOGE(" proxy_open() pcm_is_ready() failed: %s", pcm_get_error(proxy->pcm)); 14598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#if defined(LOG_PCM_PARAMS) 14698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean log_pcm_config(&proxy->alsa_config, "config"); 14798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean#endif 14898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 14998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 15098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return -ENOMEM; 15198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 15298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 15398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return 0; 15498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 15598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 15698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanvoid proxy_close(alsa_device_proxy * proxy) 15798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 15898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean ALOGV("proxy_close() [pcm:%p]", proxy->pcm); 15998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 16098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean if (proxy->pcm != NULL) { 16198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean pcm_close(proxy->pcm); 16298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean proxy->pcm = NULL; 16398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean } 16498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 16598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 16698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 16798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Sample Rate 16898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 16998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_sample_rate(const alsa_device_proxy * proxy) 17098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 17198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.rate; 17298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 17398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 17498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 17598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Format 17698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 17798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanenum pcm_format proxy_get_format(const alsa_device_proxy * proxy) 17898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 17998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.format; 18098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 18198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 18298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 18398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Channel Count 18498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 18598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_channel_count(const alsa_device_proxy * proxy) 18698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 18798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.channels; 18898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 18998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 19098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 19198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * Other 19298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 19398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_size(const alsa_device_proxy * proxy) 19498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 19598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_size; 19698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 19798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 19898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned int proxy_get_period_count(const alsa_device_proxy * proxy) 19998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 20098ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return proxy->alsa_config.period_count; 20198ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 20298ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 20398ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanunsigned proxy_get_latency(const alsa_device_proxy * proxy) 20498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 20598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return (proxy_get_period_size(proxy) * proxy_get_period_count(proxy) * 1000) 20698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean / proxy_get_sample_rate(proxy); 20798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 20898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 2098785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_get_presentation_position(const alsa_device_proxy * proxy, 2108785fe142d519d8e011eecdc340a638978fb9272Andy Hung uint64_t *frames, struct timespec *timestamp) 2118785fe142d519d8e011eecdc340a638978fb9272Andy Hung{ 2128785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = -EPERM; // -1 2138785fe142d519d8e011eecdc340a638978fb9272Andy Hung unsigned int avail; 2148785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (proxy->pcm != NULL 2158785fe142d519d8e011eecdc340a638978fb9272Andy Hung && pcm_get_htimestamp(proxy->pcm, &avail, timestamp) == 0) { 2168785fe142d519d8e011eecdc340a638978fb9272Andy Hung const size_t kernel_buffer_size = 2178785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->alsa_config.period_size * proxy->alsa_config.period_count; 2188785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (avail > kernel_buffer_size) { 2198785fe142d519d8e011eecdc340a638978fb9272Andy Hung ALOGE("available frames(%u) > buffer size(%zu)", avail, kernel_buffer_size); 2208785fe142d519d8e011eecdc340a638978fb9272Andy Hung } else { 2218785fe142d519d8e011eecdc340a638978fb9272Andy Hung int64_t signed_frames = proxy->transferred - kernel_buffer_size + avail; 2228785fe142d519d8e011eecdc340a638978fb9272Andy Hung // It is possible to compensate for additional driver and device delay 2238785fe142d519d8e011eecdc340a638978fb9272Andy Hung // by changing signed_frames. Example: 2248785fe142d519d8e011eecdc340a638978fb9272Andy Hung // signed_frames -= 20 /* ms */ * proxy->alsa_config.rate / 1000; 2258785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (signed_frames >= 0) { 2268785fe142d519d8e011eecdc340a638978fb9272Andy Hung *frames = signed_frames; 2278785fe142d519d8e011eecdc340a638978fb9272Andy Hung ret = 0; 2288785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2298785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2308785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2318785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 2328785fe142d519d8e011eecdc340a638978fb9272Andy Hung} 2338785fe142d519d8e011eecdc340a638978fb9272Andy Hung 23498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean/* 23598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean * I/O 23698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean */ 2378785fe142d519d8e011eecdc340a638978fb9272Andy Hungint proxy_write(alsa_device_proxy * proxy, const void *data, unsigned int count) 23898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 2398785fe142d519d8e011eecdc340a638978fb9272Andy Hung int ret = pcm_write(proxy->pcm, data, count); 2408785fe142d519d8e011eecdc340a638978fb9272Andy Hung if (ret == 0) { 2418785fe142d519d8e011eecdc340a638978fb9272Andy Hung proxy->transferred += count / proxy->frame_size; 2428785fe142d519d8e011eecdc340a638978fb9272Andy Hung } 2438785fe142d519d8e011eecdc340a638978fb9272Andy Hung return ret; 24498ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 24598ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean 24698ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLeanint proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count) 24798ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean{ 24898ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean return pcm_read(proxy->pcm, data, count); 24998ca8d42b782987cd1ceb370c10460c3eb79223ePaul McLean} 25021b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean 25121b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean/* 25221b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean * Debugging 25321b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean */ 25421b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLeanvoid proxy_dump(const alsa_device_proxy* proxy, int fd) 25521b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean{ 25621b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean if (proxy != NULL) { 25721b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean dprintf(fd, " channels: %d\n", proxy->alsa_config.channels); 25821b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean dprintf(fd, " rate: %d\n", proxy->alsa_config.rate); 25921b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean dprintf(fd, " period_size: %d\n", proxy->alsa_config.period_size); 26021b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean dprintf(fd, " period_count: %d\n", proxy->alsa_config.period_count); 26121b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean dprintf(fd, " format: %d\n", proxy->alsa_config.format); 26221b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean } 26321b04ade57e5cbf33eff11f3f400f77eed5e2e75Paul McLean} 264948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 265948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLeanint proxy_scan_rates(alsa_device_proxy * proxy, unsigned sample_rates[]) { 266948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean alsa_device_profile* profile = proxy->profile; 267948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean if (profile->card < 0 || profile->device < 0) { 268948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean return -EINVAL; 269948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean } 270948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 271948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean struct pcm_config alsa_config; 272948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean memcpy(&alsa_config, &proxy->alsa_config, sizeof(alsa_config)); 273948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 274948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean struct pcm * alsa_pcm; 275948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean int rate_index = 0; 276948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean while (sample_rates[rate_index] != 0) { 277948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean alsa_config.rate = sample_rates[rate_index]; 278948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean alsa_pcm = pcm_open(profile->card, profile->device, 279948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean profile->direction | PCM_MONOTONIC, &alsa_config); 280948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean if (alsa_pcm != NULL) { 281948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean if (pcm_is_ready(alsa_pcm)) { 282948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean pcm_close(alsa_pcm); 283948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean return rate_index; 284948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean } 285948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 286948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean pcm_close(alsa_pcm); 287948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean } 288948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 289948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean rate_index++; 290948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean } 291948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean 292948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean return -EINVAL; 293948a6a4ba0fdda99dc36bfc2ff9dec121792c051Paul McLean} 294