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