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