audio_hal.c revision 0f1753ead073b9abffb23dc712bb636280d7f5a6
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"
18cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean/*#define LOG_NDEBUG 0*/
1919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <errno.h>
2188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <inttypes.h>
2219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <pthread.h>
2319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdint.h>
2419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdlib.h>
2588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <sys/time.h>
2619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <log/log.h>
2819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/str_parms.h>
2919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/properties.h>
3019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio.h>
32e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio_alsaops.h>
3319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/hardware.h>
34e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
3519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <system/audio.h>
3619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <tinyalsa/asoundlib.h>
3819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39c2201159bbdfd58ed54e505061825df3ab9f1ef0Paul McLean#include <audio_utils/channels.h>
40c2201159bbdfd58ed54e505061825df3ab9f1ef0Paul McLean
4103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung/* FOR TESTING:
4203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * Set k_force_channels to force the number of channels to present to AudioFlinger.
4303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *   0 disables (this is default: present the device channels to AudioFlinger).
4403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *   2 forces to legacy stereo mode.
4503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *
4603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * Others values can be tried (up to 8).
4703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * TODO: AudioFlinger cannot support more than 8 active output channels
4803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * at this time, so limiting logic needs to be put here or communicated from above.
4903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung */
5003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hungstatic const unsigned k_force_channels = 0;
5103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung
52c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_profile.h"
53c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_proxy.h"
54271444af385a288bf4164bd2b3e186525e4c0d40Paul McLean#include "audio_logging.h"
55f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
56c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#define DEFAULT_INPUT_BUFFER_SIZE_MS 20
57f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
5919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
6019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
64c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile out_profile;
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
67c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile in_profile;
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
69253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    bool mic_muted;
70253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
7519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
7619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
80c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
81c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
82c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
83c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
8603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * This may differ from the device channel count when
8703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * the device is not compatible with AudioFlinger
8803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * capabilities, e.g. exposes too many channels or
8903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * too few channels. */
90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
10019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
10119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
105c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
1066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1072cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
1082cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * This may differ from the device channel count when
1092cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * the device is not compatible with AudioFlinger
1102cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * capabilities, e.g. exposes too many channels or
1112cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * too few channels. */
112c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
11330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
11430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
11530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
11630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
11819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
121eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
122eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
125eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
12930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
133e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
135e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples,
136e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 short * out_buff)
137e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
13830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
14030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
14130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
14230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
14330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
14488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const unsigned char* src_ptr = in_buff;
14530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
14630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
14730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
14830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
14930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
15030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
15130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
15230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
15330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
15430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
15530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
15630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
1576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples.
1586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   in_buff points to the buffer of PCM32 samples
1596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   num_in_samples size of input buffer in SAMPLES
1606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
1616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns
1626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   the number of BYTES of output data.
1636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
1646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit).
1656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE:
1666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
1676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module.
1686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
1696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff)
1706b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{
1716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /*
1726b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * Move from front to back so that the conversion can be done in-place
1736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. in_buff == out_buff
1746b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     */
1756b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1766b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    short * dst_ptr = out_buff;
1776b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const int32_t* src_ptr = in_buff;
1786b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    size_t src_smpl_index;
1796b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
1806b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        *dst_ptr++ = *src_ptr++ >> 16;
1816b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1826b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1836b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return number of *bytes* generated: */
1846b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return num_in_samples * 2;
1856b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
1866b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1870f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean/*
1880f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * Extract the card and device numbers from the supplied key/value pairs.
1890f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   kvpairs    A null-terminated string containing the key/value pairs or card and device.
1900f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *              i.e. "card=1;device=42"
1910f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   card   A pointer to a variable to receive the parsed-out card number.
1920f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   device A pointer to a variable to receive the parsed-out device number.
1930f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * NOTE: The variables pointed to by card and device return -1 (undefined) if the
1940f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *  associated key/value pair is not found in the provided string.
1950f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean */
1960f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLeanstatic void parse_card_device_params(const char *kvpairs, int *card, int *device)
19719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1980f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
1990f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    char value[32];
2000f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    int param_val;
201f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
2020f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    // initialize to "undefined" state.
2030f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *card = -1;
2040f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *device = -1;
2050f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2060f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
2070f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
2080f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *card = atoi(value);
2090f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
2100f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2110f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
2120f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
2130f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *device = atoi(value);
2140f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
2150f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2160f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    str_parms_destroy(parms);
2170f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean}
2180f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2190f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
2200f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean{
221c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
222c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
223f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
224f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
226c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
227f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
228c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
229c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
230c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
231c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
232c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
233c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
234c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
235e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
23619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
238c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
239c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
242c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
245c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
246c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
247c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
248c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
249c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
250c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
252c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
25319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
254c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
256eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters = %s", result_str);
258f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
259c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
262eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
263eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
264eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
265eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
266eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
267eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
268eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
26919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
270c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
271c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
272c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
27319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
27419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
275c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
276c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
277c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
287c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
288c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
289c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
290c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
29503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
29603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    return audio_channel_out_mask_from_count(out->hal_channel_count);
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
301c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
302c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
303c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
304c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
305c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
306c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
307c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
31119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
31319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
31619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
31719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
31819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
32119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
323c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
32419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
32519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
32619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
32819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
32919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
33919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
340eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
341eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
34219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
343c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
345eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
34605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
34705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
34819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
349f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3520f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(kvpairs, &card, &device);
35305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
3542c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(out->profile, card, device)) {
35505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
35605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!out->standby)
35705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
35805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
35905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = out->profile->card;
36005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = out->profile->device;
36105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->card = card;
36205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->device = device;
36305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
36405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
36505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->card = saved_card;
36605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->device = saved_device;
36705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
36805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
369eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
3702c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
371f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
372f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
37319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
374eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
37519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
37619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
377f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
37819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
379c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
380f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
381f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
382f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
383f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
384f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
385f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
386f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
387f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
388f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
389f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
390f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
391f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
392f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
393c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
394c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
39619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
39819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
39919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
40019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
40119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
402eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
403eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
404eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
40530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
406f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          out->profile->card, out->profile->device);
407eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
408c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
411eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
41219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
41319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
41419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
41519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
41619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
41719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
41819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
41919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
42019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
42105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&out->dev->lock);
42219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
42319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
42605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&out->dev->lock);
42705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
428c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
42988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
430eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
43103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
43203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
43330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
43403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
43503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
43603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
43703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
43803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
43903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
44003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
44103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
44203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
44303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
44403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
445eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
44603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
44703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
44803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
449eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
450eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
451eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
452eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
453c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
454eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
45519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
463c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
47319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
475c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
476c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
477c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
478c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* FIXME - This needs to be implemented */
479c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -EINVAL;
480c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
481c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
48219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
48319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
49846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
49946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
50046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
50146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
502f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
5030f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                   const char *address /*__unused*/)
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
5050f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream()"
5060f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          "handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
5070f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          handle, devices, flags, address);
508eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
50919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
510eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
51119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
51219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
51319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
51419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
51519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
51619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
51819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
51919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
52019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
52119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
52219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
52319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
52419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
52519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
52619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
52719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
52819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
52919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
53019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
53119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
53219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
53319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
53519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
53619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
53719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
5380f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&adev->lock);
539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
540c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
541c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
5432c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
544f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5450f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
5460f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(out->profile->card), &(out->profile->device));
5470f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5480f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(out->profile);
5490f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5500f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&adev->lock);
5510f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
553c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
555c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
556c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
557c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
558c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
559c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
560c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
561c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
562c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
56319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
564c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
565c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
566c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
567c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
568c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
569c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
570c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
571c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
572c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
573c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
574c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
575c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
576c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
57819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
579c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
58003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned proposed_channel_count = profile_get_default_channel_count(out->profile);
58103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
58203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
58303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
58403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
585eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
58603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* we can expose any channel count mask, and emulate internally. */
58703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
58803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    out->hal_channel_count = proposed_channel_count;
58903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
59003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
59103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    proxy_config.channels = proposed_channel_count;
592eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
593c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
594c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
595c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
596c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
597c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
598eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
599eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
600eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
601eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
60246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
60319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
604c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
605c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
60619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
60919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
610eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
61119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
61419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
6170f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream(c:%d d:%d)",
6180f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          out->profile->card, out->profile->device);
61919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
620c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
62119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
622eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
623eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
624c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
625eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
626eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
627eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
62819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
62919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
63019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
63119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
63246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
63319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
634c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
635c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
63619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
63719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
640c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
643c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
644c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
648eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
650c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
651eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
656c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
6572cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
6622cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    const struct stream_in *in = (const struct stream_in*)stream;
6632cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return audio_channel_in_mask_from_count(in->hal_channel_count);
664eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
665eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
668c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary input formats
669c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
670c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
671c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_format() = %d", format);
672c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return format;
673c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
674c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Input only supports PCM16 */
675c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats
676c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean       rewrite this to return the ACTUAL channel format (above) */
677c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return AUDIO_FORMAT_PCM_16_BIT;
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
680eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
681eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
682c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
683c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
684eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
686eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
688eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
689c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
69030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
69230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
69330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
695c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
69630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
69730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
69830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
70030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
70130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
711eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
71230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
713eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
714eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
715c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
716eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
717eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
718eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
719eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
72005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
72105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
722eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
723f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
724f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
725eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
7260f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(kvpairs, &card, &device);
72705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
7282c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
72905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
73005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!in->standby)
73105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
73205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
73305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = in->profile->card;
73405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = in->profile->device;
73505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->card = card;
73605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->device = device;
73705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
73805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
73905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->card = saved_card;
74005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->device = saved_device;
74105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
74205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
7432c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
744eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
745f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
746f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
747c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
748eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
749eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
750eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
751c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
752c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
75330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
754c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
755f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
756f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
75730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
758c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
75930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
760f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
761f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
7626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
763f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
764eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
769eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
770eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
774eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
775eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
77630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
778eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
780eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
782c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
783c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
785f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          in->profile->card, in->profile->device);
78630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
787c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
790e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
79130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
79230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
79388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
79430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
79530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
79630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
797c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
80030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
80130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
80230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
80305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&in->dev->lock);
80430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
80530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
80730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
80805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&in->dev->lock);
80905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
81030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
811c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
812c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
813c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
814c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
815c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
816c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
818c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(&in->proxy);
8192cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    int num_req_channels = in->hal_channel_count;
82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
82130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
822cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
82330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
825c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    enum pcm_format format = proxy_get_format(&in->proxy);
826c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (format == PCM_FORMAT_S24_3LE) {
8276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
82830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
829c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (format == PCM_FORMAT_S32_LE) {
8306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
8316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
83230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
83330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
834c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
83530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
83630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
837e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
838e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
83930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
84030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
84230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
84330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
84430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
845c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (proxy_read(&in->proxy, read_buff, num_read_buff_bytes) == 0) {
84630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
84730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
84830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
84930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
850c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (format != PCM_FORMAT_S16_LE) {
851c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            /* we need to convert */
85230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
85330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
85430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
85530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
856c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            if (format == PCM_FORMAT_S24_3LE) {
8576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
859c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else if (format == PCM_FORMAT_S32_LE) {
8606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
862c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else {
8636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
8646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
86530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
866eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
868c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
869c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
87030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
87130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
872eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
873eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
874eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
875eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
876fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
877eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
878eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
879eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
880cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
88130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
882253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
883253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
884253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
885253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent            memset(buffer, 0, num_read_buff_bytes);
88630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
88930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
89030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
89130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
89430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
89530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
896eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
89946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
90046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
90146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
90230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
9037d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
904f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
9050f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                  const char *address /*__unused*/,
906f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
90719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
90888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
90930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
9127661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
9137661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
917c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
923eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
925eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
926eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
929eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
930eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
932eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
933eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
934eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
93530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
9360f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&in->dev->lock);
937eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
938c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
939f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
940c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
9412c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
942eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9430f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
9440f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(in->profile->card), &(in->profile->device));
9450f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9460f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(in->profile);
9470f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&in->dev->lock);
9480f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9506b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
951c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
952c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
953c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9546b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
955c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
956c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9587661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
9616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
9626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
9636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
966c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
9686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
970c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
9726b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
9736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
974c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9756b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
9766b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
977eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9782cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* Channels */
9792cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned proposed_channel_count = profile_get_default_channel_count(in->profile);
9802cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    if (k_force_channels) {
9812cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = k_force_channels;
9822cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
9832cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
984eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
985c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9862cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* we can expose any channel count mask, and emulate internally. */
9872cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
9882cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    in->hal_channel_count = proposed_channel_count;
9892cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
990c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
991eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
99230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
99330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
99430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
99530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
99630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
997eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
998eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9997661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
100019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
100119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
100230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
100319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
100430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
100530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
100730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
100830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
100930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
101030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
101130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
101219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
101319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1014c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
1015c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
1016c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
1017c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
10192c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    ALOGV("audio_hw:usb adev_set_parameters(%s)", kvpairs);
10202c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10212c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct audio_device * adev = (struct audio_device *)dev;
10222c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10232c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    char value[32];
10242c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    int param_val;
10252c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10262c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
10272c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10282c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    /* Check for the "disconnect" message */
10292c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    param_val = str_parms_get_str(parms, "disconnect", value, sizeof(value));
10302c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (param_val >= 0) {
10312c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        audio_devices_t device = (audio_devices_t)atoi(value);
10322c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10332c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "card", value, sizeof(value));
10342c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_card = param_val >= 0 ? atoi(value) : -1;
10352c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10362c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "device", value, sizeof(value));
10372c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_device = param_val >= 0 ? atoi(value) : -1;
10382c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10392c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        if (alsa_card >= 0 && alsa_device >= 0) {
10402c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            /* "decache" the profile */
10412c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_lock(&adev->lock);
10422c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_OUT_USB_DEVICE &&
10432c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->out_profile, alsa_card, alsa_device)) {
10442c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->out_profile);
10452c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10462c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_IN_USB_DEVICE &&
10472c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->in_profile, alsa_card, alsa_device)) {
10482c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->in_profile);
10492c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10502c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_unlock(&adev->lock);
10512c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        }
10522c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
10532c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
1054c357157e28dc0ffd069b80aeba9bf8b9eed72c9asoon    str_parms_destroy(parms);
1055c357157e28dc0ffd069b80aeba9bf8b9eed72c9asoon
1056c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1057c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1058c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1059c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
1060c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1061c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
1062c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1063c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1064c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
1065c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1066c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1067c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1068c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1069c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1070c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1071c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1072c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1073c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1074c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1075c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1076c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1077c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1078c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1079c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1080c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1081c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1082c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1083c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1084c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1085c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1086253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    struct audio_device * adev = (struct audio_device *)dev;
1087253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_lock(&adev->lock);
1088253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    adev->mic_muted = state;
1089253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_unlock(&adev->lock);
1090c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1091c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1092c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1093c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1094c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1095c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1096c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1097c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
109919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
110119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
110319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
110419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
110619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
110819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
110919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
111019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
111130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
111219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
111319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
111419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
111519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1116eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
111719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
111819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
111919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1120c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1121c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1122c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
112319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
112485e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1125c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
112619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
112719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
112919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
113019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
113119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
113219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
113319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
113419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
113519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
113619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
113719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
113819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
113919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
114019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
114119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
114219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
114319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
114419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
114519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
114619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
114719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
114819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
114919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
115019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
115119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
115219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
115319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
115419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
115546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
115646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
115719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
115819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
115919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
116019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
116119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
116219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1163