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