audio_hal.c revision 03576bed8129d6d2faad5cb9c6aaae7cebb35d70
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
6919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
7019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
75eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
79c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
80c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
81c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
82eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
8403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * This may differ from the device channel count when
8503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * the device is not compatible with AudioFlinger
8603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * capabilities, e.g. exposes too many channels or
8703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * too few channels. */
88eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
89eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
9819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
9919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
100c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
102c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
103c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
1046b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
105c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // not used?
106c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // struct audio_config hal_pcm_config;
10730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
108c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
10930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
11030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
11130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
11230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
115eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
116eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
117eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
11930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
12030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
121eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
12230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
129e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
131e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples,
132e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 short * out_buff)
133e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
13630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
13730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
13830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
14088e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const unsigned char* src_ptr = in_buff;
14130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
14230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
14330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
14430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
14530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
14630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
14730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
14830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
14930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
15030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
15130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
15230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
1536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples.
1546b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   in_buff points to the buffer of PCM32 samples
1556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   num_in_samples size of input buffer in SAMPLES
1566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
1576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns
1586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   the number of BYTES of output data.
1596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
1606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit).
1616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE:
1626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
1636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module.
1646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
1656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff)
1666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{
1676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /*
1686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * Move from front to back so that the conversion can be done in-place
1696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. in_buff == out_buff
1706b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     */
1716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1726b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    short * dst_ptr = out_buff;
1736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const int32_t* src_ptr = in_buff;
1746b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    size_t src_smpl_index;
1756b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
1766b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        *dst_ptr++ = *src_ptr++ >> 16;
1776b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1786b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1796b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return number of *bytes* generated: */
1806b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return num_in_samples * 2;
1816b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
1826b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
183c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
18419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
185c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys);
186f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
188c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
189f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
190f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
191c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
193f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
194c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
196c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
197c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
198c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
199c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
201e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
20219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
203c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
204c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
205c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
206c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
208c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
209eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
21019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
211c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
212c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
213c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
214c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
215c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
216c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
21719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
218c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
21919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
220c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
221c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
223c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters = %s", result_str);
224f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
22619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
22719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
228eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
229eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
230eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
234eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
23519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
236c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
238c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
23919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
24019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
242c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
243c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
24719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
24819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
24919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
25219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
253c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
254c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
256c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_buffer_size()  = %zu", buffer_size);
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
25819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
26203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
26303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    return audio_channel_out_mask_from_count(out->hal_channel_count);
26419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
26719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
268c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
269c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
270c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
271c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
272c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
273c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
274c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_format() = %d", format);
275c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
28819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
291c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
30719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
308eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
311c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
313eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
315eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
31619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
317c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
318f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
319f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
321eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool recache_device_params = false;
322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
324f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        out->profile->card = atoi(value);
325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
327eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
330f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        out->profile->device = atoi(value);
331eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
332eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
33319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
334f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    if (recache_device_params && out->profile->card >= 0 && out->profile->device >= 0) {
335c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
338f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
339f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
34119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
342eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
34319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
345f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
34619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
347c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
348f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
349f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
351f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
352f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
353f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
354f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
355f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
356f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
357f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
358f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
359f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
360f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
361c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
362c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
36319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
36619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
36719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
36819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
370eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
37330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
374f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          out->profile->card, out->profile->device);
375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
376c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
378eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
38019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
38119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
386c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    pthread_mutex_unlock(&out->dev->lock);
387c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
38819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
39019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
39119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
39419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
396c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
39788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
398eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
39903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
40003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
40130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
40203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
40303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
40403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
40503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
40603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
40703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
40803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
40903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
41003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
41103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
41203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
413eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
41403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
41503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
41603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
417eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
418eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
420eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
421c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
422eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
42319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
42719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
431c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
43719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
443c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
444c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
445c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
446c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* FIXME - This needs to be implemented */
447c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -EINVAL;
448c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
449c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
45019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
45119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
45519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
46646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
46746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
46846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
46946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_out **stream_out)
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X",
473eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
474eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
47519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
476eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
47719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
47819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
48019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
48119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
48219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
483c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
500c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
505c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
506c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
507c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
508c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
509f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
510c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
511c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
512c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
513c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
514c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
515c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
516c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
518c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
519c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
520c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
52119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
522c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
523c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
524c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
525c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
526c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
527c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
528c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
529c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
530c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
531c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
532c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
533c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
535c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
53619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
537c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
53803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned proposed_channel_count = profile_get_default_channel_count(out->profile);
53903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
54003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
54103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
54203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
543eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
54403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* we can expose any channel count mask, and emulate internally. */
54503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
54603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    out->hal_channel_count = proposed_channel_count;
54703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
54803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
54903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    proxy_config.channels = proposed_channel_count;
550eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
553c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
555c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
556eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
557eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
558eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
559eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
56046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
56119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
562c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
563c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
56419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
56519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
56619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
56719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
568eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
56919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
57019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
57119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
57219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
57319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
57519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
57619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
57819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
579eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
580eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
581c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
582eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
583eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
584eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
58519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
58719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
58946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
59019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
591c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
592c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
59319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
59419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
595c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
596c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
597c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
598eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
599eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
600c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
601c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
602c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
603eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
607c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
608eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
609eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
610eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
611eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
612eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
613c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
614c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
615c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
616c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_buffer_size() = %zd", buffer_size);
617c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
618c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent    return buffer_size;
619eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
620eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
621eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
622eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
623c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary channel counts
624c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
625c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * unsigned channel_count = proxy_get_channel_count(proxy);
626c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * uint32_t channel_mask = audio_channel_in_mask_from_count(channel_count);
627c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_channels() = 0x%X count:%d", channel_mask, channel_count);
628c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return channel_mask;
629c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
630c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels
631c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     rewrite this to return the ACTUAL channel format */
63230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return AUDIO_CHANNEL_IN_STEREO;
633eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
634eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
635eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
636eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
637c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary input formats
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
640c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_format() = %d", format);
641c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return format;
642c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
643c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Input only supports PCM16 */
644c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats
645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean       rewrite this to return the ACTUAL channel format (above) */
646c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return AUDIO_FORMAT_PCM_16_BIT;
647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
648eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
651c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
652c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
658c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
65930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
66030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
66130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
66230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
66330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
664c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
66530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
66630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
66730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
66830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
66930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
67030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
680eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
68130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
683eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
684c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
686eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
688eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
689eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
690c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
691c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
692f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
693f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
694eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
69530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    bool recache_device_params = false;
69630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
697c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Card/Device */
698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
699eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
700f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        in->profile->card = atoi(value);
70130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
706f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        in->profile->device = atoi(value);
70730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
710f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    if (recache_device_params && in->profile->card >= 0 && in->profile->device >= 0) {
711c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
712c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     }
713eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
714f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
715f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
716c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
717eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
718eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
719eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
720eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
721eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
722c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
723c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
72430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
725c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
726f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
727f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
72830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
729c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
73030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
731f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
732f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
7336b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
734f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
735eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
736eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
737eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
738eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
739eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
740eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
741eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
742eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
743eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
744eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
745eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
746eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
74730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
74830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
749eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
750eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
751eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
75230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
753c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
754c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
75530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
756f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          in->profile->card, in->profile->device);
75730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
758c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
75930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
76030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
761e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
76230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
76330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
76488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
76530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
76630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
76730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
768c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
76930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
77030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
77130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
772c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    pthread_mutex_unlock(&in->dev->lock);
77330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
77430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
77530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
77630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
77830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
77930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
78030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
781c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
782c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
783c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
784c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
785c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
786c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
78730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
788c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(&in->proxy);
78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_req_channels = 2; /* always, for now */
79030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
79130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
792cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
79330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
79430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
795c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    enum pcm_format format = proxy_get_format(&in->proxy);
796c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (format == PCM_FORMAT_S24_3LE) {
7976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
799c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (format == PCM_FORMAT_S32_LE) {
8006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
8016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
80230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
80330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
804c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
80530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
807e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
808e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
81030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
81130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
815c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (proxy_read(&in->proxy, read_buff, num_read_buff_bytes) == 0) {
81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
81830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
81930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
820c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (format != PCM_FORMAT_S16_LE) {
821c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            /* we need to convert */
82230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
82330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
82530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
826c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            if (format == PCM_FORMAT_S24_3LE) {
8276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
829c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else if (format == PCM_FORMAT_S32_LE) {
8306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
832c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else {
8336b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
8346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
83530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
836eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
83730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
838c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
839c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
84030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
842eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
843eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
844eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
845eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
846fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
847eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
848eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
849eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
850cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
85130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
85230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
853eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
85530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
85630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
86130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
864eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
86646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
86746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
86830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
8697d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
8707d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  audio_input_flags_t flags __unused)
87119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
87288e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
87330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
874eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
8767661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
8777661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
879eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
881c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
890eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
891eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
894eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
896eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
89930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
901c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
902f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
903c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
907c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
908c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
909c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
911c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
912c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9147661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
9176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
9186b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
9196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9206b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9216b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
922c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
9246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
926c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
92730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
9286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
9296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
930c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
9326b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
933eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
9356b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_CHANNEL_IN_STEREO until the framework supports other input
9366b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
938c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) {
9406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* allow only stereo capture for now */
9416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
9426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
943eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
944c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // proxy_config.channels = 0;  /* don't change */
945c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
946c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
947c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
948eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
95030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
95130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
95230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
95330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9567661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
95719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
95819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
95930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
96019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
96130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
96230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
963c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
96430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
96530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
96630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
96730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
96830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
96919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
97019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
971c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
972c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
973c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
974c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
975c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
976c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
977c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
978c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
979c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
980c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
981c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
982c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
983c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
984c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
985c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
986c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
987c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
988c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
989c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
990c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
991c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
992c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
993c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
994c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
998c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
999c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1000c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1001c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1003c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1004c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1005c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1007c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1008c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1009c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1010c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1011c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1012c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1013c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
101419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
101519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
101619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
101719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
101819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
101919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
102019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1021eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
102219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1023eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
102619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
102819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
102919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
103019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
103119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1032eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
103319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
103419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
103519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1036c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1037c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1038c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
104085e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1041c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
104319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
104519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
104619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
104719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
104919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
105019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
105119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
105219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
105419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
105619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
105819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
105919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
106019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
106219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
106319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
106519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
107146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
107246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1079