Home | History | Annotate | Download | only in usbaudio
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "alsa_device_proxy"
     18 /*#define LOG_NDEBUG 0*/
     19 /*#define LOG_PCM_PARAMS 0*/
     20 
     21 #include <log/log.h>
     22 
     23 #include "alsa_device_proxy.h"
     24 
     25 #include "logging.h"
     26 
     27 #define DEFAULT_PERIOD_SIZE     1024
     28 #define DEFAULT_PERIOD_COUNT    2
     29 
     30 void proxy_prepare(alsa_device_proxy * proxy, alsa_device_profile* profile,
     31                    struct pcm_config * config)
     32 {
     33     ALOGV("proxy_prepare()");
     34 
     35     proxy->profile = profile;
     36 
     37 #ifdef LOG_PCM_PARAMS
     38     log_pcm_config(config, "proxy_setup()");
     39 #endif
     40 
     41     proxy->alsa_config.format =
     42         config->format != PCM_FORMAT_INVALID && profile_is_format_valid(profile, config->format)
     43             ? config->format : profile->default_config.format;
     44     proxy->alsa_config.rate =
     45         config->rate != 0 && profile_is_sample_rate_valid(profile, config->rate)
     46             ? config->rate : profile->default_config.rate;
     47     proxy->alsa_config.channels =
     48         config->channels != 0 && profile_is_channel_count_valid(profile, config->channels)
     49             ? config->channels : profile->default_config.channels;
     50 
     51     proxy->alsa_config.period_count = profile->default_config.period_count;
     52     proxy->alsa_config.period_size =
     53             profile_get_period_size(proxy->profile, proxy->alsa_config.rate);
     54 
     55     // Hack for USB accessory audio.
     56     // Here we set the correct value for period_count if tinyalsa fails to get it from the
     57     // f_audio_source driver.
     58     if (proxy->alsa_config.period_count == 0) {
     59         proxy->alsa_config.period_count = 4;
     60     }
     61 
     62     proxy->pcm = NULL;
     63 }
     64 
     65 int proxy_open(alsa_device_proxy * proxy)
     66 {
     67     alsa_device_profile* profile = proxy->profile;
     68     ALOGV("proxy_open(card:%d device:%d %s)", profile->card, profile->device,
     69           profile->direction == PCM_OUT ? "PCM_OUT" : "PCM_IN");
     70 
     71     proxy->pcm = pcm_open(profile->card, profile->device, profile->direction, &proxy->alsa_config);
     72     if (proxy->pcm == NULL) {
     73         return -ENOMEM;
     74     }
     75 
     76     if (!pcm_is_ready(proxy->pcm)) {
     77         ALOGE("[%s] proxy_open() pcm_open() failed: %s", LOG_TAG, pcm_get_error(proxy->pcm));
     78 #ifdef LOG_PCM_PARAMS
     79         log_pcm_config(&proxy->alsa_config, "config");
     80 #endif
     81         pcm_close(proxy->pcm);
     82         proxy->pcm = NULL;
     83         return -ENOMEM;
     84     }
     85 
     86     return 0;
     87 }
     88 
     89 void proxy_close(alsa_device_proxy * proxy)
     90 {
     91     ALOGV("proxy_close() [pcm:%p]", proxy->pcm);
     92 
     93     if (proxy->pcm != NULL) {
     94         pcm_close(proxy->pcm);
     95         proxy->pcm = NULL;
     96     }
     97 }
     98 
     99 /*
    100  * Sample Rate
    101  */
    102 unsigned proxy_get_sample_rate(const alsa_device_proxy * proxy)
    103 {
    104     return proxy->alsa_config.rate;
    105 }
    106 
    107 /*
    108  * Format
    109  */
    110 enum pcm_format proxy_get_format(const alsa_device_proxy * proxy)
    111 {
    112     return proxy->alsa_config.format;
    113 }
    114 
    115 /*
    116  * Channel Count
    117  */
    118 unsigned proxy_get_channel_count(const alsa_device_proxy * proxy)
    119 {
    120     return proxy->alsa_config.channels;
    121 }
    122 
    123 /*
    124  * Other
    125  */
    126 unsigned int proxy_get_period_size(const alsa_device_proxy * proxy)
    127 {
    128     return proxy->alsa_config.period_size;
    129 }
    130 
    131 unsigned int proxy_get_period_count(const alsa_device_proxy * proxy)
    132 {
    133     return proxy->alsa_config.period_count;
    134 }
    135 
    136 unsigned proxy_get_latency(const alsa_device_proxy * proxy)
    137 {
    138     return (proxy_get_period_size(proxy) * proxy_get_period_count(proxy) * 1000)
    139                / proxy_get_sample_rate(proxy);
    140 }
    141 
    142 /*
    143  * I/O
    144  */
    145 int proxy_write(const alsa_device_proxy * proxy, const void *data, unsigned int count)
    146 {
    147     return pcm_write(proxy->pcm, data, count);
    148 }
    149 
    150 int proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count)
    151 {
    152     return pcm_read(proxy->pcm, data, count);
    153 }
    154