audio_hal.c revision 30f4185da772fcc679db35e01148eca6eeafe15f
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"
1830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* #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
10230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. 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
11519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *dev;
116eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
117eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_config hal_pcm_config;
118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_itfe *resampler;
120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_buffer_provider buf_provider;
12130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
122eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int read_status;
12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // We may need to read more data from the device in order to data reduce to 16bit, 4chan */
12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
12919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
13019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
131eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Input Configuration Cache
13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * but that will involve changes in The Framework.
13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
13630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic struct pcm_config cached_input_hardware_config;
13730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic bool input_hardware_config_is_cached = false;
13830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
140eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Utility
141eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
142eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
143eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Translates from ALSA format ID to ANDROID_AUDIO_CORE format ID
144eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * (see master/system/core/include/core/audio.h)
145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean) Replace with audio_format_from_pcm_format() (in hardware/audio_alsaops.h).
146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   post-integration.
14719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */
148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t alsa_to_fw_format_id(int alsa_fmt_id)
149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    switch (alsa_fmt_id) {
151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S8:
152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_8_BIT;
15319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
154eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_3LE:
155eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        //TODO(pmclean) make sure this is the 'right' sort of 24-bit
156eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_8_24_BIT;
15719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
158eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S32_LE:
159eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_LE:
160eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return AUDIO_FORMAT_PCM_32_BIT;
161eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return AUDIO_FORMAT_PCM_16_BIT;
164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
166eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
167eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
168eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
169eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
170eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Convert a buffer of PCM16LE samples to packed (3-byte) PCM24LE samples.
171eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   in_buff points to the buffer of PCM16 samples
172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   out_buff points to the buffer to receive converted PCM24 LE samples.
17430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
17530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support PCM24_3LE (24-bit, packed).
17830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
17930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   We're just filling the low-order byte of the PCM24LE samples with 0.
18030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
181eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
182eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
18330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t convert_16_to_24_3(short * in_buff, size_t num_in_samples, unsigned char * out_buff) {
184eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
185eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Move from back to front so that the conversion can be done in-place
186eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * i.e. in_buff == out_buff
187eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
188eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_buff_size_in_bytes = num_in_samples * 2;
189eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* we need 3 bytes in the output for every 2 bytes in the input */
190eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_buff_size_in_bytes = ((3 * in_buff_size_in_bytes) / 2);
191eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned char* dst_ptr = out_buff + out_buff_size_in_bytes - 1;
19230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
193eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned char* src_ptr = ((unsigned char *)in_buff) + in_buff_size_in_bytes - 1;
194eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* hi-byte */
196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = *src_ptr--; /* low-byte */
19730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*TODO(pmclean) - we might want to consider dithering the lowest byte. */
198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        *dst_ptr-- = 0;          /* zero-byte */
199eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
200eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
201eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* return number of *bytes* generated */
202eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return out_buff_size_in_bytes;
203eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
204eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
205eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
20630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
20730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
208eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
20930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
21030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
21130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
21230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
21330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
21430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
21530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   We're just filling the low-order byte of the PCM24LE samples with 0.
21630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
21730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * TODO(pmclean, hung) Move this to a utilities module.
21830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
21930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t convert_24_3_to_16(unsigned char * in_buff, size_t num_in_samples, short * out_buff) {
22030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
22130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
22230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
22330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
22430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
22530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
22630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* src_ptr = in_buff;
22730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
22830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
22930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
23030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
23130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
23230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
23330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
23430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
23530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
23630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
23730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
23830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
23930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels
24030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N < M).
24130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM16 samples
24230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff_channels Specifies the number of channels in the input buffer.
243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   out_buff points to the buffer to receive converted PCM16 samples.
24430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff_channels Specifies the number of channels in the output buffer.
24530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   num_in_samples size of input buffer in SAMPLES
24630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
24730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
24830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE
24930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   channels > N are filled with silence.
25030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff)
251eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to
252eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support 4-channel devices.
253eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
254eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
25530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t expand_channels_16(short* in_buff, int in_buff_chans,
25630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                 short* out_buff, int out_buff_chans,
25730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                 size_t num_in_samples) {
258eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
259eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Move from back to front so that the conversion can be done in-place
260eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * i.e. in_buff == out_buff
26130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
26230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
26330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
26430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
26530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* dst_ptr = out_buff + num_out_samples - 1;
26630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int src_index;
26730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* src_ptr = in_buff + num_in_samples - 1;
26830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_zero_chans = out_buff_chans - in_buff_chans;
26930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
27030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        int dst_offset;
27130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        for(dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) {
27230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr-- = 0;
27330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
27430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        for(; dst_offset < out_buff_chans; dst_offset++) {
27530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr-- = *src_ptr--;
27630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
27730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
27830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
27930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated */
28030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_out_samples * sizeof(short);
28130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
28230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
28330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
28430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels
28530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N > M).
28630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM16 samples
28730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff_channels Specifies the number of channels in the input buffer.
28830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16 samples.
28930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff_channels Specifies the number of channels in the output buffer.
29030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   num_in_samples size of input buffer in SAMPLES
29130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
29230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
29330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE
29430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   channels > N are thrown away.
29530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff)
29630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to
29730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support 4-channel devices.
29830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * TODO(pmclean, hung) Move this to a utilities module.
29930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
30030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t contract_channels_16(short* in_buff, int in_buff_chans,
30130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   short* out_buff, int out_buff_chans,
30230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   size_t num_in_samples) {
30330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
30430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
30530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
30630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
30830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
30930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
31030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_skip_samples = in_buff_chans - out_buff_chans;
31130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
31230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* dst_ptr = out_buff;
31330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* src_ptr = in_buff;
314eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int src_index;
31530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
31630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        int dst_offset;
31730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        for(dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) {
31830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr++ = *src_ptr++;
31930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
32030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr += num_skip_samples;
321eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* return number of *bytes* generated */
32430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_out_samples * sizeof(short);
325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
327eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * ALSA Utilities
329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
331eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * gets the ALSA bit-format flag from a bits-per-sample value.
332eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module.
333eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
334eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int bits_to_alsa_format(int bits_per_sample, int default_format)
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    enum pcm_format format;
337eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    for (format = PCM_FORMAT_S16_LE; format < PCM_FORMAT_MAX; format++) {
338eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (pcm_format_to_bits(format) == bits_per_sample) {
33930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            return format;
34030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
341eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
342eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return default_format;
343eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
345eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
346eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Reads and decodes configuration info from the specified ALSA card/device
347eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
348eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config)
349eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
35030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",card, device, io_type);
35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
352eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (card < 0 || device < 0) {
353eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
354eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
35519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
356eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type);
357eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (alsa_hw_params == NULL) {
358eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
35919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
361eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
362eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * This Logging will be useful when testing new USB devices.
363eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
364eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
365eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
366eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
367eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
368eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
369eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
370eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
374eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul 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)); */
376eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
378eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS);
380eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
381eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
382eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int bits_per_sample = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
383eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->format = bits_to_alsa_format(bits_per_sample, PCM_FORMAT_S16_LE);
384eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
38619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
388eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
389eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
390eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
391eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
392eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
393eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
394eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
396eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
39719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
39819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
399eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.rate;
40019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
40119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
40219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
40319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
40419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
40519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
40619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
40719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
40819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.period_size * audio_stream_frame_size(stream);
41019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
41119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
41219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
41319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
414eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Always Stero for now. We will do *some* conversions in this HAL.
415eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary channels
416eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // rewrite this to return the ACTUAL channel format
41719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_CHANNEL_OUT_STEREO;
41819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
41919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
42119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
422eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Always return 16-bit PCM. We will do *some* conversions in this HAL.
423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary PCM formats
424eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // rewrite this to return the ACTUAL data format
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_FORMAT_PCM_16_BIT;
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
42719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        pcm_close(out->pcm);
44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->pcm = NULL;
44319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
44419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
44519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
44719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
44819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
45319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
459eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = out->dev;
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct str_parms *parms;
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
465eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
467eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    parms = str_parms_create_str(kvpairs);
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&adev->lock);
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
472eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool recache_device_params = false;
473eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
474eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
475eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_card = atoi(value);
476eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
477eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
478eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
479eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_device = atoi(value);
482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
485eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) {
486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT,
48730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                            &cached_output_hardware_config);
488eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        output_hardware_config_is_cached = (ret_value == 0);
489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&adev->lock);
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
494eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
497eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters()
498eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type)
499eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
50030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
50130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
50230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys);
50330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
504eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_out *out = (struct stream_out *) stream;
505eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
506eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
50730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (adev->out_card < 0 || adev->out_device < 0)
50830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
50930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
510eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned min, max;
511eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
512eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *query = str_parms_create_str(keys);
513eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *result = str_parms_create();
514eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
515eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_written = 0;
516eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char buffer[256];
517eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
518eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char* result_str = NULL;
519eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
520eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT);
521eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
522eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // These keys are from hardware/libhardware/include/audio.h
523eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample rates
524eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
525eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
526eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // if they are different, return a list containing those two values, otherwise just the one.
527eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
528eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
529eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
530eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
53130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
532eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
533eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
534eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                          buffer);
535eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
536eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
537eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported channel counts
538eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
539eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // Similarly for output channels count
540eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
541eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
542eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
543eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
544eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
545eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
546eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer);
547eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
548eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
549eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample formats
550eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
551eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // Similarly for output channels count
552eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        //TODO(pmclean): this is wrong.
553eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
554eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
555eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
556eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
557eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
558eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
559eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer);
560eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
561eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
562eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    result_str = str_parms_to_str(result);
563eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // done with these...
565eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(query);
566eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(result);
567eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
568eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return result_str;
56919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
57019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
57219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
57330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_out *out = (struct stream_out *) stream;
574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
575eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean): Do we need a term here for the USB latency
576eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // (as reported in the USB descriptors)?
57730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    uint32_t latency = (cached_output_hardware_config.period_size
57830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            * cached_output_hardware_config.period_count * 1000) / out_get_sample_rate(&stream->common);
579eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return latency;
58019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
58119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
58419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
58519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
587eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
588eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
589eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
591eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int return_val = 0;
592eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
59330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
59430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          adev->out_card, adev->out_device);
595eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
596eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config);
597eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm == NULL) {
598eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
599eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
600eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
601eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm && !pcm_is_ready(out->pcm)) {
602eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ALOGE("audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(out->pcm));
603eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_close(out->pcm);
604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
607eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
608eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
609eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
610eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
61119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
61319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
61419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
61719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
61819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
61919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
62019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
62119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
62219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
62319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
62419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
62530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // Setup conversion buffer
62630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // compute maximum potential buffer size.
62730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // * 2 for stereo -> quad conversion
62830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // * 3/2 for 16bit -> 24 bit conversion
62930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int required_conversion_buffer_size = (bytes * 3 * 2) / 2;
63030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (required_conversion_buffer_size > out->conversion_buffer_size) {
63130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        //TODO(pmclean) - remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
63230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // (and do these conversions themselves)
63330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer_size = required_conversion_buffer_size;
63430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size);
63530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
63630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
637eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * write_buff = buffer;
638eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
639eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
640eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Num Channels conversion
642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_device_channels = cached_output_hardware_config.channels;
644eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_req_channels = 2; /* always, for now */
64530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
64730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                expand_channels_16(write_buff, num_req_channels,
64830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   out->conversion_buffer, num_device_channels,
64930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   num_write_buff_bytes / sizeof(short));
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
651eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     *  16 vs 24-bit logic here
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    switch (cached_output_hardware_config.format) {
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S16_LE:
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // the output format is the same as the input format, so just write it out
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    case PCM_FORMAT_S24_3LE:
662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // 16-bit LE2 - 24-bit LE3
66330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_write_buff_bytes = convert_16_to_24_3(write_buff,
66430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                                  num_write_buff_bytes / sizeof(short),
66530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                                  out->conversion_buffer);
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    default:
670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // hmmmmm.....
671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ALOGV("usb:Unknown Format!!!");
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        break;
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_write(out->pcm, write_buff, num_write_buff_bytes);
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
67819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
67919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
68019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
68119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
68219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
68319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
68419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
68519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
686f9953b7d52bcf560b15efde807f41cf0903e875dAmit Shekhar    pthread_mutex_unlock(&out->dev->lock);
68719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
68819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
68919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
69019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
69119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
69219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
69319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
69419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
69530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
69619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
69719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
69819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
69919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
70019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
70119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
70219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
70319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
70419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
70519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
70619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
70719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
70819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
70919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
71030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
71119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
71219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
71319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
71419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
71519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
71646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
71746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
71846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
71946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
72019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_out **stream_out)
72119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
72230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X",
723eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
724eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
72519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
726eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
72719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
72819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
72919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
73019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
73119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
73219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
733eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
73419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
73519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
73619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
73719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
73819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
73919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
74019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
74119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
74219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
74319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
74419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
74519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
74619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
74719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
74819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
74919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
75019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
75119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
75219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
75319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
754eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (output_hardware_config_is_cached) {
755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = cached_output_hardware_config.rate;
75619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->format = alsa_to_fw_format_id(cached_output_hardware_config.format);
758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // Always report PCM16 for now. AudioPolicyManagerBase/AudioFlinger dont' understand
760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // formats with more other format, so we won't get chosen (say with a 24bit DAC).
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            //TODO(pmclean) remove this when the above restriction is removed.
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->format = AUDIO_FORMAT_PCM_16_BIT;
763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
76419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask =
766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                audio_channel_out_mask_from_count(cached_output_hardware_config.channels);
767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) {
768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // Always report STEREO for now.  AudioPolicyManagerBase/AudioFlinger dont' understand
769eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // formats with more channels, so we won't get chosen (say with a 4-channel DAC).
770eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            //TODO(pmclean) remove this when the above restriction is removed.
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    } else {
774eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        cached_output_hardware_config = default_alsa_out_config;
775eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
776eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->format = out_get_format(&out->stream.common);
777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask = out_get_channels(&out->stream.common);
778eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = out_get_sample_rate(&out->stream.common);
779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
780eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
781eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
782eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
783eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
784eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
78546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
78619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
78719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
78819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
78919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
79019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
79119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
792eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
79319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
79419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
79519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
79619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
79719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
798eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
79919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
80019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
801eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    //TODO(pmclean) why are we doing this when stream get's freed at the end
802eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // because it closes the pcm device
80319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
804eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
805eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
806eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
807eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
808eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
80919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
81019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
81119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
81219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
81319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
81419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
81519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
81619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
81819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
81919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return strdup("");
82019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
82119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
82219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev)
82319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
82419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
82519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
82619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
82719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
82819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
82919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
83019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
83119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
83219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
83319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
83419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
83519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
83619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
83719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
83819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
83919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
84019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
84119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
84219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
84319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
84419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
84519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
84619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
84719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
84819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
84919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
85019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
85119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
85219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
85346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
85419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
85519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
85619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
85719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
86130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return cached_input_hardware_config.rate;
862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
864eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
865eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
866eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
867eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
868eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
87130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: in_get_buffer_size() = %d",
87230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          cached_input_hardware_config.period_size * audio_stream_frame_size(stream));
87330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return cached_input_hardware_config.period_size * audio_stream_frame_size(stream);
87430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
877eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
87930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // just report stereo for now
88030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return AUDIO_CHANNEL_IN_STEREO;
881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // just report 16-bit, pcm for now.
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return AUDIO_FORMAT_PCM_16_BIT;
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
890eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
891eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
894eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
89630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *) stream;
89730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
89830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
89930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
90030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
90130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
90230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        pcm_close(in->pcm);
90330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->pcm = NULL;
90430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
90530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
90630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
90730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
90830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
90930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
92030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
923eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = in->dev;
924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *parms;
925eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
926eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
929eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
930eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    parms = str_parms_create_str(kvpairs);
931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_lock(&adev->lock);
932eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
93330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    bool recache_device_params = false;
93430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
935eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Card/Device
936eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
937eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
938eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_card = atoi(value);
93930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
940eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
941eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
942eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
943eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
944eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_device = atoi(value);
94530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
946eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
947eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (recache_device_params && adev->in_card >= 0 && adev->in_device >= 0) {
94930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ret_value = read_alsa_device_config(adev->in_card, adev->in_device,
95030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                            PCM_IN, &(cached_input_hardware_config));
95130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        input_hardware_config_is_cached = (ret_value == 0);
952eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_unlock(&adev->lock);
955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
956eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
958eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
959eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
960eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters()
961eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type)
962eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
96330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys) {
96430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys);
96530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
96630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
96730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct audio_device *adev = in->dev;
96830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
96930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (adev->in_card < 0 || adev->in_device < 0)
97030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN);
97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (alsa_hw_params == NULL)
97430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
97530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct str_parms *query = str_parms_create_str(keys);
97730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct str_parms *result = str_parms_create();
978eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
97930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_written = 0;
98030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    char buffer[256];
98130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
98230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    char* result_str = NULL;
983eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned min, max;
98530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // These keys are from hardware/libhardware/include/audio.h
98730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported sample rates
98830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
98930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
99030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // if they are different, return a list containing those two values, otherwise just the one.
99130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
99230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
99330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
99430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (min != max) {
99530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
99630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
99730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer);
99830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
999eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
100030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported channel counts
100130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
100230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // Similarly for output channels count
100330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
100430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
100530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
100630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (min != max) {
100730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
100830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
100930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer);
101030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
101130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
101230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported sample formats
101330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
101430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        //TODO(pmclean): this is wrong.
101530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
101630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS);
101730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_written = snprintf(buffer, buffer_size, "%d", min);
101830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (min != max) {
101930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            snprintf(buffer + num_written, buffer_size - num_written, "|%d", max);
102030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
102130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer);
102230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
102330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
102430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    result_str = str_parms_to_str(result);
102530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
102630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // done with these...
102730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    str_parms_destroy(query);
102830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    str_parms_destroy(result);
102930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
103030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return result_str;
1031eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1032eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1033eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
1034eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1035eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1036eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1037eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1038eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
1039eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1040eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1041eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1042eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
104430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
1045eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1046eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1047eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
104930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int start_input_stream(struct stream_in *in) {
105030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct audio_device *adev = in->dev;
105130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int return_val = 0;
105230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
105330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
105430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          adev->in_card, adev->in_device);
105530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
105630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->pcm = pcm_open(adev->in_card, adev->in_device, PCM_IN, &cached_input_hardware_config);
105730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->pcm == NULL) {
105830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ALOGE("usb:audio_hw pcm_open() in->pcm == NULL");
105930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return -ENOMEM;
106030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
106130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
106230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->pcm && !pcm_is_ready(in->pcm)) {
106330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ALOGE("usb:audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(in->pcm));
106430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        pcm_close(in->pcm);
106530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return -ENOMEM;
106630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
106730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
106830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return 0;
106930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
107030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
107130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean//TODO(pmclean) mutex stuff here (see out_write)
107230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
107330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
107430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_read_buff_bytes = 0;
107530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
107630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
107730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
107830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in * in = (struct stream_in *) stream;
107930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
108030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
108130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
108230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
108330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
108430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
108530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
108630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
108730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
108830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
108930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
109030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // OK, we need to figure out how much data to read to be able to output the requested
109130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // number of bytes in the HAL format (16-bit, stereo).
109230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
109330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_device_channels = cached_input_hardware_config.channels;
109430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_req_channels = 2; /* always, for now */
109530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
109630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
109730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes *= num_device_channels/num_req_channels;
109830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
109930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
110030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (cached_output_hardware_config.format == PCM_FORMAT_S24_3LE) {
110130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
110230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
110330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
110430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // Setup/Realloc the conversion buffer (if necessary).
110530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
110630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
110730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            //TODO(pmclean) - remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
110830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            // (and do these conversions themselves)
110930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
111030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
111130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
111230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
111330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
111430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
111530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (pcm_read(in->pcm, read_buff, num_read_buff_bytes) == 0) {
111630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
111730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
111830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
111930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
112030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (cached_output_hardware_config.format == PCM_FORMAT_S24_3LE) {
112130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
112230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
112330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
112430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
112530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Bit Format Conversion */
112630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            num_read_buff_bytes =
112730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
112830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
1129eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
113030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
113130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
113230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
113330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            num_read_buff_bytes =
113430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                contract_channels_16(read_buff, num_device_channels,
113530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                     out_buff, num_req_channels,
113630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                     num_read_buff_bytes / sizeof(short));
113730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
113830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
1139eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
114030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
114130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
114230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
114330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
114430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
1145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
114730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
114830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
1149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
115246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
115346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
115446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
115530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
115619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  struct audio_stream_in **stream_in)
115719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
115830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: in adev_open_input_stream() rate:%d, chanMask:0x%X, fmt:%d",
115930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
1160eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1161eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
1162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
1163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
1164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
1166eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
1167eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
1168eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
1169eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
1170eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
1171eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
1172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
1173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
1174eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
1175eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
1176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
1177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
1178eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1179eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
1180eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
1181eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
1182eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
118330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
1184eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
118530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (output_hardware_config_is_cached) {
118630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->sample_rate = cached_output_hardware_config.rate;
1187eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
118830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->format = alsa_to_fw_format_id(cached_output_hardware_config.format);
118930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
119030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            // Always report PCM16 for now. AudioPolicyManagerBase/AudioFlinger dont' understand
119130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            // formats with more other format, so we won't get chosen (say with a 24bit DAC).
119230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            //TODO(pmclean) remove this when the above restriction is removed.
119330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            config->format = AUDIO_FORMAT_PCM_16_BIT;
119430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
1195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
119630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->channel_mask = audio_channel_out_mask_from_count(
119730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                cached_output_hardware_config.channels);
119830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) {
119930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            // Always report STEREO for now.  AudioPolicyManagerBase/AudioFlinger dont' understand
120030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            // formats with more channels, so we won't get chosen (say with a 4-channel DAC).
120130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            //TODO(pmclean) remove this when the above restriction is removed.
120230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
120330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
120430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
120530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        cached_input_hardware_config = default_alsa_in_config;
1206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
120730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->format = out_get_format(&in->stream.common);
120830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->channel_mask = out_get_channels(&in->stream.common);
120930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        config->sample_rate = out_get_sample_rate(&in->stream.common);
1210eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
121230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
121330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
121430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
121530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
121630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
1218eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1219eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
122019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
122119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
122230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
122319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
122430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
122530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
122630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    //TODO(pmclean) why are we doing this when stream get's freed at the end
122730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // because it closes the pcm device
122830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
122930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
123030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
123130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
123230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
123319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
123419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
123519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
123619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
123719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
123819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
123919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
124019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
124119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1242eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
124319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1244eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1245eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    output_hardware_config_is_cached = false;
124630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    input_hardware_config_is_cached = false;
1247eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
124819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
124919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
125019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
125130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
125219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
125319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
125419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
125519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1256eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
125719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
125819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
125919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
126019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
126185e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
126219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.module = (struct hw_module_t *) module;
126319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
126419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
126519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
126619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
126719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
126819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
126919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
127019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
127119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
127219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
127319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
127419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
127519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
127619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
127719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
127819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
127919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
128019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
128119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
128219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
128319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
128419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
128519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
128619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
128719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
128819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
128919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
129019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
129119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
129246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
129346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
129419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
129519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
129619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
129719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
129819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
129919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1300