audio_hal.c revision 83b47a6891a5bf3d546f0f7a8976132e45169075
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"
54c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "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
187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
18819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
189c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys);
190f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
191c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
193f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
194f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
196c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
197f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
198c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
199c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
201c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
202c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
203c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
204c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
205e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
20619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
208c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
209c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
210c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
211c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
212c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
21419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
215c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
216c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
217c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
218c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
219c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
220c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
22119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
222c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
22319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
224c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
226eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
227c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters = %s", result_str);
228f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
229c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
23019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
23119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
234eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
235eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
236eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
237eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
23919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
242c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
24319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
245c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
246c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
247c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
24819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
25219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
25319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
25619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
258c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
259c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
260c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
26419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
26503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
26603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    return audio_channel_out_mask_from_count(out->hal_channel_count);
26719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
27019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
271c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
272c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
273c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
274c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
275c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
276c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
277c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
28819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
29019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
293c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
30919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
310eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
311eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
313c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
315eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
31619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
317eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
31805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
31905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
321c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
322f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
323f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
32419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
32605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    if (param_val >= 0)
32705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        card = atoi(value);
328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
33005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    if (param_val >= 0)
33105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        device = atoi(value);
33205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
3332c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(out->profile, card, device)) {
33405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
33505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!out->standby)
33605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
33705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
33805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = out->profile->card;
33905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = out->profile->device;
34005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->card = card;
34105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->device = device;
34205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
34305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
34405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->card = saved_card;
34505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->device = saved_device;
34605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
34705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
348eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
3492c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
351f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
35219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
35319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
354eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
35519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
35619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
357f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
35819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
359c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
360f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
361f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
362f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
363f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
364f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
365f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
366f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
367f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
368f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
369f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
370f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
371f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
372f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
373c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
374c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
37519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
37619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
37730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
37819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
37919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
38019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
38119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
382eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
383eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
384eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
38530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
386f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          out->profile->card, out->profile->device);
387eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
388c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
389eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
390eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
391eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
39419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
39719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
39819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
39919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
40019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
40105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&out->dev->lock);
40219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
40319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
40419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
40519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
40605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&out->dev->lock);
40705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
408c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
40988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
41103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
41203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
41330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
41403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
41503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
41603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
41703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
41803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
41903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
42003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
42103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
42203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
42303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
42403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
425eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
42603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
42703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
42803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
429eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
430eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
431eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
432eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
433c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
434eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
43719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
443c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
44419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
44519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
44619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
44819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
45119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
45319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
455c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
456c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
457c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
458c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* FIXME - This needs to be implemented */
459c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -EINVAL;
460c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
461c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
47319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
47519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
47846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
47946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
48046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
48146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
482f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
483f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   const char *address __unused)
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
48530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X",
486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
487eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
496c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
50519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
50619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
50719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
50819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
50919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
51019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
51119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
51219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
513c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
51419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
51519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
51619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
51719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
518c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
519c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
520c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
521c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
5222c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
523f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
524c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
525c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
526c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
527c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
528c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
529c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
530c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
531c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
532c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
533c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
53519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
536c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
537c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
538c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
540c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
541c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
543c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
548c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
549c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
55019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
55203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned proposed_channel_count = profile_get_default_channel_count(out->profile);
55303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
55403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
55503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
55603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
557eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
55803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* we can expose any channel count mask, and emulate internally. */
55903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
56003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    out->hal_channel_count = proposed_channel_count;
56103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
56203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
56303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    proxy_config.channels = proposed_channel_count;
564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
565c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
566c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
567c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
568c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
569c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
570eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
571eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
572eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
573eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
57446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
57519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
576c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
57819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
58019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
58119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
582eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
58419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
58719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
588eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
58919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
59019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
591c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
59219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
593eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
594eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
595c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
596eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
597eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
598eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
59919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
60219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
60346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
60419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
605c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
606c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
609c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
610c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
611c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
612eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
613eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
614c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
615c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
616c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
617eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
618eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
619eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
620eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
621c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
622eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
623eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
624eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
625eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
626eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
627c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
6282cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
629eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
630eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
631eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
632eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
6332cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    const struct stream_in *in = (const struct stream_in*)stream;
6342cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return audio_channel_in_mask_from_count(in->hal_channel_count);
635eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
636eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
637eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
638eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary input formats
640c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
641c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
642c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_format() = %d", format);
643c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return format;
644c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Input only supports PCM16 */
646c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats
647c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean       rewrite this to return the ACTUAL channel format (above) */
648c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return AUDIO_FORMAT_PCM_16_BIT;
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
651eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
653c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
654c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
660c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
66130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
66230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
66330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
66430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
66530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
666c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
66730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
66830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
66930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
67030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
67130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
67230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
680eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
681eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
68330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
684eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
686c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
688eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
689eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
690eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
69105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
69205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
693eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
694c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
695c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
696f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
697f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
6992c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    /* Device Connection Message ("card=1,device=0") */
700eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
70105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    if (param_val >= 0)
70205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        card = atoi(value);
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
70505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    if (param_val >= 0)
70605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        device = atoi(value);
70705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
7082c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
70905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
71005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!in->standby)
71105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
71205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
71305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = in->profile->card;
71405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = in->profile->device;
71505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->card = card;
71605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->device = device;
71705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
71805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
71905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->card = saved_card;
72005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->device = saved_device;
72105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
72205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
7232c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
724eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
725f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
726f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
727c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
728eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
729eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
730eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
731eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
732eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
733c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
734c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
73530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
736c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
737f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
738f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
73930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
740c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
74130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
742f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
743f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
7446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
745f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
746eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
747eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
748eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
749eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
750eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
751eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
752eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
753eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
754eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
756eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
75830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
75930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
76330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
764c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
765c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
76630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
767f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          in->profile->card, in->profile->device);
76830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
769c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
77030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
77130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
772e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
77330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
77430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
77588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
77630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
77883b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    int ret = 0;
77930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
780c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
78230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
78330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
78530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
78605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&in->dev->lock);
78730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
79030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
79105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&in->dev->lock);
79205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
79330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
794c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
795c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
796c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
797c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
798c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
799c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
80030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
801c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(&in->proxy);
8022cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    int num_req_channels = in->hal_channel_count;
80330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
80430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
805cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
80730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
808c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    enum pcm_format format = proxy_get_format(&in->proxy);
809c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (format == PCM_FORMAT_S24_3LE) {
8106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
81130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
812c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (format == PCM_FORMAT_S32_LE) {
8136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
8146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
817c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
81830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
81930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
820e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
821e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
82230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
82330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
82530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
82630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
82730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
82883b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    ret = proxy_read(&in->proxy, read_buff, num_read_buff_bytes);
82983b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    if (ret == 0) {
83030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
83130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
83230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
83330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
834c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (format != PCM_FORMAT_S16_LE) {
835c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            /* we need to convert */
83630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
83730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
83830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
83930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
840c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            if (format == PCM_FORMAT_S24_3LE) {
8416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
843c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else if (format == PCM_FORMAT_S32_LE) {
8446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
846c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else {
8476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
8486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
84930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
850eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
852c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
853c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
85430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
85530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
856eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
857eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
858eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
859eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
860fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
861eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
862eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
863eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
864cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
86530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
866253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
867253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
868253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
869253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent            memset(buffer, 0, num_read_buff_bytes);
87083b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    } else if (ret == -ENODEV) {
87183b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala            num_read_buff_bytes = 0; //reset the  value after USB headset is unplugged
87230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
87430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
87530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
87630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
87730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
879eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
88130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
88646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
88746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
88830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
8897d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
890f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
891f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  const char *address __unused,
892f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
89319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
89488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
89530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
896eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
8987661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
8997661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
901eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
903c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
905eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
907eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
92130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
923c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
924f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
925c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
9262c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
930c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
931c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
932c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9336b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
934c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
935c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9366b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9377661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
9406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
9416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
9426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
945c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9466b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
9476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
949c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
95030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
9516b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
9526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
953c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9546b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
9556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
956eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9572cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* Channels */
9582cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned proposed_channel_count = profile_get_default_channel_count(in->profile);
9592cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    if (k_force_channels) {
9602cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = k_force_channels;
9612cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
9622cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
963eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
964c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9652cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* we can expose any channel count mask, and emulate internally. */
9662cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
9672cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    in->hal_channel_count = proposed_channel_count;
9682cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
969c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
970eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
97230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
97430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
97530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
976eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
977eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9787661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
97919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
98019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
98130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
98219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
98330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
985c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
98730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
98830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
98930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
99030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
99119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
99219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
993c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
994c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
9982c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    ALOGV("audio_hw:usb adev_set_parameters(%s)", kvpairs);
9992c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10002c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct audio_device * adev = (struct audio_device *)dev;
10012c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10022c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    char value[32];
10032c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    int param_val;
10042c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10052c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
10062c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10072c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    /* Check for the "disconnect" message */
10082c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    param_val = str_parms_get_str(parms, "disconnect", value, sizeof(value));
10092c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (param_val >= 0) {
10102c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        audio_devices_t device = (audio_devices_t)atoi(value);
10112c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10122c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "card", value, sizeof(value));
10132c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_card = param_val >= 0 ? atoi(value) : -1;
10142c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10152c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "device", value, sizeof(value));
10162c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_device = param_val >= 0 ? atoi(value) : -1;
10172c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10182c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        if (alsa_card >= 0 && alsa_device >= 0) {
10192c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            /* "decache" the profile */
10202c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_lock(&adev->lock);
10212c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_OUT_USB_DEVICE &&
10222c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->out_profile, alsa_card, alsa_device)) {
10232c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->out_profile);
10242c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10252c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_IN_USB_DEVICE &&
10262c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->in_profile, alsa_card, alsa_device)) {
10272c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->in_profile);
10282c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10292c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_unlock(&adev->lock);
10302c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        }
10312c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
10322c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
1033781bb3f72e2706f07ee8bcc0c140201faf07c35csoon    str_parms_destroy(parms);
1034781bb3f72e2706f07ee8bcc0c140201faf07c35csoon
1035c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1036c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1037c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1038c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
1039c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1040c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
1041c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1042c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1043c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
1044c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1045c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1046c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1047c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1048c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1049c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1050c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1051c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1052c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1053c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1054c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1055c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1056c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1057c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1058c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1059c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1060c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1061c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1062c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1063c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1064c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1065253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    struct audio_device * adev = (struct audio_device *)dev;
1066253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_lock(&adev->lock);
1067253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    adev->mic_muted = state;
1068253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_unlock(&adev->lock);
1069c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1070c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1071c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1072c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1073c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1074c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1075c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1076c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
108119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1084eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1086eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
108819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
108919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
109030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
109319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
109419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1095eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
109619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1099c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1100c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1101c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
110385e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1104c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
110519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
110619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
110719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
110819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
110919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
111019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
111119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
111219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
111319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
111419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
111519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
111619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
111719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
111819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
111919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
112019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
112119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
112319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
112519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
112619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
112819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
112919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
113019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
113119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
113219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
113319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
113446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
113546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
113619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
113719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
113819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
113919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
114019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
114119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1142