audio_hal.c revision f5e2469c02825f018df6336125882812003b8e64
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
41c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_profile.h"
42c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_proxy.h"
43c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "logging.h"
44f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
45c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#define DEFAULT_INPUT_BUFFER_SIZE_MS 20
46f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
4719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
4819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
4919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
5019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
51eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
52eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
53c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile out_profile;
54eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
56c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile in_profile;
57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
5819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
5919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
6019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
6219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
6319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
67c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
68c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
69c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
70c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
72eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
73eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
74eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
75eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
84c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
85eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile;
87c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
886b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
89c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // not used?
90c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // struct audio_config hal_pcm_config;
9130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
92c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
9330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
9430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
9530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
9630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
9719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
9819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
10330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
10430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
10630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
10730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
10830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
10930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
11030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
11130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
11230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
113e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
11430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
115e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples,
116e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 short * out_buff)
117e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
11830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
11930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
12030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
12130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
12230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
12488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const unsigned char* src_ptr = in_buff;
12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
12930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
1376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples.
1386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   in_buff points to the buffer of PCM32 samples
1396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   num_in_samples size of input buffer in SAMPLES
1406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
1416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns
1426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   the number of BYTES of output data.
1436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
1446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit).
1456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE:
1466b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
1476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module.
1486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
1496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff)
1506b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{
1516b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /*
1526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * Move from front to back so that the conversion can be done in-place
1536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. in_buff == out_buff
1546b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     */
1556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    short * dst_ptr = out_buff;
1576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const int32_t* src_ptr = in_buff;
1586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    size_t src_smpl_index;
1596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
1606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        *dst_ptr++ = *src_ptr++ >> 16;
1616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return number of *bytes* generated: */
1646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return num_in_samples * 2;
1656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
1666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
167c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
16819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
169c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys);
170f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
171c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
172c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
173f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
174f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
175c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
176c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
177f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
178c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
179c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
180c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
181c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
182c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
183c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
184c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
185e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
18619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
188c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
189c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
190c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
191c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
193eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
19419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
196c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
197c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
198c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
199c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
20119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
202c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
20319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
204c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
205c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("usb:audio_hw::device_get_parameters = %s", result_str);
208f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
209c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
21019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
21119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
212eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
214eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
215eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
216eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
218eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
21919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
220c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
221c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
222c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
22319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
22419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
226c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
227c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
22819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
22919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
23019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
23119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
23219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
23319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
23419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
23519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
23619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
238c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
239c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_buffer_size()  = %zu", buffer_size);
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
24219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
24519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
246c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
247c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_profile * profile = ((struct stream_out*)stream)->profile;
248c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * unsigned channel_count = profile_get_channel_count(profile);
249c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * uint32_t channel_mask = audio_channel_out_mask_from_count(channel_count);
250c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("out_get_channels() = 0x%X count:%d", channel_mask, channel_count);
251c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return channel_mask;
252c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
253c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
254c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Always Stereo for now. We will do *some* conversions in this HAL.
255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels
256c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * rewrite this to return the ACTUAL channel format */
25719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_CHANNEL_OUT_STEREO;
25819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
262c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
263c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
264c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
265c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
266c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
267c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
268c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_format() = %d", format);
269c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
27019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
27319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
27419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
27519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
285c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
28819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
29019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
302eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
303eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
305c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
311c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
312f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
313f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
315eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool recache_device_params = false;
316eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
317eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
318f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        out->profile->card = atoi(value);
319eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
320eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
321eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
324f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        out->profile->device = atoi(value);
325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
328f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    if (recache_device_params && out->profile->card >= 0 && out->profile->device >= 0) {
329c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
332f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
333f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
339f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
341c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
342f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
343f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
344f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
345f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
346f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
347f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
348f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
349f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
351f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
352f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
353f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
354f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
355c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
356c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
35719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
35819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
35930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
36119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
36219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
364eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
365eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
366eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
36730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
368f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          out->profile->card, out->profile->device);
369eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
370c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
37419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
37519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
37619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
37719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
37819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
37919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
380c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    pthread_mutex_unlock(&out->dev->lock);
381c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
38619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
38819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
390c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile* profile = out->profile;
391c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
392c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
393c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
394c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     *  Setup conversion buffer
395c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * compute maximum potential buffer size.
396c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * * 2 for stereo -> quad conversion
397c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * * 3/2 for 16bit -> 24 bit conversion
398c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
39988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t required_conversion_buffer_size = (bytes * 3 * 2) / 2;
40030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (required_conversion_buffer_size > out->conversion_buffer_size) {
401e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        /* TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
402e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean           (and do these conversions themselves) */
40330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer_size = required_conversion_buffer_size;
40430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size);
40530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
40630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
40788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
408eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
411eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Num Channels conversion
412eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
413c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(proxy);
414c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_req_channels = 2; /* always for now */
415c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
41630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
417eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean        audio_format_t audio_format = out_get_format(&(out->stream.common));
418eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean        unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
420eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean             adjust_channels(write_buff, num_req_channels,
421eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                             out->conversion_buffer, num_device_channels,
422eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                             sample_size_in_bytes, num_write_buff_bytes);
423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
424eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
425eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
426eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
427c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
428eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
437c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
44430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
44519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
44619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
44719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
449c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
450c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
451c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
452c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* FIXME - This needs to be implemented */
453c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -EINVAL;
454c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
455c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
47246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
47346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
47446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
47546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
476f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
477f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   const char *address __unused)
47819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X",
480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
490c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
50519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
50619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
507c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
50819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
50919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
51019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
51119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
512c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
513c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
514c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
515c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
516f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
518c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
519c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
520c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
521c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
522c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
523c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
524c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
525c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
526c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
527c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
52819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
529c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
530c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
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    } else {
534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
535c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
536c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
537c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
538c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
540c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
541c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
54319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        /* This will be needed when the framework supports non-stereo output */
547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        /* config->channel_mask =
548c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         *        audio_channel_out_mask_from_count(profile_get_default_channel_count(out->profile));
549c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         */
550c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.channels = profile_get_default_channel_count(out->profile);
551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
553c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        /* This will be needed when the framework supports non-stereo output */
554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        /*
555c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         * unsigned channel_count = audio_channel_count_from_out_mask(config->channel_mask);
556c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         * if (profile_is_channel_count_valid(out->profile, channel_count)) {
557c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         *     proxy_set_channel_count(out->proxy, channel_count);
558c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         * } else {
559c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         *     config->channel_mask =
560c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         *             audio_channel_out_mask_from_count(proxy_get_channel_count(out->proxy));
561c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         *     ret = -EINVAL;
562c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         * }
563c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean         */
564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) {
565c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.channels = profile_get_default_channel_count(out->profile);
566eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
567c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
568c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }  else {
569c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.channels = profile_get_default_channel_count(out->profile);
570eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
571eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
572eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
573c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
574c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
575c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
576c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
578eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
579eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
580eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
581eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
58246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
584c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
585c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
58719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
58819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
58919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
59119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
59219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
59319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
59419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
59519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
596eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
59719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
59819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
599c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
601eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
602eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
603c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
61146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
613c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
614c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
617c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
618c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
619c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
620eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
621eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
622c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
623c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
624c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
625eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
626eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
627eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
628eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
629c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
630eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
631eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
632eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
633eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
634eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
635c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
636c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
637c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_buffer_size() = %zd", buffer_size);
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
640c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent    return buffer_size;
641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
644eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary channel counts
646c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
647c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * unsigned channel_count = proxy_get_channel_count(proxy);
648c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * uint32_t channel_mask = audio_channel_in_mask_from_count(channel_count);
649c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_channels() = 0x%X count:%d", channel_mask, channel_count);
650c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return channel_mask;
651c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
652c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels
653c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     rewrite this to return the ACTUAL channel format */
65430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return AUDIO_CHANNEL_IN_STEREO;
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
659c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary input formats
660c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
661c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
662c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_format() = %d", format);
663c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return format;
664c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
665c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Input only supports PCM16 */
666c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats
667c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean       rewrite this to return the ACTUAL channel format (above) */
668c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return AUDIO_FORMAT_PCM_16_BIT;
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
673c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
674c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
680c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
68130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
68230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
68330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
68430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
68530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
686c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
68730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
68830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
68930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
69130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
69230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
693eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
694eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
695eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
699eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
700eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
701eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
70330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
706c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
711eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
712c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
713c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
714f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
715f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
716eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
71730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    bool recache_device_params = false;
71830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
719c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Card/Device */
720eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
721eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
722f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        in->profile->card = atoi(value);
72330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
724eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
725eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
726eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
727eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
728f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean        in->profile->device = atoi(value);
72930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
730eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
731eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
732f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    if (recache_device_params && in->profile->card >= 0 && in->profile->device >= 0) {
733c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
734c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     }
735eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
736f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
737f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
738c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
739eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
740eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
741eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
742eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
743eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
744c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
745c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
74630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
747c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
748f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
749f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
75030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
751c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
75230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
753f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
754f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
7556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
756f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
764eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
76930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
77030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
77430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
775c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
776c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
778f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean          in->profile->card, in->profile->device);
77930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
780c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
78230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
783e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
78530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
78688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
78730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
790c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
79130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
79230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
79330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
794c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    pthread_mutex_unlock(&in->dev->lock);
79530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
79630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
79730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
80030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
80130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
80230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
803c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
804c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
805c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
806c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
807c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
808c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
810c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(&in->proxy);
81130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_req_channels = 2; /* always, for now */
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
814cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
817c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    enum pcm_format format = proxy_get_format(&in->proxy);
818c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (format == PCM_FORMAT_S24_3LE) {
8196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
821c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (format == PCM_FORMAT_S32_LE) {
8226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
8236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
82530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
826c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
82730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
82830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
829e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
830e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
83130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
83230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
83330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
83430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
83530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
83630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
837c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (proxy_read(&in->proxy, read_buff, num_read_buff_bytes) == 0) {
83830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
83930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
84030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
842c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (format != PCM_FORMAT_S16_LE) {
843c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            /* we need to convert */
84430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
84530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
84630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
84730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
848c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            if (format == PCM_FORMAT_S24_3LE) {
8496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8506b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
851c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else if (format == PCM_FORMAT_S32_LE) {
8526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
854c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else {
8556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
8566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
860c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
861c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
86230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
86330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
864eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
865eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
866eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
867eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
868fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
869eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
870eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
871eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
872cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
87330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
87430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
87630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
87730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
87830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
87930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
88330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
88846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
88946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
89030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
8917d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
892f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
893f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  const char *address __unused,
894f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
89519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
89688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
89730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
9007661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
9017661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
903eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
905c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
907eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
92330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
925c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
926f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
927c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
931c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
932c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
933c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
935c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
936c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9387661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
9416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
9426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
9436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
946c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
9486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
950c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
95130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
9526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
9536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
954c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
9566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
9596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_CHANNEL_IN_STEREO until the framework supports other input
9606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
962c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) {
9646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* allow only stereo capture for now */
9656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
9666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
967eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
968c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // proxy_config.channels = 0;  /* don't change */
969c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
970c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
971c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
972eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
97430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
97630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
97730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
978eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
979eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9807661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
98119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
98219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
98330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
98419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
98530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
987c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
98830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
98930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
99030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
99130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
99230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
99319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
99419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
998c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
999c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1000c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1001c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1003c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
1004c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1005c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1007c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1008c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
1009c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1010c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1011c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1012c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1013c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1014c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1015c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1016c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1017c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1019c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1020c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1021c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1022c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1023c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1024c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1025c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1026c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1027c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1028c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1029c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1030c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1031c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1032c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1033c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1034c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1035c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1036c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1037c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1045eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
104619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1047eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
104919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
105019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
105130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
105219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
105419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1056eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
105819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
105919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1060c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1061c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1062c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
106319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
106485e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1065c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
108119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
108419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
108619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
108919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
109019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
109319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
109419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
109546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
109646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
109919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
110119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1103