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
581d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean/* Lock play & record samples rates at or above this threshold */
591d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean#define RATELOCK_THRESHOLD 96000
601d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean
6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
6219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
6319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
67c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile out_profile;
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
69eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
70c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile in_profile;
71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
721d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    /* lock input & output sample rates */
731d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    /*FIXME - How do we address multiple output streams? */
741d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    uint32_t device_sample_rate;
751d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean
76253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    bool mic_muted;
77253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
7819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
7919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
8019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
8119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
85703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by playback thread */
86eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
87eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
88c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
89c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
91c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
9403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * This may differ from the device channel count when
9503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * the device is not compatible with AudioFlinger
9603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * capabilities, e.g. exposes too many channels or
9703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * too few channels. */
98182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
99182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung
100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
108eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
109703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
110703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by capture thread */
11119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
11219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
113c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
114eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
11565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
116c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
1176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1182cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
1192cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * This may differ from the device channel count when
1202cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * the device is not compatible with AudioFlinger
1212cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * capabilities, e.g. exposes too many channels or
1222cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * too few channels. */
123780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
124780f1f8149996442f43c77ec50518cc8030cd682Andy Hung
125c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
12930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
13019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
13119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
132eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
133703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * NOTE: when multiple mutexes have to be acquired, always take the
134703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * stream_in or stream_out mutex first, followed by the audio_device mutex.
135703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * stream pre_lock is always acquired before stream lock to prevent starvation of control thread by
136703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * higher priority playback or capture thread.
137703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent */
138703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
139703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent/*
1400f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * Extract the card and device numbers from the supplied key/value pairs.
1410f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   kvpairs    A null-terminated string containing the key/value pairs or card and device.
1420f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *              i.e. "card=1;device=42"
1430f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   card   A pointer to a variable to receive the parsed-out card number.
1440f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   device A pointer to a variable to receive the parsed-out device number.
1450f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * NOTE: The variables pointed to by card and device return -1 (undefined) if the
1460f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *  associated key/value pair is not found in the provided string.
14765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean *  Return true if the kvpairs string contain a card/device spec, false otherwise.
1480f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean */
14965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLeanstatic bool parse_card_device_params(const char *kvpairs, int *card, int *device)
15019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1510f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
1520f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    char value[32];
1530f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    int param_val;
154f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
1550f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    // initialize to "undefined" state.
1560f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *card = -1;
1570f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *device = -1;
1580f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1590f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
1600f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
1610f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *card = atoi(value);
1620f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
1630f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1640f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
1650f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
1660f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *device = atoi(value);
1670f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
1680f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1690f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    str_parms_destroy(parms);
17065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
17165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    return *card >= 0 && *device >= 0;
1720f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean}
1730f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1740f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
1750f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean{
176c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
177c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
178f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
179f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
180c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
181c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
182f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
183c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
184c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
185c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
186c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
188c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
189c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
190e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
19119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
193c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
194c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
196c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
197c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
19919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
201c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
202c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
203c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
204c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
205c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
20619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
20819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
209c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
210c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
21265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("device_get_parameters = %s", result_str);
213f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
214c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
21519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
21619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
217703180998f088cc83ff8e58f5881c65963d557a8Eric Laurentvoid lock_input_stream(struct stream_in *in)
218703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent{
219703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&in->pre_lock);
220703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&in->lock);
221703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->pre_lock);
222703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent}
223703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
224703180998f088cc83ff8e58f5881c65963d557a8Eric Laurentvoid lock_output_stream(struct stream_out *out)
225703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent{
226703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&out->pre_lock);
227703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&out->lock);
228703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&out->pre_lock);
229703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent}
230703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
234eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
235eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
236eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
237eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
23819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
239c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
24219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
24319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
244c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
245c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
246c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
24719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
25019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
25219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
25519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
256c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
258c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
259c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
26319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
26403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
265182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    return out->hal_channel_mask;
26619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
26919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
270c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
271c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
272c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
273c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
274c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
275c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
276c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
288703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
290703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&out->dev->lock);
291c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
292703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&out->dev->lock);
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("out_set_parameters() keys:%s", kvpairs);
308eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
30919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
310c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
31119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
312eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
31305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
31405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
31519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
31765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
31865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
31965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
32065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
321703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
32265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    /* Lock the device because that is where the profile lives */
323f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
32419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!profile_is_cached_for(out->profile, card, device)) {
32605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
32705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!out->standby)
32805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
32905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
33005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = out->profile->card;
33105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = out->profile->device;
33205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->card = card;
33305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->device = device;
33405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
33505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
33605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->card = saved_card;
33705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->device = saved_device;
33805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
33905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
340eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
3412c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
342f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
343703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&out->lock);
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
345eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
34619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
348f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
34919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
350c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
351703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
352f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
353f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
354f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
355f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
356f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
357f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
358f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
359f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
360f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
361f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
362f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
363f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
364c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
365c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
36619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
36919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
37019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
37119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
37219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
374eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
37665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("start_output_stream(card:%d device:%d)", out->profile->card, out->profile->device);
377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
378c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
380eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
381eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
386703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
388703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&out->dev->lock);
38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
390703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&out->dev->lock);
39119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
39419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
39605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
397c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
39888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
399eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
40003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
40103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
40230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
40303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
40403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
40503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
40603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
40703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
40803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
40903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
41003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
41103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
41203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
41303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
414eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
41503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
41603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
41703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
418eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
420eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
421eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
422c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
432c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
43719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
444c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
445c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
446c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
447c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    struct stream_out *out = (struct stream_out *)stream; // discard const qualifier
448c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    lock_output_stream(out);
449c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung
450c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    const alsa_device_proxy *proxy = &out->proxy;
451c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    const int ret = proxy_get_presentation_position(proxy, frames, timestamp);
452c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung
453c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    pthread_mutex_unlock(&out->lock);
454c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    return ret;
455c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
456c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
46019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
47346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
47446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
47546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
47646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
477f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
4780f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                   const char *address /*__unused*/)
47919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
48065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
4810f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          handle, devices, flags, address);
482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
484eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
491c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
50519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
50619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
50719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
508c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
50919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
51019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
511703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
512703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
513703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
51419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
5150f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&adev->lock);
516c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
518c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
519c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
5202c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
521f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5220f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
5230f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(out->profile->card), &(out->profile->device));
5240f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5250f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(out->profile);
5260f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
527c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    int ret = 0;
528c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
529c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Rate */
530c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->sample_rate == 0) {
531c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
532c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
533c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
535c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
536c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
537c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
53819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
5391d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    out->dev->device_sample_rate = config->sample_rate;
5401d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    pthread_mutex_unlock(&adev->lock);
5411d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean
542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
543c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
548c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
549c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
550c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
553c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
555c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
55619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
557c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
558182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    unsigned proposed_channel_count = 0;
55903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
56003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
561182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
562182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung        proposed_channel_count =  profile_get_default_channel_count(out->profile);
563eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
564698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean
565182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    if (proposed_channel_count != 0) {
5665e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        if (proposed_channel_count <= FCC_2) {
5675e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            // use channel position mask for mono and stereo
5685e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
5695e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        } else {
5705e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            // use channel index mask for multichannel
571182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung            config->channel_mask =
572182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
5735e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        }
574182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    } else {
575698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
576182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    }
577698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean    out->hal_channel_count = proposed_channel_count;
578698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean
579182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    /* we can expose any channel mask, and emulate internally based on channel count. */
580182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    out->hal_channel_mask = config->channel_mask;
581182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung
58203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
58303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
584698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean    proxy_config.channels = out->hal_channel_count;
585c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
586c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
587c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
588c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
589c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
591eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
592eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
593eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
59446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
59519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
596c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
597c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
59819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
59919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
60119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
602eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
60319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
60519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
60619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
60965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
61019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
611c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
613eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
614eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
615c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
616eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
617eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
618eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
6191d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    pthread_mutex_lock(&out->dev->lock);
6201d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    out->dev->device_sample_rate = 0;
6211d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    pthread_mutex_unlock(&out->dev->lock);
6221d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean
62319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
62419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
62519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
62619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
62746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
62819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
629c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
630c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
63119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
63219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
633c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
634c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
635c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
636eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
637eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
640c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
644eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
648eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
651c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
6522cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
6572cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    const struct stream_in *in = (const struct stream_in*)stream;
658780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    return in->hal_channel_mask;
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
663780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     alsa_device_proxy *proxy = &((struct stream_in*)stream)->proxy;
664780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
665780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     return format;
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
670c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
671c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
677c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
67830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
679703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
68030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
681703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&in->dev->lock);
682c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
683703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&in->dev->lock);
68430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
68530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
68630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
68730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
68830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
689eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
690eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
691eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
692eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
693eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
694eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
695eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
69965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("in_set_parameters() keys:%s", kvpairs);
700eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
701eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
702c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
70705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
70805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
71065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
71165ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
71265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
71365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
71465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
715703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
716f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
717eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
7182c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
71905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
72005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!in->standby)
72105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
72205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
72305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = in->profile->card;
72405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = in->profile->device;
72505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->card = card;
72605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->device = device;
72705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
72805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
72905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->card = saved_card;
73005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->device = saved_device;
73105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
73205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
7332c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
734eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
735f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
736703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->lock);
737c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
738eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
739eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
740eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
741c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
742c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
74330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
744c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
745703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
746f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
74730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
748c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
74930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
750f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
751703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->lock);
7526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
753f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
754eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
756eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
764eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
76630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
76730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
769eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
770eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
77130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
772c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
773c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
7741d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    ALOGV("start_input_stream(card:%d device:%d)", in->profile->card, in->profile->device);
77530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
776c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
77830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
779e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
78030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
78288e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
78330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
78583b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    int ret = 0;
78630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
787c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
789703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
79030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
791703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&in->dev->lock);
792703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        ret = start_input_stream(in);
793703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&in->dev->lock);
794703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        if (ret != 0) {
79530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
79630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
79730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
800c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
801c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
802c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
803c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
804c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
805c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
807780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    int num_device_channels = proxy_get_channel_count(&in->proxy); /* what we told Alsa */
808780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    int num_req_channels = in->hal_channel_count; /* what we told AudioFlinger */
80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
81030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
811cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
814c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
817e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
818e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
81930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
82130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
82230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
82330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
82583b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    ret = proxy_read(&in->proxy, read_buff, num_read_buff_bytes);
82683b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    if (ret == 0) {
82730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
828c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
829c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
83030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
83130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
832eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
833eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
834eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
835eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
836fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
837eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
838eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
839eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
840cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
842253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
843253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
844253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
845253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent            memset(buffer, 0, num_read_buff_bytes);
8468c7e1114a3a07c3cb071df461d42e75b7ef3feaeViswanath L    } else {
847e64994292cb02fae66f04002e1121d29979503d1Eric Laurent        num_read_buff_bytes = 0; // reset the value after USB headset is unplugged
84830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
849eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
85130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
85230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
85330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
854eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
855eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
86246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
86346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
86430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
8657d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
866f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
8670f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                  const char *address /*__unused*/,
868f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
86919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
8701d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    ALOGV("adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
87130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
872eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
8747661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
8757661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
877eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
879c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
890eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
891eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
894eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
896eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
897703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
898703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
899703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
90030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
9010f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&in->dev->lock);
902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
903c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
904f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
905c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
9062c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
907eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9080f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
9090f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(in->profile->card), &(in->profile->device));
9100f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9110f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(in->profile);
9120f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
9159a1c30572b3b27e66cb7d50fd89ae52e22d8718cPaul McLean        config->sample_rate = profile_get_default_sample_rate(in->profile);
9169a1c30572b3b27e66cb7d50fd89ae52e22d8718cPaul McLean    }
9179a1c30572b3b27e66cb7d50fd89ae52e22d8718cPaul McLean
9189a1c30572b3b27e66cb7d50fd89ae52e22d8718cPaul McLean    if (in->dev->device_sample_rate != 0 &&                 /* we are playing, so lock the rate */
9199a1c30572b3b27e66cb7d50fd89ae52e22d8718cPaul McLean        in->dev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
9201d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean        ret = config->sample_rate != in->dev->device_sample_rate ? -EINVAL : 0;
9211d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean        proxy_config.rate = config->sample_rate = in->dev->device_sample_rate;
922c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
9231d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean        in->dev->device_sample_rate = proxy_config.rate = config->sample_rate;
9246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
925c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
926c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9281d585cc7ab82ae96b95fcc85457e1834b08eabcfPaul McLean    pthread_mutex_unlock(&in->dev->lock);
9297661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
932780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        proxy_config.format = profile_get_default_format(in->profile);
933780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        config->format = audio_format_from_pcm_format(proxy_config.format);
93430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
935780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
936780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        if (profile_is_format_valid(in->profile, fmt)) {
937780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            proxy_config.format = fmt;
938780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        } else {
939780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            proxy_config.format = profile_get_default_format(in->profile);
940780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            config->format = audio_format_from_pcm_format(proxy_config.format);
941780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            ret = -EINVAL;
942780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        }
9436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
944eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9452cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* Channels */
946780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    unsigned proposed_channel_count = 0;
9472cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    if (k_force_channels) {
9482cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = k_force_channels;
949780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
950780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        proposed_channel_count = profile_get_default_channel_count(in->profile);
951eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
952780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    if (proposed_channel_count != 0) {
953780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
954780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        if (config->channel_mask == AUDIO_CHANNEL_INVALID)
955780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            config->channel_mask =
956780f1f8149996442f43c77ec50518cc8030cd682Andy Hung                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
957780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        in->hal_channel_count = proposed_channel_count;
958780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    } else {
959780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        in->hal_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
960780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    }
961780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    /* we can expose any channel mask, and emulate internally based on channel count. */
962780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    in->hal_channel_mask = config->channel_mask;
963c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9642cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
965c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
966eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
96730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
96830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
96930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
97030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
972eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
973eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9747661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
97519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
97619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
97730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
97819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
97930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
98030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
981c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
98230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
98330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
98530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
98719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
98819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
989c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
990c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
991c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
992c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
993c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
994c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
998c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
999c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
1000c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1001c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
1003c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1004c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1005c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1007c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
1008c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1009c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1010c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1011c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1012c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1013c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1014c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1015c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1016c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1017c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1019c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1020c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1021c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1022c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1023c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1024253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    struct audio_device * adev = (struct audio_device *)dev;
1025253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_lock(&adev->lock);
1026253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    adev->mic_muted = state;
1027253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_unlock(&adev->lock);
1028c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1029c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1030c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1031c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1032c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1033c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1034c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1035c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
103619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
103719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1043eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1045eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
104719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
105019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
105119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
105219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1054eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
105619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1058c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1059c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1060c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
106119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
106285e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1063c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
106419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
106519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
108419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
108619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
108819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
108919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
109019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
109346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
109446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
109519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
109619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
109919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1101