audio_hal.c revision 698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1d
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
585e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung// stereo channel count
595e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung#define FCC_2 2
60780f1f8149996442f43c77ec50518cc8030cd682Andy Hung// fixed channel count of 8 limitation (for data processing in AudioFlinger)
61780f1f8149996442f43c77ec50518cc8030cd682Andy Hung#define FCC_8 8
62780f1f8149996442f43c77ec50518cc8030cd682Andy Hung
6319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
6419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
6519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
6619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
67eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
69c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile out_profile;
70eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
72c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile in_profile;
73eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
74253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    bool mic_muted;
75253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
7619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
7719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
7819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
8019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
8119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
82eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
83703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by playback thread */
84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
85eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
86c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
87c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
8865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
89c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
9203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * This may differ from the device channel count when
9303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * the device is not compatible with AudioFlinger
9403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * capabilities, e.g. exposes too many channels or
9503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                         * too few channels. */
96182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
97182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung
98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
107703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
108703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_t pre_lock;           /* acquire before lock to avoid DOS by capture thread */
10919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
11019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
111c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct audio_device *dev;           /* hardware information - only using this for the lock */
112eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
11365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    alsa_device_profile * profile;      /* Points to the alsa_device_profile in the audio_device */
114c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy proxy;            /* state of the stream */
1156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
1162cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    unsigned hal_channel_count;         /* channel count exposed to AudioFlinger.
1172cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * This may differ from the device channel count when
1182cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * the device is not compatible with AudioFlinger
1192cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * capabilities, e.g. exposes too many channels or
1202cfd81bae005a795fa405db5615867b107ca02f9Paul McLean                                         * too few channels. */
121780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    audio_channel_mask_t hal_channel_mask;   /* channel mask exposed to AudioFlinger. */
122780f1f8149996442f43c77ec50518cc8030cd682Andy Hung
123c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */
12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
12819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
12919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
130eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
131703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * NOTE: when multiple mutexes have to be acquired, always take the
132703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * stream_in or stream_out mutex first, followed by the audio_device mutex.
133703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * stream pre_lock is always acquired before stream lock to prevent starvation of control thread by
134703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent * higher priority playback or capture thread.
135703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent */
136703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
137703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent/*
1380f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * Extract the card and device numbers from the supplied key/value pairs.
1390f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   kvpairs    A null-terminated string containing the key/value pairs or card and device.
1400f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *              i.e. "card=1;device=42"
1410f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   card   A pointer to a variable to receive the parsed-out card number.
1420f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *   device A pointer to a variable to receive the parsed-out device number.
1430f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean * NOTE: The variables pointed to by card and device return -1 (undefined) if the
1440f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean *  associated key/value pair is not found in the provided string.
14565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean *  Return true if the kvpairs string contain a card/device spec, false otherwise.
1460f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean */
14765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLeanstatic bool parse_card_device_params(const char *kvpairs, int *card, int *device)
14819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1490f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    struct str_parms * parms = str_parms_create_str(kvpairs);
1500f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    char value[32];
1510f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    int param_val;
152f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
1530f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    // initialize to "undefined" state.
1540f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *card = -1;
1550f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    *device = -1;
1560f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1570f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
1580f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
1590f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *card = atoi(value);
1600f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
1610f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1620f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
1630f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    if (param_val >= 0) {
1640f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean        *device = atoi(value);
1650f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    }
1660f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1670f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    str_parms_destroy(parms);
16865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
16965ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    return *card >= 0 && *device >= 0;
1700f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean}
1710f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
1720f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys)
1730f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean{
174c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (profile->card < 0 || profile->device < 0) {
175c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        return strdup("");
176f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    }
177f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
178c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *query = str_parms_create_str(keys);
179c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct str_parms *result = str_parms_create();
180f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
181c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* These keys are from hardware/libhardware/include/audio.h */
182c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample rates */
183c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
184c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* rates_list = profile_get_sample_rate_strs(profile);
185c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
186c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          rates_list);
187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(rates_list);
188e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
18919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
190c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported channel counts */
191c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char* channels_list = profile_get_channel_count_strs(profile);
193c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS,
194c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          channels_list);
195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(channels_list);
196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
19719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
198c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* supported sample formats */
199c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        char * format_params = profile_get_format_strs(profile);
201c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS,
202c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                          format_params);
203c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        free(format_params);
20419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
205c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(query);
20619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char* result_str = str_parms_to_str(result);
208c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    str_parms_destroy(result);
209eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
21065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("device_get_parameters = %s", result_str);
211f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
212c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return result_str;
21319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
21419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
215703180998f088cc83ff8e58f5881c65963d557a8Eric Laurentvoid lock_input_stream(struct stream_in *in)
216703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent{
217703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&in->pre_lock);
218703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&in->lock);
219703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->pre_lock);
220703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent}
221703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
222703180998f088cc83ff8e58f5881c65963d557a8Eric Laurentvoid lock_output_stream(struct stream_out *out)
223703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent{
224703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&out->pre_lock);
225703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_lock(&out->lock);
226703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&out->pre_lock);
227703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent}
228703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
229eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
230eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
234eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
235eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
23619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
238c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions
239c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
24019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
24119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
242c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy);
243c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("out_get_sample_rate() = %d", rate);
244c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
24519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
24619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
24719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
24819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
24919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
25019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
25219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
25319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
254c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_out* out = (const struct stream_out*)stream;
255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    size_t buffer_size =
256c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream));
257c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return buffer_size;
25819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
26203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const struct stream_out *out = (const struct stream_out*)stream;
263182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    return out->hal_channel_mask;
26419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
26519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
26619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
26719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
268c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Note: The HAL doesn't do any FORMAT conversion at this time. It
269c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * Relies on the framework to provide data in the specified format.
270c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * This could change in the future.
271c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
272c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
273c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
274c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return format;
27519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
28519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
286703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
288703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&out->dev->lock);
289c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&out->proxy);
290703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&out->dev->lock);
29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
30219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
30319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
30565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("out_set_parameters() keys:%s", kvpairs);
306eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
30719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
308c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
30919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
310eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
31105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
31205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
31319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
31565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
31665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
31765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
31865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
319703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
32065ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    /* Lock the device because that is where the profile lives */
321f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
32219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
32365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!profile_is_cached_for(out->profile, card, device)) {
32405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
32505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!out->standby)
32605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
32705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
32805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = out->profile->card;
32905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = out->profile->device;
33005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->card = card;
33105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            out->profile->device = device;
33205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL;
33305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
33405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->card = saved_card;
33505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                out->profile->device = saved_device;
33605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
33705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
338eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
3392c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean
340f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
341703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&out->lock);
34219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
343eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
34519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
346f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
34719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
348c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_out *out = (struct stream_out *)stream;
349703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&out->dev->lock);
351f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
352f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    char * params_str =  device_get_parameters(out->profile, keys);
353f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
354f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->lock);
355f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&out->dev->lock);
356f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
357f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
358f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean}
359f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
360f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
361f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{
362c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy;
363c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_get_latency(proxy);
36419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
36519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
36630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
36719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
36819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
36919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
37019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
37465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("start_output_stream(card:%d device:%d)", out->profile->card, out->profile->device);
375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
376c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&out->proxy);
377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
378eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
38019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
38119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
384703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_output_stream(out);
38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
386703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&out->dev->lock);
38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
388703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&out->dev->lock);
38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
39019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
39119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
39219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
39319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
39405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent
395c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_proxy* proxy = &out->proxy;
39688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
397eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
39803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_device_channels = proxy_get_channel_count(proxy); /* what we told alsa */
39903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    const int num_req_channels = out->hal_channel_count; /* what we told AudioFlinger */
40030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
40103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* allocate buffer */
40203576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const size_t required_conversion_buffer_size =
40303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                 bytes * num_device_channels / num_req_channels;
40403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        if (required_conversion_buffer_size > out->conversion_buffer_size) {
40503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer_size = required_conversion_buffer_size;
40603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung            out->conversion_buffer = realloc(out->conversion_buffer,
40703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                             out->conversion_buffer_size);
40803576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        }
40903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        /* convert data */
41003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const audio_format_t audio_format = out_get_format(&(out->stream.common));
41103576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        const unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
412eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
41303576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                adjust_channels(write_buff, num_req_channels,
41403576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                out->conversion_buffer, num_device_channels,
41503576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung                                sample_size_in_bytes, num_write_buff_bytes);
416eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
417eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
418eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
420c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
421eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
42219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
42419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
42719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
430c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
43730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
442c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream,
443c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean                                         uint64_t *frames, struct timespec *timestamp)
444c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
445c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    struct stream_out *out = (struct stream_out *)stream; // discard const qualifier
446c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    lock_output_stream(out);
447c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung
448c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    const alsa_device_proxy *proxy = &out->proxy;
449c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    const int ret = proxy_get_presentation_position(proxy, frames, timestamp);
450c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung
451c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    pthread_mutex_unlock(&out->lock);
452c9515ce60d45556cb11f49a3e35eb8ddc40548a7Andy Hung    return ret;
453c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
454c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
45519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
46530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
47146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
47246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
47346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
47446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
475f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                   struct audio_stream_out **stream_out,
4760f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                   const char *address /*__unused*/)
47719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
47865ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X, addr:%s",
4790f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean          handle, devices, flags, address);
480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
48319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
489c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
50519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
506c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->stream.get_presentation_position = out_get_presentation_position;
50719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
50819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
509703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
510703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
511703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
51219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
5130f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&adev->lock);
514c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    out->profile = &adev->out_profile;
515c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
516c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    // build this to hand to the alsa_device_proxy
517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
5182c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
519f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
5200f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
5210f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(out->profile->card), &(out->profile->device));
5220f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5230f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(out->profile);
5240f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
5250f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&adev->lock);
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
539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Format */
540c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
541c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.format = profile_get_default_format(out->profile);
542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        config->format = audio_format_from_pcm_format(proxy_config.format);
543c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else {
544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        if (profile_is_format_valid(out->profile, fmt)) {
546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = fmt;
547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        } else {
548c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            proxy_config.format = profile_get_default_format(out->profile);
549c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            config->format = audio_format_from_pcm_format(proxy_config.format);
550c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            ret = -EINVAL;
551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        }
552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    }
55319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Channels */
555182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    unsigned proposed_channel_count = 0;
55603576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    if (k_force_channels) {
55703576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung        proposed_channel_count = k_force_channels;
558182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
559182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung        proposed_channel_count =  profile_get_default_channel_count(out->profile);
560eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
561698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean
562182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    if (proposed_channel_count != 0) {
5635e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        if (proposed_channel_count <= FCC_2) {
5645e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            // use channel position mask for mono and stereo
5655e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            config->channel_mask = audio_channel_out_mask_from_count(proposed_channel_count);
5665e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        } else {
5675e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung            // use channel index mask for multichannel
568182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung            config->channel_mask =
569182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
5705e58a30b6f625d3c28d1c6b15eec3edf5643e227Andy Hung        }
571182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    } else {
572698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean        proposed_channel_count = audio_channel_count_from_out_mask(config->channel_mask);
573182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    }
574698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean    out->hal_channel_count = proposed_channel_count;
575698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean
576182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    /* we can expose any channel mask, and emulate internally based on channel count. */
577182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung    out->hal_channel_mask = config->channel_mask;
578182ddc7d130d078e3cdb1e1fbf02d86368a2ac47Andy Hung
57903576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung    /* no validity checks are needed as proxy_prepare() forces channel_count to be valid.
58003576bed8129d6d2faad5cb9c6aaae7cebb35d70Andy Hung     * and we emulate any channel count discrepancies in out_write(). */
581698dbd76b9c16bf1d2a3cb2d0268511e1ff4cd1dPaul McLean    proxy_config.channels = out->hal_channel_count;
582c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&out->proxy, out->profile, &proxy_config);
583c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
584c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */
585c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ret = 0;
586c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
587eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
588eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
589eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
59146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
59219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
593c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
594c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return ret;
59519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
59619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
59719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
59819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
599eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
60119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
60219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
60319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
60419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
60519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
60665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
608c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
60919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
610eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
611eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
612c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
613eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
614eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
615eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
61719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
61819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
61919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
62046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
62119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
622c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* TODO This needs to be calculated based on format/channels/rate */
623c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 320;
62419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
62519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
626c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
627c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions
628c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
629eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
630eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
631c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy);
632c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_get_sample_rate() = %d", rate);
633c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return rate;
634eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
635eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
636eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
637eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_sample_rate(%d) - NOPE", rate);
639eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
640eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
644c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    const struct stream_in * in = ((const struct stream_in*)stream);
6452cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    return proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream));
646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
648eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
649eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
6502cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    const struct stream_in *in = (const struct stream_in*)stream;
651780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    return in->hal_channel_mask;
652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
656780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     alsa_device_proxy *proxy = &((struct stream_in*)stream)->proxy;
657780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy));
658780f1f8149996442f43c77ec50518cc8030cd682Andy Hung     return format;
659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
663c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    ALOGV("in_set_format(%d) - NOPE", format);
664c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
665eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
670c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in *in = (struct stream_in *)stream;
67130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
672703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
67330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
674703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&in->dev->lock);
675c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_close(&in->proxy);
676703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&in->dev->lock);
67730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
67830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
67930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
68030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
68130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
683eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
684eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
686eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
688eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
689eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
690eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
691eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
69265ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("in_set_parameters() keys:%s", kvpairs);
693eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
694eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
695c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
699eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
70005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int card = -1;
70105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent    int device = -1;
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
70365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    if (!parse_card_device_params(kvpairs, &card, &device)) {
70465ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        // nothing to do
70565ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean        return ret_value;
70665ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    }
70765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean
708703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
709f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
7112c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
71205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        /* cannot read pcm device info if playback is active */
71305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        if (!in->standby)
71405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = -ENOSYS;
71505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        else {
71605333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_card = in->profile->card;
71705333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            int saved_device = in->profile->device;
71805333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->card = card;
71905333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            in->profile->device = device;
72005333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL;
72105333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            if (ret_value != 0) {
72205333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->card = saved_card;
72305333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent                in->profile->device = saved_device;
72405333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent            }
72505333d458d1c946a17c127372d3ff82558f38ee6Eric Laurent        }
7262c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    }
727eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
728f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
729703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->lock);
730c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
731eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
732eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
733eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
734c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys)
735c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
73630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
737c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
738703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
739f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_lock(&in->dev->lock);
74030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
741c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    char * params_str =  device_get_parameters(in->profile, keys);
74230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
743f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    pthread_mutex_unlock(&in->dev->lock);
744703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_unlock(&in->lock);
7456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
746f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean    return params_str;
747eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
748eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
749eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
750eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
751eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
752eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
753eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
754eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
756eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
75930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
76030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
76430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
765c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in)
766c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
76765ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("ustart_input_stream(card:%d device:%d)", in->profile->card, in->profile->device);
76830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
769c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return proxy_open(&in->proxy);
77030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
77130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
772e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
77330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
77430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
77588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
77630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
77883b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    int ret = 0;
77930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
780c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct stream_in * in = (struct stream_in *)stream;
78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
782703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    lock_input_stream(in);
78330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
784703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_lock(&in->dev->lock);
785703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        ret = start_input_stream(in);
786703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        pthread_mutex_unlock(&in->dev->lock);
787703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent        if (ret != 0) {
78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
79030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
79130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
79230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
793c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    alsa_device_profile * profile = in->profile;
794c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
795c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /*
796c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * OK, we need to figure out how much data to read to be able to output the requested
797c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     * number of bytes in the HAL format (16-bit, stereo).
798c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean     */
79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
800780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    int num_device_channels = proxy_get_channel_count(&in->proxy); /* what we told Alsa */
801780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    int num_req_channels = in->hal_channel_count; /* what we told AudioFlinger */
80230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
80330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
804cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
80530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
80630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
807c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Setup/Realloc the conversion buffer (if necessary). */
80830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
810e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
811e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
81430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
81883b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    ret = proxy_read(&in->proxy, read_buff, num_read_buff_bytes);
81983b47a6891a5bf3d546f0f7a8976132e45169075Pavan Chikkala    if (ret == 0) {
82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
821c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean            // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels);
822c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
82330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
825eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean            if (num_device_channels != num_req_channels) {
826eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                audio_format_t audio_format = in_get_format(&(in->stream.common));
827eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format);
828eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean
829fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
830eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                    adjust_channels(read_buff, num_device_channels,
831eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    out_buff, num_req_channels,
832eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean                                    sample_size_in_bytes, num_read_buff_bytes);
833cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
83430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
835253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent
836253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        /* no need to acquire in->dev->lock to read mic_muted here as we don't change its state */
837253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent        if (num_read_buff_bytes > 0 && in->dev->mic_muted)
838253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent            memset(buffer, 0, num_read_buff_bytes);
8398c7e1114a3a07c3cb071df461d42e75b7ef3feaeViswanath L    } else {
840e64994292cb02fae66f04002e1121d29979503d1Eric Laurent        num_read_buff_bytes = 0; // reset the value after USB headset is unplugged
84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
842eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
84330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
84430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
84530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
84630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
847eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
848eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
84930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
85030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
851eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
852eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
853eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
85446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
85546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
85646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
8587d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten                                  struct audio_stream_in **stream_in,
859f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_input_flags_t flags __unused,
8600f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean                                  const char *address /*__unused*/,
861f5e2469c02825f018df6336125882812003b8e64Eric Laurent                                  audio_source_t source __unused)
86219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
86365ec72b72b01fa2269e91de7c6eb3e6285f9fa86Paul McLean    ALOGV("in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
86430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
865eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
866eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
8677661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
8687661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
871eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
872c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* setup function pointers */
873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
874eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
877eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
879eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
890703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
891703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent    pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
892703180998f088cc83ff8e58f5881c65963d557a8Eric Laurent
89330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
8940f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_lock(&in->dev->lock);
895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
896c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    in->profile = &in->dev->in_profile;
897f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean
898c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    struct pcm_config proxy_config;
8992c6196f20c2ca25f6e7f8e0f752c2cbc00113538Paul McLean    memset(&proxy_config, 0, sizeof(proxy_config));
900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9010f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    /* Pull out the card/device pair */
9020f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    parse_card_device_params(address, &(in->profile->card), &(in->profile->device));
9030f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9040f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    profile_read_device_info(in->profile);
9050f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean    pthread_mutex_unlock(&in->dev->lock);
9060f1753ead073b9abffb23dc712bb636280d7f5a6Paul McLean
9076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
9086b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
909c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
910c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
911c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate;
9126b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
913c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
914c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean        ret = -EINVAL;
9156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
9167661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
9176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
9186b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
919780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        proxy_config.format = profile_get_default_format(in->profile);
920780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        config->format = audio_format_from_pcm_format(proxy_config.format);
92130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
922780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        enum pcm_format fmt = pcm_format_from_audio_format(config->format);
923780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        if (profile_is_format_valid(in->profile, fmt)) {
924780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            proxy_config.format = fmt;
925780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        } else {
926780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            proxy_config.format = profile_get_default_format(in->profile);
927780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            config->format = audio_format_from_pcm_format(proxy_config.format);
928780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            ret = -EINVAL;
929780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        }
9306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9322cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    /* Channels */
933780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    unsigned proposed_channel_count = 0;
9342cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    if (k_force_channels) {
9352cfd81bae005a795fa405db5615867b107ca02f9Paul McLean        proposed_channel_count = k_force_channels;
936780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    } else if (config->channel_mask == AUDIO_CHANNEL_NONE) {
937780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        proposed_channel_count = profile_get_default_channel_count(in->profile);
938eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
939780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    if (proposed_channel_count != 0) {
940780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        config->channel_mask = audio_channel_in_mask_from_count(proposed_channel_count);
941780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        if (config->channel_mask == AUDIO_CHANNEL_INVALID)
942780f1f8149996442f43c77ec50518cc8030cd682Andy Hung            config->channel_mask =
943780f1f8149996442f43c77ec50518cc8030cd682Andy Hung                    audio_channel_mask_for_index_assignment_from_count(proposed_channel_count);
944780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        in->hal_channel_count = proposed_channel_count;
945780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    } else {
946780f1f8149996442f43c77ec50518cc8030cd682Andy Hung        in->hal_channel_count = audio_channel_count_from_in_mask(config->channel_mask);
947780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    }
948780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    /* we can expose any channel mask, and emulate internally based on channel count. */
949780f1f8149996442f43c77ec50518cc8030cd682Andy Hung    in->hal_channel_mask = config->channel_mask;
950c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
9512cfd81bae005a795fa405db5615867b107ca02f9Paul McLean    proxy_config.channels = profile_get_default_channel_count(in->profile);
952c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    proxy_prepare(&in->proxy, in->profile, &proxy_config);
953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
95430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
95530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
95630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
95730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
95830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
959eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
960eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
9617661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
96219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
96319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
96430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
96519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
96630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
96730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
968c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    /* Close the pcm device */
96930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
97030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
97230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
97419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
97519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
976c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/*
977c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions
978c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */
979c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
980c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
981c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
982c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
983c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
984c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
985c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
986c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return strdup("");
987c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
988c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
989c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev)
990c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
991c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
992c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
993c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
994c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
998c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
999c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
1000c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1001c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1003c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1004c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
1005c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return 0;
1007c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1008c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1009c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
1010c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1011253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    struct audio_device * adev = (struct audio_device *)dev;
1012253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_lock(&adev->lock);
1013253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    adev->mic_muted = state;
1014253def9fa0b5d597125ce0af883d9c1deddd7ef9Eric Laurent    pthread_mutex_unlock(&adev->lock);
1015c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1016c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1017c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
1019c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{
1020c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    return -ENOSYS;
1021c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean}
1022c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
102319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
102619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
102719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
102819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
102919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1030eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
103119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1032eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
103319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
103419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
103519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
103630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
103719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1041eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
104319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1045c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->out_profile, PCM_OUT);
1046c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    profile_init(&adev->in_profile, PCM_IN);
1047c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean
104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
104985e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
1050c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean    adev->hw_device.common.module = (struct hw_module_t *)module;
105119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
105219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
105419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
105619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
105819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
105919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
106019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
106119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
106219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
106319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
106419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
106519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
108046a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
108146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
108419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
108619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1088