119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/*
219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Copyright (C) 2012 The Android Open Source Project
319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Licensed under the Apache License, Version 2.0 (the "License");
519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * you may not use this file except in compliance with the License.
619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * You may obtain a copy of the License at
719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *      http://www.apache.org/licenses/LICENSE-2.0
919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
1019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Unless required by applicable law or agreed to in writing, software
1119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * See the License for the specific language governing permissions and
1419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * limitations under the License.
1519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */
1619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#define LOG_TAG "usb_audio_hw"
1819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/*#define LOG_NDEBUG 0*/
1919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <errno.h>
2119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <pthread.h>
2219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdint.h>
2319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <sys/time.h>
2419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdlib.h>
2519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/log.h>
2719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/str_parms.h>
2819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/properties.h>
2919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/hardware.h>
3119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <system/audio.h>
3219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/audio.h>
3319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <tinyalsa/asoundlib.h>
3519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct pcm_config pcm_config = {
3719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .channels = 2,
3819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .rate = 44100,
3919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .period_size = 1024,
4019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .period_count = 4,
4119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .format = PCM_FORMAT_S16_LE,
4219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
4319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
4419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
4519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
4619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
4719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
4819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int card;
4919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int device;
5019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
5119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
5219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
5319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
5419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
5519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
5619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
5719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct pcm *pcm;
5819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
5919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *dev;
6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
6219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/**
6419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * NOTE: when multiple mutexes have to be acquired, always respect the
6519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * following order: hw device > out stream
6619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */
6719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/* Helper functions */
6919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/* must be called with hw device and output stream mutexes locked */
7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int start_output_stream(struct stream_out *out)
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = out->dev;
7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int i;
7519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if ((adev->card < 0) || (adev->device < 0))
7719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
7819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->pcm = pcm_open(adev->card, adev->device, PCM_OUT, &pcm_config);
8019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
8119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->pcm && !pcm_is_ready(out->pcm)) {
8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ALOGE("pcm_open() failed: %s", pcm_get_error(out->pcm));
8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        pcm_close(out->pcm);
8419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
8519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
8619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
8719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
8819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
8919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
9019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/* API functions */
9119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
9219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
9319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
9419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return pcm_config.rate;
9519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
9619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
9719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
9819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
9919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
10019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
10119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
10219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
10319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
10419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return pcm_config.period_size *
10519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson           audio_stream_frame_size((struct audio_stream *)stream);
10619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
10719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
10819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
10919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
11019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_CHANNEL_OUT_STEREO;
11119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
11219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
11519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_FORMAT_PCM_16_BIT;
11619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
11819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
11919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
12019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
12119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
12219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
12319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
12419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
12519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
12619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
12719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
12819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
12919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
13019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
13119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        pcm_close(out->pcm);
13219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->pcm = NULL;
13319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
13419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
13519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
13619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
13719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
13819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
13919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
14019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
14119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
14219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
14319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
14419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
14519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
14619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
14719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
14819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
14919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
15019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = out->dev;
15119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct str_parms *parms;
15219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
15319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
15419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
15519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
15619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    parms = str_parms_create_str(kvpairs);
15719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&adev->lock);
15819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
15919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    ret = str_parms_get_str(parms, "card", value, sizeof(value));
16019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret >= 0)
16119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        adev->card = atoi(value);
16219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
16319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    ret = str_parms_get_str(parms, "device", value, sizeof(value));
16419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret >= 0)
16519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        adev->device = atoi(value);
16619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
16719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&adev->lock);
16819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
16919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
17019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
17119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
17219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
17319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
17419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
17519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return strdup("");
17619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
17719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
17819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
17919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
18019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return (pcm_config.period_size * pcm_config.period_count * 1000) /
18119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            out_get_sample_rate(&stream->common);
18219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
18319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
18419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_volume(struct audio_stream_out *stream, float left,
18519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                          float right)
18619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
18719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
18819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
18919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
19019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
19119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                         size_t bytes)
19219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
19319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
19419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
19519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
19619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
19719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
19819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
19919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
20019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
20119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
20219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
20319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
20419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
20519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
20619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pcm_write(out->pcm, (void *)buffer, bytes);
20719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
20819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
20919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
21019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
21119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
21219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
21319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
21419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
2151482406b70a254fc85d153a7066d7f90d724d195Amit Shekhar    pthread_mutex_unlock(&out->dev->lock);
21619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
21719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
21819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
21919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
22019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
22119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
22219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
22319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
22419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_get_render_position(const struct audio_stream_out *stream,
22519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   uint32_t *dsp_frames)
22619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
22719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
22819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
22919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
23019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
23119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
23219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
23319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
23419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
23519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
23619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
23719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
23819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
23919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream,
24119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                        int64_t *timestamp)
24219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
24319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
24746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
24846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
24946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
25046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_out **stream_out)
25219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
25319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
25419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
25519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
25619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
25819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
26219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
26319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
26419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
26519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
26619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
26719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
26819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
26919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
27019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
27119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
27219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
27319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
27419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
27519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood    config->format = out_get_format(&out->stream.common);
28246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood    config->channel_mask = out_get_channels(&out->stream.common);
28346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood    config->sample_rate = out_get_sample_rate(&out->stream.common);
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->standby = true;
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood    adev->card = -1;
28846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood    adev->device = -1;
28946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
29019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return ret;
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
30519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
30919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
31119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic char * adev_get_parameters(const struct audio_hw_device *dev,
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  const char *keys)
31519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
31619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return strdup("");
31719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev)
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
32119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
32219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
32319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
32519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
32619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
32819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
33019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
33219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
34119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
34219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
34519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
34619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
34719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
35046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
35219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
35319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
35419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
35546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
35646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
35746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
35846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  struct audio_config *config,
35919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  struct audio_stream_in **stream_in)
36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
36119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
36219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_input_stream(struct audio_hw_device *dev,
36519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_in *stream)
36619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
36719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
37019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
37119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
37219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
37319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
37419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
37519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
37619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)device;
37719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
37819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
37919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
38019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
38119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open(const hw_module_t* module, const char* name,
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                     hw_device_t** device)
38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev;
38619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
38819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
39019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev = calloc(1, sizeof(struct audio_device));
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
39419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
39685e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
39719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.module = (struct hw_module_t *) module;
39819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
39919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
40019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
40119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
40219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
40319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
40419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
40519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
40619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
40719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
40819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
40919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
41019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
41119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
41219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
41319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
41419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
41519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
41619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
41719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
41819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
41919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
42119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
42219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
42319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
42746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
42846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
435