audio_hal.c revision eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1
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
36eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* This is the default configuration to hand to The Framework on the initial
37eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream(). Actual device attributes will be used on the subsequent
38eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream() after the card and device number have been set in out_set_parameters()
39eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
40eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_SIZE 1024
41eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_COUNT 4
42eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_SAMPLING_RATE 44100
43eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
44eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_out_config = {
4519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .channels = 2,
46eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .rate = OUT_SAMPLING_RATE,
47eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_size = OUT_PERIOD_SIZE,
48eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_count = OUT_PERIOD_COUNT,
4919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .format = PCM_FORMAT_S16_LE,
5019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
5119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
52eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
53eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Input defaults.  See comment above.
54eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_SIZE 1024
56eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_COUNT 4
57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_SAMPLING_RATE 44100
58eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
59eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_in_config = {
60eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .channels = 2,
61eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .rate = IN_SAMPLING_RATE,
62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_size = IN_PERIOD_SIZE,
63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_count = IN_PERIOD_COUNT,
64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .format = PCM_FORMAT_S16_LE,
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .start_threshold = 1,
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .stop_threshold = (IN_PERIOD_SIZE * IN_PERIOD_COUNT),
67eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
6919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
7019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
73eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
74eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
75eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_card;
76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_device;
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_card;
80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_device;
81eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
8419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
8519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
8619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
8719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
88eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
89eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm *pcm;                    /* state of the stream */
90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *dev;           /* hardware information */
93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Output Configuration Cache
102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * FIXME(pmclean) This is not rentrant. Should probably be moved into the stream structure
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * but that will involve changes in The Framework.
104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic struct pcm_config cached_output_hardware_config;
106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic bool output_hardware_config_is_cached = false;
107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
108eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
109eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
110eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
11119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
11219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct pcm *pcm;
11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
115eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_config alsa_pcm_config;
116eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *dev;
118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_config hal_pcm_config;
120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
121eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned int requested_rate;
122eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_itfe *resampler;
123eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_buffer_provider buf_provider;
124eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int16_t *buffer;
125eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t buffer_size;
126eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t frames_in;
127eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int read_status;
12819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
12919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
130eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
131eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Utility
132eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
133eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
134eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Translates from ALSA format ID to ANDROID_AUDIO_CORE format ID
135eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * (see master/system/core/include/core/audio.h)
136eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean) Replace with audio_format_from_pcm_format() (in hardware/audio_alsaops.h).
137eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   post-integration.
13819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */
139eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t alsa_to_fw_format_id(int alsa_fmt_id)
140eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
141eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    switch (alsa_fmt_id) {
142eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S8:
143eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_8_BIT;
14419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_3LE:
146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        //TODO(pmclean) make sure this is the 'right' sort of 24-bit
147eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_8_24_BIT;
14819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S32_LE:
150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_LE:
151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_32_BIT;
152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
153eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
154eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return AUDIO_FORMAT_PCM_16_BIT;
155eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
156eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
157eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
158eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
159eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
160eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
161eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Convert a buffer of PCM16LE samples to packed (3-byte) PCM24LE samples.
162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   in_buff points to the buffer of PCM16 samples
163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   out_buff points to the buffer to receive converted PCM24 LE samples.
165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   returns the number of BYTES of output data.
166eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
167eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support PCM24_3LE (24-bit, packed).
168eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: we're just filling the low-order byte of the PCM24LE samples with 0.
169eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
170eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
171eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t convert_16_to_24_3(unsigned short * in_buff,
172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                 size_t num_in_samples,
173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                 unsigned char * out_buff) {
174eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
175eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Move from back to front so that the conversion can be done in-place
176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * i.e. in_buff == out_buff
177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
178eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_buff_size_in_bytes = num_in_samples * 2;
179eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* we need 3 bytes in the output for every 2 bytes in the input */
180eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_buff_size_in_bytes = ((3 * in_buff_size_in_bytes) / 2);
181eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned char* dst_ptr = out_buff + out_buff_size_in_bytes - 1;
182eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int src_smpl_index;
183eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned char* src_ptr = ((unsigned char *)in_buff) + in_buff_size_in_bytes - 1;
184eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
185eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* hi-byte */
186eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* low-byte */
187eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = 0;          /* zero-byte */
188eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
189eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
190eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* return number of *bytes* generated */
191eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return out_buff_size_in_bytes;
192eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
193eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
194eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Convert a buffer of 2-channel PCM16 samples to 4-channel PCM16 channels
196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   in_buff points to the buffer of PCM16 samples
197eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   out_buff points to the buffer to receive converted PCM16 samples.
199eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   returns the number of BYTES of output data.
200eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE channels 3 & 4 are filled with silence.
201eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to
202eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support 4-channel devices.
203eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
204eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
205eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t convert_2chan16_to_4chan16(unsigned short* in_buff,
206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                          size_t num_in_samples,
207eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                          unsigned short* out_buff) {
208eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
209eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Move from back to front so that the conversion can be done in-place
210eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * i.e. in_buff == out_buff
211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
212eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_buff_size = num_in_samples * 2;
213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned short* dst_ptr = out_buff + out_buff_size - 1;
214eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int src_index;
215eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned short* src_ptr = in_buff + num_in_samples - 1;
216eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    for (src_index = 0; src_index < num_in_samples; src_index += 2) {
217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = 0;          /* chan 4 */
218eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = 0;          /* chan 3 */
219eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* chan 2 */
220eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* chan 1 */
221eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
223eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* return number of *bytes* generated */
224eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return out_buff_size * 2;
225eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
226eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
227eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
228eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * ALSA Utilities
229eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
230eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * gets the ALSA bit-format flag from a bits-per-sample value.
232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
234eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int bits_to_alsa_format(int bits_per_sample, int default_format)
23519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
236eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    enum pcm_format format;
237eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    for (format = PCM_FORMAT_S16_LE; format < PCM_FORMAT_MAX; format++) {
238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (pcm_format_to_bits(format) == bits_per_sample) {
239eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            return  format;
240eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean         }
241eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
242eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return default_format;
243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
245eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
246eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Reads and decodes configuration info from the specified ALSA card/device
247eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
248eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config)
249eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
250eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw - read_alsa_device_config(card:%d device:%d)", card, device);
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
252eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (card < 0 || device < 0) {
253eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
254eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
25519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
256eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type);
257eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (alsa_hw_params == NULL) {
258eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
261eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
262eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * This Logging will be useful when testing new USB devices.
263eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
264eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_SAMPLE_BITS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS)); */
265eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_FRAME_BITS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_FRAME_BITS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_FRAME_BITS)); */
266eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_CHANNELS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); */
267eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_RATE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); */
268eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_TIME)); */
269eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_SIZE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE)); */
270eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_BYTES min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_BYTES), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_BYTES)); */
271eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_PERIODS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS)); */
272eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_TIME)); */
273eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_SIZE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_SIZE)); */
274eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_BYTES min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_BYTES), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_BYTES)); */
275eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* ALOGV("usb:audio_hw - PCM_PARAM_TICK_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_TICK_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_TICK_TIME)); */
276eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
277eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
278eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
279eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS);
280eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
281eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
282eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int bits_per_sample = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
283eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->format = bits_to_alsa_format(bits_per_sample, PCM_FORMAT_S16_LE);
284eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
288eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
289eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
290eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
291eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
292eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
293eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
294eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
296eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
299eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.rate;
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.period_size * audio_stream_frame_size(stream);
31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
31319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
314eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Always Stero for now. We will do *some* conversions in this HAL.
315eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary channels
316eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // rewrite this to return the ACTUAL channel format
31719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_CHANNEL_OUT_STEREO;
31819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
32119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Always return 16-bit PCM. We will do *some* conversions in this HAL.
323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary PCM formats
324eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // rewrite this to return the ACTUAL data format
32519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_FORMAT_PCM_16_BIT;
32619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
32919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
33619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
33919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
34119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        pcm_close(out->pcm);
34219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->pcm = NULL;
34319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
34519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
34719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
34819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
35019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
35219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
35319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
35419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
35519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
35619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
35719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
35819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
359eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
360eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
36119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
36219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = out->dev;
36319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct str_parms *parms;
36419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
365eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
36619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
367eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
36819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    parms = str_parms_create_str(kvpairs);
37019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&adev->lock);
37119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool recache_device_params = false;
373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
374eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_card = atoi(value);
376eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
378eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
380eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
381eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_device = atoi(value);
382eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
383eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
385eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) {
386eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT,
387eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                            &(cached_output_hardware_config));
388eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        output_hardware_config_is_cached = (ret_value == 0);
389eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
39019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&adev->lock);
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
394eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
39619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
397eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters()
398eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type)
399eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
400eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys) {
401eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_out *out = (struct stream_out *) stream;
402eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
403eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
404eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned min, max;
405eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
406eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *query = str_parms_create_str(keys);
407eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *result = str_parms_create();
408eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_written = 0;
410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char buffer[256];
411eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
412eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char* result_str = NULL;
413eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
414eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT);
415eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
416eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // These keys are from hardware/libhardware/include/audio.h
417eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample rates
418eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
420eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // if they are different, return a list containing those two values, otherwise just the one.
421eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
422eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
424eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
425eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d",
426eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                     max);
427eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
428eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
429eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                          buffer);
430eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
431eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
432eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported channel counts
433eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
434eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // Similarly for output channels count
435eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
436eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
437eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
438eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
439eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
440eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
441eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer);
442eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
443eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
444eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample formats
445eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
446eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // Similarly for output channels count
447eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        //TODO(pmclean): this is wrong.
448eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
449eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
450eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
451eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
452eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
453eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
454eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer);
455eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
456eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
457eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    result_str = str_parms_to_str(result);
458eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
459eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // done with these...
460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(query);
461eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(result);
462eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
463eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return result_str;
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
468eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_out *out = (struct stream_out *)stream;
469eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
470eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean): Do we need a term here for the USB latency
471eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // (as reported in the USB descriptors)?
472eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    uint32_t latency = (cached_output_hardware_config.period_size *
473eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        cached_output_hardware_config.period_count * 1000) / out_get_sample_rate(&stream->common);
474eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return latency;
47519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_volume(struct audio_stream_out *stream, float left,
47819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                          float right)
47919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
48019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
48119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
48219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
484eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
485eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
487eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int return_val = 0;
488eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
490eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean           adev->out_card, adev->out_device);
491eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
492eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config);
493eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm == NULL) {
494eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
495eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
496eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
497eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm && !pcm_is_ready(out->pcm)) {
498eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ALOGE("audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(out->pcm));
499eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_close(out->pcm);
500eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
501eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
502eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
503eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Setup conversion buffer
504eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t buffer_size = out_get_buffer_size(&(out->stream.common));
505eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
506eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // computer maximum potential buffer size.
507eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // * 2 for stereo -> quad conversion
508eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // * 3/2 for 16bit -> 24 bit conversion
509eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) - remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
510eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // (and do these conversions themselves)
511eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = (buffer_size * 3 * 2) / 2;
512eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size);
513eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
514eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
515eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
516eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
517eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
51819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
51919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
52019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
52119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
52219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
52319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
52419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
52519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
52619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
52719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
52819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
52919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
53019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
53119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
532eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * write_buff = buffer;
533eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
534eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
535eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
536eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Num Channels conversion
537eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
538eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_device_channels = cached_output_hardware_config.channels;
539eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_req_channels = 2; /* always, for now */
540eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (num_device_channels != num_req_channels && num_device_channels == 4) {
541eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
542eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                convert_2chan16_to_4chan16(write_buff, num_write_buff_bytes / 2,
543eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                           out->conversion_buffer);
544eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
545eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
546eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
547eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
548eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     *  16 vs 24-bit logic here
549eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
550eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    switch (cached_output_hardware_config.format) {
551eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S16_LE:
552eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // the output format is the same as the input format, so just write it out
553eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
554eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
555eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_3LE:
556eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // 16-bit LE2 - 24-bit LE3
557eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
558eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                convert_16_to_24_3(write_buff, num_write_buff_bytes / 2, out->conversion_buffer);
559eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
560eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
561eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
562eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    default:
563eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // hmmmmm.....
564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ALOGV("usb:Unknown Format!!!");
565eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
566eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
567eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
568eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
569eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_write(out->pcm, write_buff, num_write_buff_bytes);
570eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
57119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
57319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
57419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
57619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
57819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
579f9953b7d52bcf560b15efde807f41cf0903e875dAmit Shekhar    pthread_mutex_unlock(&out->dev->lock);
58019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
58119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
58219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
58419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
58719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_get_render_position(const struct audio_stream_out *stream,
58919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   uint32_t *dsp_frames)
59019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
59119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
59219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
59319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
59419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
59519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
59619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
59719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
59819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
59919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
60119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
60219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
60419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream,
60519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                        int64_t *timestamp)
60619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
61146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
61246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
61346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
61446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_out **stream_out)
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
617eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, devices:0x%X, flags:0x%X",
618eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
619eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
62019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
621eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
62219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
62319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
62419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
62519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
62619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
62719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
628eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
62919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
63019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
63119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
63219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
63319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
63419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
63519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
63619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
63719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
63819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
63919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
64019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
64119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
64219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
64319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
64419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
64519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
64619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
64719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
64819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (output_hardware_config_is_cached) {
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = cached_output_hardware_config.rate;
65119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->format = alsa_to_fw_format_id(cached_output_hardware_config.format);
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // Always report PCM16 for now. AudioPolicyManagerBase/AudioFlinger dont' understand
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // formats with more other format, so we won't get chosen (say with a 24bit DAC).
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            //TODO(pmclean) remove this when the above restriction is removed.
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->format = AUDIO_FORMAT_PCM_16_BIT;
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
65919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask =
661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                audio_channel_out_mask_from_count(cached_output_hardware_config.channels);
662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) {
663eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // Always report STEREO for now.  AudioPolicyManagerBase/AudioFlinger dont' understand
664eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // formats with more channels, so we won't get chosen (say with a 4-channel DAC).
665eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            //TODO(pmclean) remove this when the above restriction is removed.
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    } else {
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        cached_output_hardware_config = default_alsa_out_config;
670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->format = out_get_format(&out->stream.common);
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask = out_get_channels(&out->stream.common);
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = out_get_sample_rate(&out->stream.common);
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw  config->sample_rate:%d", config->sample_rate);
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw  config->format:0x%X", config->format);
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw  config->channel_mask:0x%X", config->channel_mask);
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
680eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
681eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
68346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
68419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
68519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
68619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
68719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
68819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
68919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
690eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
69119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
69219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
69319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
69419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
69519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
69719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
69819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
699eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) why are we doing this when stream get's freed at the end
700eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // because it closes the pcm device
70119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
70719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
70819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
70919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
71019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
71119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
71219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
71319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
71419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
71519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic char * adev_get_parameters(const struct audio_hw_device *dev,
71619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  const char *keys)
71719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
71819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return strdup("");
71919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
72019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
72119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev)
72219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
72319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
72419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
72519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
72619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
72719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
72819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
72919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
73019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
73119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
73219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
73319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
73419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
73519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
73619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
73719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
73819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
73919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
74019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
74119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
74219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
74319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
74419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
74519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
74619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
74719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
74819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
74919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
75019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
75119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
75246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
75319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
75419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
75519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
75619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return in->alsa_pcm_config.rate;
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
764eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
769eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
770eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t buff_size =
773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            in->alsa_pcm_config.period_size
774eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            * audio_stream_frame_size((struct audio_stream *)stream);
775eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return buff_size;
776eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
778eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
780eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
781eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) this should be done with a num_channels_to_alsa_channels()
782eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return in->alsa_pcm_config.channels == 2
783eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            ? AUDIO_CHANNEL_IN_STEREO : AUDIO_CHANNEL_IN_MONO;
784eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
785eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
786eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
787eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
788eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // just report 16-bit, pcm for now.
789eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return AUDIO_FORMAT_PCM_16_BIT;
790eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
791eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
792eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
793eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
794eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
795eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
796eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
797eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
798eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
799eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("-pcm-audio_hw::in in_standby() [Not Implemented]");
800eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
801eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
802eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
803eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
804eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
805eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
806eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
807eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
808eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
809eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
810eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("Vaudio_hw::in in_set_parameters() keys:%s", kvpairs);
811eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
812eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
813eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = in->dev;
814eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *parms;
815eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
816eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
817eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
818eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
819eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
820eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    parms = str_parms_create_str(kvpairs);
821eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_lock(&adev->lock);
822eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
823eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Card/Device
824eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
825eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
826eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_card = atoi(value);
827eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
828eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
829eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
830eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
831eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_device = atoi(value);
832eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
833eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
834eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (adev->in_card >= 0 && adev->in_device >= 0) {
835eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ret_value = read_alsa_device_config(adev->in_card, adev->in_device, PCM_IN, &(in->alsa_pcm_config));
836eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
837eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
838eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_unlock(&adev->lock);
839eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
840eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
841eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
842eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
843eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
844eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters()
845eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type)
846eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
847eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
848eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
849eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys);
850eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
851eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  struct stream_in *in = (struct stream_in *)stream;
852eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  struct audio_device *adev = in->dev;
853eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
854eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN);
855eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  if (alsa_hw_params == NULL)
856eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean      return strdup("");
857eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  struct str_parms *query = str_parms_create_str(keys);
859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  struct str_parms *result = str_parms_create();
860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
861eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  int num_written = 0;
862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  char buffer[256];
863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  int buffer_size = sizeof(buffer)/sizeof(buffer[0]);
864eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  char* result_str = NULL;
865eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
866eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  unsigned min, max;
867eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
868eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  // These keys are from hardware/libhardware/include/audio.h
869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  // supported sample rates
870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
871eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
872eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // if they are different, return a list containing those two values, otherwise just the one.
873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
874eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    num_written = snprintf(buffer, buffer_size, "%d", min);
876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (min != max) {
877eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean      snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
879eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer);
880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  } // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  // supported channel counts
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Similarly for output channels count
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    num_written = snprintf(buffer, buffer_size, "%d", min);
888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (min != max) {
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean      snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
890eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
891eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer);
892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  } // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
894eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  // supported sample formats
895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
896eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean): this is wrong.
897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    num_written = snprintf(buffer, buffer_size, "%d", min);
900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (min != max) {
901eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean      snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
903eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer);
904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  } // AUDIO_PARAMETER_STREAM_SUP_FORMATS
905eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  result_str = str_parms_to_str(result);
907eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  // done with these...
909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  str_parms_destroy(query);
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  str_parms_destroy(result);
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean  return result_str;
913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
923eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
925eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain) {
926eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
929eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) {
930eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in * in = (struct stream_in *)stream;
931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
932eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int err = pcm_read(in->pcm, buffer, bytes);
933eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
934eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return err == 0 ? bytes : 0;
935eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
936eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
937eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) {
938eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
939eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
940eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
94246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
94346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
944eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                  struct audio_config *hal_config,
94519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  struct audio_stream_in **stream_in)
94619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
947eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::in adev_open_input_stream() rate:%d, chanMask:0x%X, fmt:%d",
948eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          hal_config->sample_rate,
949eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          hal_config->channel_mask,
950eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          hal_config->format);
951eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
952eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
956eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
958eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
959eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
960eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
961eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
962eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
963eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
964eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
965eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
966eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
967eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
968eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
969eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
970eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
971eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
972eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
973eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
974eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)dev;
975eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->dev = adev;
976eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
977eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->standby = true;
978eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->requested_rate = hal_config->sample_rate;
979eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->alsa_pcm_config = default_alsa_in_config;
980eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
981eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (hal_config->sample_rate != 0)
982eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        in->alsa_pcm_config.rate = hal_config->sample_rate;
983eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
984eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) is this correct, or do we need to map from ALSA format?
985eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // hal_config->format is an audio_format_t
986eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // logical
987eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // hal_config->format = default_alsa_in_config.format;
988eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) use audio_format_from_pcm_format() (in hardware/audio_alsaops.h)
989eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    switch (default_alsa_in_config.format) {
990eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S32_LE:
991eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        hal_config->format = AUDIO_FORMAT_PCM_32_BIT;
992eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
993eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
994eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S8:
995eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        hal_config->format = AUDIO_FORMAT_PCM_8_BIT;
996eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
997eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
998eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_LE:
999eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        hal_config->format = AUDIO_FORMAT_PCM_8_24_BIT;
1000eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
1001eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1002eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_3LE:
1003eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        hal_config->format = AUDIO_FORMAT_PCM_8_24_BIT;
1004eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
1005eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1006eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    default:
1007eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S16_LE:
1008eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        hal_config->format = AUDIO_FORMAT_PCM_16_BIT;
1009eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
1010eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1011eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1012eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
1013eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1014eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
101519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
101619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
101719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_input_stream(struct audio_hw_device *dev,
101819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_in *stream)
101919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
102019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
102119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
102319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
102619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
102819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1029eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::adev_close()");
103019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1031eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
103219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1033eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1034eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    output_hardware_config_is_cached = false;
1035eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
103619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
103719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open(const hw_module_t* module, const char* name,
104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                     hw_device_t** device)
104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1042eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // ALOGV("usb:audio_hw::adev_open(%s)", name);
104319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
104519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
104619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1047eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
104919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
105019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
105119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
105285e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.module = (struct hw_module_t *) module;
105419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
105619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
105819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
105919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
106019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
106119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
106219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
106319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
106419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
106519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
108119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
108346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
108446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
108619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
108819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
108919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
109019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1091