audio_hal.c revision 65ec72b72b01fa2269e91de7c6eb3e6285f9fa86
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
179ab869acfd02cf841a6c8309ae45acf936557720Paul McLean#define LOG_TAG "modules.usbaudio.audio_hal"
18cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean/*#define LOG_NDEBUG 0*/
1919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <errno.h>
2188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <inttypes.h>
2219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <pthread.h>
2319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdint.h>
2419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdlib.h>
2588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <sys/time.h>
2619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <log/log.h>
2819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/str_parms.h>
2919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/properties.h>
3019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio.h>
32e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio_alsaops.h>
3319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/hardware.h>
34e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
3519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <system/audio.h>
3619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <tinyalsa/asoundlib.h>
3819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39c2201159bbdfd58ed54e505061825df3ab9f1ef0Paul McLean#include <audio_utils/channels.h>
40c2201159bbdfd58ed54e505061825df3ab9f1ef0Paul McLean
4103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung/* FOR TESTING:
4203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * Set k_force_channels to force the number of channels to present to AudioFlinger.
4303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *   0 disables (this is default: present the device channels to AudioFlinger).
4403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *   2 forces to legacy stereo mode.
4503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung *
4603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * Others values can be tried (up to 8).
4703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * TODO: AudioFlinger cannot support more than 8 active output channels
4803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung * at this time, so limiting logic needs to be put here or communicated from above.
4903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung */
5003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hungstatic const unsigned k_force_channels = 0;
5103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung
52c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_profile.h"
53c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_proxy.h"
549ab869acfd02cf841a6c8309ae45acf936557720Paul McLean#include "alsa_logging.h"
55f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
56c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#define DEFAULT_INPUT_BUFFER_SIZE_MS 20
57f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
5919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
6019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
64c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile out_profile;
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
67c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile in_profile;
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
69253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    bool mic_muted;
70253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
7519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
7619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
80c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
81c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
8265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
83c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
8603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * This may differ from the device channel count when
8703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * the device is not compatible with AudioFlinger
8803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * capabilities, e.g. exposes too many channels or
8903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * too few channels. */
90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
10019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
10119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
10465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
105c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
1066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1072cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
1082cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * This may differ from the device channel count when
1092cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * the device is not compatible with AudioFlinger
1102cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * capabilities, e.g. exposes too many channels or
1112cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * too few channels. */
112c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
11330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
11430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
11530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
11630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
11819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
121eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
122eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
125eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
12930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
133e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
135e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples,
136e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 short * out_buff)
137e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
13830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
14030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
14130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
14230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
14330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
14488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const unsigned char* src_ptr = in_buff;
14530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
14630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
14730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
14830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
14930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
15030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
15130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
15230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
15330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
15430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
15530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
15630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
1576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples.
1586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   in_buff points to the buffer of PCM32 samples
1596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   num_in_samples size of input buffer in SAMPLES
1606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
1616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns
1626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   the number of BYTES of output data.
1636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
1646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit).
1656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE:
1666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
1676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module.
1686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
1696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff)
1706b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{
1716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /*
1726b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * Move from front to back so that the conversion can be done in-place
1736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. in_buff == out_buff
1746b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     */
1756b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1766b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    short * dst_ptr = out_buff;
1776b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const int32_t* src_ptr = in_buff;
1786b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    size_t src_smpl_index;
1796b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
1806b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        *dst_ptr++ = *src_ptr++ >> 16;
1816b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1826b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1836b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return number of *bytes* generated: */
1846b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return num_in_samples * 2;
1856b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
1866b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1870f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean/*
1880f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * Extract the card and device numbers from the supplied key/value pairs.
1890f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   kvpairs    A null-terminated string containing the key/value pairs or card and device.
1900f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *              i.e. "card=1;device=42"
1910f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   card   A pointer to a variable to receive the parsed-out card number.
1920f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   device A pointer to a variable to receive the parsed-out device number.
1930f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * NOTE: The variables pointed to by card and device return -1 (undefined) if the
1940f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *  associated key/value pair is not found in the provided string.
19565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean *  Return true if the kvpairs string contain a card/device spec, false otherwise.
1960f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean */
19765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLeanstatic bool parse_card_device_params(const char *kvpairs, int *card, int *device)
19819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1990f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
2000f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    char value[32];
2010f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    int param_val;
202f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
2030f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    // initialize to "undefined" state.
2040f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *card = -1;
2050f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *device = -1;
2060f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2070f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
2080f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
2090f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *card = atoi(value);
2100f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
2110f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2120f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
2130f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
2140f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *device = atoi(value);
2150f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
2160f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2170f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    str_parms_destroy(parms);
21865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
21965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    return *card >= 0 && *device >= 0;
2200f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean}
2210f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
2220f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
2230f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean{
224c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
226f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
227f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
228c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
229c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
230f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
231c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
232c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
233c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
234c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
235c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
236c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
238e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
23919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
242c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
243c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
244c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
245c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
246eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
24719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
248c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
249c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
250c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
251c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
252c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
253c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
25419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
25619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
258c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
259eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
26065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("device_get_parameters = %s", result_str);
261f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
262c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
26319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
265eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
266eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
267eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
268eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
269eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
270eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
271eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
27219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
273c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
274c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
275c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
278c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
279c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
280c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
290c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
291c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
292c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
293c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
29803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
29903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    return audio_channel_out_mask_from_count(out->hal_channel_count);
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
304c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
305c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
306c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
307c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
308c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
309c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
310c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
31119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
31519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
31619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
31719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
31919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
32019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
32119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
32319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
32419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
326c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
32819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
32919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
33219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
33619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
33919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
34119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
34219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
34365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("out_set_parameters() keys:%s", kvpairs);
344eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
34519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
346c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
34719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
348eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
34905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
35005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
35265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
35365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
35465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
35565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
35665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
35765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    /* Lock the device because that is where the profile lives */
358f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
359f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!profile_is_cached_for(out->profile, card, device)) {
36205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
36305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!out->standby)
36405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
36505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
36605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = out->profile->card;
36705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = out->profile->device;
36805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->card = card;
36905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->device = device;
37005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
37105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
37205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->card = saved_card;
37305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->device = saved_device;
37405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
37505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
376eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
3772c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
378f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
379f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
38019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
381eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
384f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
386c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
387f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
388f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->lock);
389f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
390f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
391f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
392f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
393f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
394f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
395f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
396f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
397f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
398f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
399f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
400c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
401c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
40219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
40319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
40430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
40519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
40619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
40719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
40819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
411eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
41265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("start_output_stream(card:%d device:%d)", out->profile->card, out->profile->device);
413eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
414c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
415eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
416eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
417eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
41819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
41919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
42019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
42119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
42319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
42705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&out->dev->lock);
42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
43205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&out->dev->lock);
43305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
434c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
43588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
436eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
43703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
43803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
43930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
44003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
44103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
44203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
44303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
44403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
44503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
44603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
44703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
44803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
44903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
45003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
451eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
45203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
45303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
45403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
455eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
456eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
457eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
458eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
459c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
469c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
47219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
47419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
47719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
47919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
48019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
481c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
482c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
483c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
484c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* FIXME - This needs to be implemented */
485c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -EINVAL;
486c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
487c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
49830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
50446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
50546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
50646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
50746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
508f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
5090f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                   const char *address /*__unused*/)
51019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
51165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
5120f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          handle, devices, flags, address);
513eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
51419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
515eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
51619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
51719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
51819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
51919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
52019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
52119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
522c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
52319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
52419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
52519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
52619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
52719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
52819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
52919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
53019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
53119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
53219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
53319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
53419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
53519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
53619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
53719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
53819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
54019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
54119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
54219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
5430f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&adev->lock);
544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
5482c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
549f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5500f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
5510f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(out->profile->card), &(out->profile->device));
5520f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5530f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(out->profile);
5540f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5550f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&adev->lock);
5560f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
557c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
558c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
559c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
560c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
561c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
562c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
563c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
564c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
565c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
566c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
567c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
56819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
569c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
570c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
571c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
572c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
573c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
574c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
575c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
576c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
578c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
579c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
580c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
581c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
582c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
584c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
58503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned proposed_channel_count = profile_get_default_channel_count(out->profile);
58603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
58703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
58803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
58903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
59103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* we can expose any channel count mask, and emulate internally. */
59203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
59303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    out->hal_channel_count = proposed_channel_count;
59403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
59503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
59603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    proxy_config.channels = proposed_channel_count;
597eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
598c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
599c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
600c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
601c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
602c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
603eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
60746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
609c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
610c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
61119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
61319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
61419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
615eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
61719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
61919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
62019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
62119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
62265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
62319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
624c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
62519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
626eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
627eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
628c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
629eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
630eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
631eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
63219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
63319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
63419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
63519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
63646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
63719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
64019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
64119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
642c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
643c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
644c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
645eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
647c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
648c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
649c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
651eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
654c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
660c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
6612cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
663eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
664eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
665eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
6662cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    const struct stream_in *in = (const struct stream_in*)stream;
6672cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return audio_channel_in_mask_from_count(in->hal_channel_count);
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
672c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO Here is the code we need when we support arbitrary input formats
673c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy;
674c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
675c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * ALOGV("in_get_format() = %d", format);
676c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * return format;
677c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
678c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Input only supports PCM16 */
679c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats
680c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean       rewrite this to return the ACTUAL channel format (above) */
681c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return AUDIO_FORMAT_PCM_16_BIT;
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
683eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
684eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
686c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
687c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
688eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
689eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
690eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
691eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
692eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
693c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
69430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
69630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
69730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
69830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
699c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
70030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
70130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
70230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
70330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
70430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
70530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
711eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
712eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
713eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
714eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
715eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
71665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("in_set_parameters() keys:%s", kvpairs);
717eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
718eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
719c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
720eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
721eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
722eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
723eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
72405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
72505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
726eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
72765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
72865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
72965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
73065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
73165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
732f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
733f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
734eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
7352c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
73605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
73705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!in->standby)
73805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
73905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
74005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = in->profile->card;
74105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = in->profile->device;
74205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->card = card;
74305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->device = device;
74405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
74505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
74605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->card = saved_card;
74705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->device = saved_device;
74805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
74905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
7502c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
751eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
752f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
753f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
754c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
756eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
758c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
759c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
76030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
761c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
762f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
763f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->lock);
76430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
765c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
76630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
767f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->lock);
768f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
7696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
770f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
774eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
775eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
776eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
778eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
780eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
781eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
782eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
785eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
786eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
787eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
789c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
790c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
79165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("ustart_input_stream(card:%d device:%d)", in->profile->card, in->profile->device);
79230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
793c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
79430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
79530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
796e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
79730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
79988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
80030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
80130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
80283b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    int ret = 0;
80330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
804c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
80530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
80730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
80830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
81005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            pthread_mutex_unlock(&in->dev->lock);
81130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
81430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    pthread_mutex_unlock(&in->dev->lock);
81605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
818c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
819c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
820c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
821c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
822c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
823c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
825c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int num_device_channels = proxy_get_channel_count(&in->proxy);
8262cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    int num_req_channels = in->hal_channel_count;
82730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
82830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
829cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
83030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
83130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
832c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    enum pcm_format format = proxy_get_format(&in->proxy);
833c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (format == PCM_FORMAT_S24_3LE) {
8346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
83530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
836c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (format == PCM_FORMAT_S32_LE) {
8376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
8386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
83930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
84030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
841c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
84230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
84330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
844e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
845e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
84630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
84730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
84830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
84930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
85030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
85130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
85283b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    ret = proxy_read(&in->proxy, read_buff, num_read_buff_bytes);
85383b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    if (ret == 0) {
85430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
85530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
85630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
858c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (format != PCM_FORMAT_S16_LE) {
859c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            /* we need to convert */
86030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
86130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
86230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
86330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
864c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            if (format == PCM_FORMAT_S24_3LE) {
8656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
867c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else if (format == PCM_FORMAT_S32_LE) {
8686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
8696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
870c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            } else {
8718c7e1114a3a07c3cb071df461d42e75b7ef3feaeViswanath L                LOG_ALWAYS_FATAL("Unsupported format");
8728c7e1114a3a07c3cb071df461d42e75b7ef3feaeViswanath L                num_read_buff_bytes = 0;
8736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
8746b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
87530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
87730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
878c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
879c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
88030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
88130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
882eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
883eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
884eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
885eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
886fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
887eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
888eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
889eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
890cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
89130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
892253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
893253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
894253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
895253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent            memset(buffer, 0, num_read_buff_bytes);
8968c7e1114a3a07c3cb071df461d42e75b7ef3feaeViswanath L    } else {
897e64994292cb02fae66f04002e1121d29979503d1Eric Laurent        num_read_buff_bytes = 0; // reset the value after USB headset is unplugged
89830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
90030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
90130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
90230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
90330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
905eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
90630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
90730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
91146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
91246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
91346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
91430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
9157d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
916f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
9170f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                  const char *address /*__unused*/,
918f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
91919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
92065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
92130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
923eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
9247661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
9257661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
926eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
929c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
930eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
932eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
933eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
934eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
935eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
936eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
937eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
938eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
939eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
940eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
941eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
942eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
943eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
944eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
945eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
946eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
94730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
9480f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&in->dev->lock);
949eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
950c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
951f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
952c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
9532c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9550f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
9560f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(in->profile->card), &(in->profile->device));
9570f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9580f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(in->profile);
9590f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&in->dev->lock);
9600f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
963c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
964c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
965c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
967c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
968c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9707661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9726b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
9736b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
9746b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
9756b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9766b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
9776b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
978c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9796b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
9806b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
9816b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
982c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
98330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
9846b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
9856b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
986c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = PCM_FORMAT_S16_LE;
9876b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
9886b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
989eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9902cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* Channels */
9912cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned proposed_channel_count = profile_get_default_channel_count(in->profile);
9922cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    if (k_force_channels) {
9932cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = k_force_channels;
9942cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_NONE) {
9952cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
996eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9982cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* we can expose any channel count mask, and emulate internally. */
9992cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
10002cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    in->hal_channel_count = proposed_channel_count;
10012cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
1003eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
100430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
100530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
100630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
100730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
100830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1009eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
1010eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
10117661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
101219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
101319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
101430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
101519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
101630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
101730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
101930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
102030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
102130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
102230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
102330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1026c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
1027c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
1028c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
1029c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
1030c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
103165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_set_parameters(%s)", kvpairs);
10322c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10332c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct audio_device * adev = (struct audio_device *)dev;
10342c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10352c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    char value[32];
10362c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    int param_val;
10372c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10382c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
10392c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10402c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    /* Check for the "disconnect" message */
10412c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    param_val = str_parms_get_str(parms, "disconnect", value, sizeof(value));
10422c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (param_val >= 0) {
10432c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        audio_devices_t device = (audio_devices_t)atoi(value);
10442c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10452c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "card", value, sizeof(value));
10462c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_card = param_val >= 0 ? atoi(value) : -1;
10472c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10482c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        param_val = str_parms_get_str(parms, "device", value, sizeof(value));
10492c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        int alsa_device = param_val >= 0 ? atoi(value) : -1;
10502c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
10512c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        if (alsa_card >= 0 && alsa_device >= 0) {
10522c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            /* "decache" the profile */
10532c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_lock(&adev->lock);
10542c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_OUT_USB_DEVICE &&
10552c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->out_profile, alsa_card, alsa_device)) {
10562c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->out_profile);
10572c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10582c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            if (device == AUDIO_DEVICE_IN_USB_DEVICE &&
10592c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_is_cached_for(&adev->in_profile, alsa_card, alsa_device)) {
10602c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean                profile_decache(&adev->in_profile);
10612c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            }
10622c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean            pthread_mutex_unlock(&adev->lock);
10632c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean        }
10642c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
10652c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
1066c357157e28dc0ffd069b80aeba9bf8b9eed72c9asoon    str_parms_destroy(parms);
1067c357157e28dc0ffd069b80aeba9bf8b9eed72c9asoon
1068c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1069c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1070c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1071c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
1072c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1073c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
1074c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1075c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1076c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
1077c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1078c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1079c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1080c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1081c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1082c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1083c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1084c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1085c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1086c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1087c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1088c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1089c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1090c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1091c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1092c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1093c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1094c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1095c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1096c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1097c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1098253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    struct audio_device * adev = (struct audio_device *)dev;
1099253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_lock(&adev->lock);
1100253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    adev->mic_muted = state;
1101253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_unlock(&adev->lock);
1102c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1103c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1104c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1105c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1106c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1107c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1108c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1109c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
111019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
111119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
111219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
111319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
111419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
111519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
111619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1117eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
111819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
112019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
112119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
112219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
112419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
112519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
112619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
112719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1128eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
112919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
113019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
113119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1132c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1133c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1134c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
113519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
113685e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1137c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
113819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
113919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
114019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
114119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
114219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
114319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
114419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
114519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
114619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
114719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
114819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
114919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
115019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
115119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
115219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
115319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
115419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
115519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
115619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
115719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
115819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
115919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
116019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
116119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
116219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
116319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
116419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
116519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
116619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
116746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
116846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
116919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
117019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
117119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
117219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
117319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
117419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1175