audio_hal.c revision f5e2469c02825f018df6336125882812003b8e64
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 1719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#define LOG_TAG "usb_audio_hw" 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 41c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_profile.h" 42c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "alsa_device_proxy.h" 43c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#include "logging.h" 44f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 45c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean#define DEFAULT_INPUT_BUFFER_SIZE_MS 20 46f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 4719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device { 4819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_hw_device hw_device; 4919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 5019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 51eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 52eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* output */ 53c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile out_profile; 54eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* input */ 56c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile in_profile; 57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 5819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 5919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 6019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 6119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out { 6219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out stream; 6319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_t lock; /* see note below on mutex acquisition order */ 65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool standby; 66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 67c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct audio_device *dev; /* hardware information - only using this for the lock */ 68c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 69c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile * profile; 70c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_proxy proxy; /* state of the stream */ 71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 72eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean void * conversion_buffer; /* any conversions are put into here 73eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * they could come from here too if 74eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * there was a previous conversion */ 75eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean size_t conversion_buffer_size; /* in bytes */ 76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}; 77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in { 79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_stream_in stream; 80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 8119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 84c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct audio_device *dev; /* hardware information - only using this for the lock */ 85eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 86c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile * profile; 87c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_proxy proxy; /* state of the stream */ 886b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 89c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean // not used? 90c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean // struct audio_config hal_pcm_config; 9130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 92c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* We may need to read more data from the device in order to data reduce to 16bit, 4chan */ 9330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * conversion_buffer; /* any conversions are put into here 9430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * they could come from here too if 9530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * there was a previous conversion */ 9630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t conversion_buffer_size; /* in bytes */ 9719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 9819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions 101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 10330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples. 10430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM24LE samples 105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * num_in_samples size of input buffer in SAMPLES 10630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff points to the buffer to receive converted PCM16LE LE samples. 10730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 10830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 10930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 11030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed). 11130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: 11230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 113e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module. 11430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 115e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples, 116e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean short * out_buff) 117e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{ 11830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 11930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Move from front to back so that the conversion can be done in-place 12030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * i.e. in_buff == out_buff 12130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 12230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* we need 2 bytes in the output for every 3 bytes in the input */ 12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned char* dst_ptr = (unsigned char*)out_buff; 12488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn const unsigned char* src_ptr = in_buff; 12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t src_smpl_index; 12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean src_ptr++; /* lowest-(skip)-byte */ 12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* low-byte */ 12930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* high-byte */ 13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* return number of *bytes* generated: */ 13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_in_samples * 2; 13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 1376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples. 1386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * in_buff points to the buffer of PCM32 samples 1396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * num_in_samples size of input buffer in SAMPLES 1406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * out_buff points to the buffer to receive converted PCM16LE LE samples. 1416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns 1426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * the number of BYTES of output data. 1436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 1446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit). 1456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE: 1466b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 1476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module. 1486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */ 1496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff) 1506b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{ 1516b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 1526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Move from front to back so that the conversion can be done in-place 1536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * i.e. in_buff == out_buff 1546b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */ 1556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 1566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean short * dst_ptr = out_buff; 1576b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean const int32_t* src_ptr = in_buff; 1586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean size_t src_smpl_index; 1596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 1606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *dst_ptr++ = *src_ptr++ >> 16; 1616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 1626b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 1636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* return number of *bytes* generated: */ 1646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean return num_in_samples * 2; 1656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean} 1666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 167c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * device_get_parameters(alsa_device_profile * profile, const char * keys) 16819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 169c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("usb:audio_hw::device_get_parameters() keys:%s", keys); 170f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 171c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (profile->card < 0 || profile->device < 0) { 172c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return strdup(""); 173f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean } 174f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 175c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct str_parms *query = str_parms_create_str(keys); 176c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct str_parms *result = str_parms_create(); 177f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 178c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* These keys are from hardware/libhardware/include/audio.h */ 179c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* supported sample rates */ 180c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { 181c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean char* rates_list = profile_get_sample_rate_strs(profile); 182c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, 183c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean rates_list); 184c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean free(rates_list); 185e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 18619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 187c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* supported channel counts */ 188c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { 189c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean char* channels_list = profile_get_channel_count_strs(profile); 190c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, 191c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean channels_list); 192c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean free(channels_list); 193eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 19419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 195c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* supported sample formats */ 196c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { 197c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean char * format_params = profile_get_format_strs(profile); 198c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, 199c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean format_params); 200c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean free(format_params); 20119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 202c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean str_parms_destroy(query); 20319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 204c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean char* result_str = str_parms_to_str(result); 205c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean str_parms_destroy(result); 206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 207c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("usb:audio_hw::device_get_parameters = %s", result_str); 208f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 209c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return result_str; 21019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 21119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 212eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions 214eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 215eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/** 216eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the 217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream 218eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 21919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 220c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/* 221c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OUT functions 222c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 22319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream) 22419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 225c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean uint32_t rate = proxy_get_sample_rate(&((struct stream_out*)stream)->proxy); 226c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("out_get_sample_rate() = %d", rate); 227c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return rate; 22819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 22919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 23019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) 23119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 23219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 23319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 23419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 23519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream) 23619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 237c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean const struct stream_out* out = (const struct stream_out*)stream; 238c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean size_t buffer_size = 239c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_get_period_size(&out->proxy) * audio_stream_out_frame_size(&(out->stream)); 240c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("out_get_buffer_size() = %zu", buffer_size); 241c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return buffer_size; 24219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 24319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 24419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream) 24519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 246c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* 247c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * alsa_device_profile * profile = ((struct stream_out*)stream)->profile; 248c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * unsigned channel_count = profile_get_channel_count(profile); 249c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * uint32_t channel_mask = audio_channel_out_mask_from_count(channel_count); 250c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ALOGV("out_get_channels() = 0x%X count:%d", channel_mask, channel_count); 251c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * return channel_mask; 252c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 253c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 254c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Always Stereo for now. We will do *some* conversions in this HAL. 255c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels 256c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * rewrite this to return the ACTUAL channel format */ 25719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return AUDIO_CHANNEL_OUT_STEREO; 25819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 25919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 26019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream) 26119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 262c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Note: The HAL doesn't do any FORMAT conversion at this time. It 263c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * Relies on the framework to provide data in the specified format. 264c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * This could change in the future. 265c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 266c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy; 267c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy)); 268c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("out_get_format() = %d", format); 269c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return format; 27019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 27119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 27219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format) 27319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 27419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 27519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 27619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 27719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream) 27819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 27919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 28019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 28119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 28219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 28319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 28419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out->standby) { 285c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_close(&out->proxy); 28619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = true; 28719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 28819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 28919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 29019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->dev->lock); 29119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 29219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 29319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 29419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 29519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd) 29619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 29719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 29819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 29919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 30019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs) 30119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 302eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs); 303eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 30419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 305c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 30619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson char value[32]; 307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 30819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int routing = 0; 309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 31019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 311c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct str_parms * parms = str_parms_create_str(kvpairs); 312f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&out->dev->lock); 313f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&out->lock); 31419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 315eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool recache_device_params = false; 316eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 317eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 318f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean out->profile->card = atoi(value); 319eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 320eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 321eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 324f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean out->profile->device = atoi(value); 325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 32719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 328f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean if (recache_device_params && out->profile->card >= 0 && out->profile->device >= 0) { 329c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret_value = profile_read_device_info(out->profile) ? 0 : -EINVAL; 330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 33119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 332f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&out->lock); 333f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&out->dev->lock); 33419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson str_parms_destroy(parms); 33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 33719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 33819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 339f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys) 34019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 341c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct stream_out *out = (struct stream_out *)stream; 342f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&out->dev->lock); 343f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&out->lock); 344f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 345f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean char * params_str = device_get_parameters(out->profile, keys); 346f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 347f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&out->lock); 348f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&out->dev->lock); 349f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 350f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean return params_str; 351f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean} 352f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 353f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLeanstatic uint32_t out_get_latency(const struct audio_stream_out *stream) 354f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean{ 355c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_proxy * proxy = &((struct stream_out*)stream)->proxy; 356c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return proxy_get_latency(proxy); 35719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 35819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 35930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right) 36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 36119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 36219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 36319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 364eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */ 365eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out) 366eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 36730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)", 368f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean out->profile->card, out->profile->device); 369eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 370c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return proxy_open(&out->proxy); 371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) 37419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 37519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int ret; 37619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 37719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 37819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 37919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 380c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean pthread_mutex_unlock(&out->dev->lock); 381c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 38219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (out->standby) { 38319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson ret = start_output_stream(out); 38419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson goto err; 38619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = false; 38819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 38919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 390c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile* profile = out->profile; 391c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_proxy* proxy = &out->proxy; 392c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 393c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* 394c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * Setup conversion buffer 395c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * compute maximum potential buffer size. 396c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * * 2 for stereo -> quad conversion 397c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * * 3/2 for 16bit -> 24 bit conversion 398c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 39988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t required_conversion_buffer_size = (bytes * 3 * 2) / 2; 40030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (required_conversion_buffer_size > out->conversion_buffer_size) { 401e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 402e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean (and do these conversions themselves) */ 40330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer_size = required_conversion_buffer_size; 40430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size); 40530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 40630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 40788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn const void * write_buff = buffer; 408eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_write_buff_bytes = bytes; 409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 410eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 411eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Num Channels conversion 412eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 413c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean int num_device_channels = proxy_get_channel_count(proxy); 414c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean int num_req_channels = 2; /* always for now */ 415c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 41630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 417eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean audio_format_t audio_format = out_get_format(&(out->stream.common)); 418eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format); 419eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_write_buff_bytes = 420eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean adjust_channels(write_buff, num_req_channels, 421eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean out->conversion_buffer, num_device_channels, 422eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean sample_size_in_bytes, num_write_buff_bytes); 423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean write_buff = out->conversion_buffer; 424eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 425eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 426eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (write_buff != NULL && num_write_buff_bytes != 0) { 427c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_write(&out->proxy, write_buff, num_write_buff_bytes); 428eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr: 43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 437c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) / 43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_get_sample_rate(&stream->common)); 43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 44319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 44430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) 44519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 44619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 44719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 44819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 449c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int out_get_presentation_position(const struct audio_stream_out *stream, 450c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean uint64_t *frames, struct timespec *timestamp) 451c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 452c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* FIXME - This needs to be implemented */ 453c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return -EINVAL; 454c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 455c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 45919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 46019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 46519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 46630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp) 46719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev, 47246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 47346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 47446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_output_flags_t flags, 47546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood struct audio_config *config, 476f5e2469c02825f018df6336125882812003b8e64Eric Laurent struct audio_stream_out **stream_out, 477f5e2469c02825f018df6336125882812003b8e64Eric Laurent const char *address __unused) 47819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 47930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X", 480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean handle, devices, flags); 481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 48219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *adev = (struct audio_device *)dev; 483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out; 48519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 48619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); 48719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out) 48819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 48919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 490c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* setup function pointers */ 49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_sample_rate = out_get_sample_rate; 49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_sample_rate = out_set_sample_rate; 49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_buffer_size = out_get_buffer_size; 49419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_channels = out_get_channels; 49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_format = out_get_format; 49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_format = out_set_format; 49719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.standby = out_standby; 49819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.dump = out_dump; 49919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_parameters = out_set_parameters; 50019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_parameters = out_get_parameters; 50119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.add_audio_effect = out_add_audio_effect; 50219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.remove_audio_effect = out_remove_audio_effect; 50319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_latency = out_get_latency; 50419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.set_volume = out_set_volume; 50519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.write = out_write; 50619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_render_position = out_get_render_position; 507c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean out->stream.get_presentation_position = out_get_presentation_position; 50819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_next_write_timestamp = out_get_next_write_timestamp; 50919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 51019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->dev = adev; 51119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 512c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean out->profile = &adev->out_profile; 513c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 514c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean // build this to hand to the alsa_device_proxy 515c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct pcm_config proxy_config; 516f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 517c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean int ret = 0; 518c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 519c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Rate */ 520c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (config->sample_rate == 0) { 521c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); 522c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) { 523c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate; 524c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 525c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile); 526c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret = -EINVAL; 527c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } 52819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 529c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Format */ 530c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (config->format == AUDIO_FORMAT_DEFAULT) { 531c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = profile_get_default_format(out->profile); 532c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean config->format = audio_format_from_pcm_format(proxy_config.format); 533c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 534c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean enum pcm_format fmt = pcm_format_from_audio_format(config->format); 535c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (profile_is_format_valid(out->profile, fmt)) { 536c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = fmt; 537c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 538c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = profile_get_default_format(out->profile); 539c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean config->format = audio_format_from_pcm_format(proxy_config.format); 540c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret = -EINVAL; 541c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } 542c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } 54319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 544c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Channels */ 545c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (config->channel_mask == AUDIO_CHANNEL_NONE) { 546c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* This will be needed when the framework supports non-stereo output */ 547c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* config->channel_mask = 548c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * audio_channel_out_mask_from_count(profile_get_default_channel_count(out->profile)); 549c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 550c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.channels = profile_get_default_channel_count(out->profile); 551c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 552c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 553c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* This will be needed when the framework supports non-stereo output */ 554c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* 555c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * unsigned channel_count = audio_channel_count_from_out_mask(config->channel_mask); 556c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * if (profile_is_channel_count_valid(out->profile, channel_count)) { 557c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * proxy_set_channel_count(out->proxy, channel_count); 558c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * } else { 559c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * config->channel_mask = 560c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * audio_channel_out_mask_from_count(proxy_get_channel_count(out->proxy)); 561c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ret = -EINVAL; 562c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * } 563c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) { 565c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.channels = profile_get_default_channel_count(out->profile); 566eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 567c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret = -EINVAL; 568c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 569c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.channels = profile_get_default_channel_count(out->profile); 570eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 571eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 572eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 573c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_prepare(&out->proxy, out->profile, &proxy_config); 574c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 575c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger. */ 576c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret = 0; 577c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 578eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 579eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 580eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 581eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->standby = true; 58246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood 58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = &out->stream; 584c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 585c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return ret; 58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 58719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open: 58819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(out); 58919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = NULL; 590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 59119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 59219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 59319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev, 59419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out *stream) 59519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 596eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out adev_close_output_stream()"); 59719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 59819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 599c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Close the pcm device */ 60019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_standby(&stream->common); 601eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 602eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean free(out->conversion_buffer); 603c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 60719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(stream); 60819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 60919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 61019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, 61146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood const struct audio_config *config) 61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 613c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO This needs to be calculated based on format/channels/rate */ 614c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return 320; 61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 617c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/* 618c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * IN functions 619c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 620eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream) 621eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 622c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean uint32_t rate = proxy_get_sample_rate(&((const struct stream_in *)stream)->proxy); 623c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("in_get_sample_rate() = %d", rate); 624c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return rate; 625eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 626eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 627eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) 628eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 629c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("in_set_sample_rate(%d) - NOPE", rate); 630eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 631eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 632eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 633eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream) 634eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 635c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean const struct stream_in * in = ((const struct stream_in*)stream); 636c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean size_t buffer_size = 637c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_get_period_size(&in->proxy) * audio_stream_in_frame_size(&(in->stream)); 638c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("in_get_buffer_size() = %zd", buffer_size); 639c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 640c5ae6a030484f83beb3f2120f136cec1c0ef8b0aEric Laurent return buffer_size; 641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream) 644eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 645c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO Here is the code we need when we support arbitrary channel counts 646c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy; 647c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * unsigned channel_count = proxy_get_channel_count(proxy); 648c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * uint32_t channel_mask = audio_channel_in_mask_from_count(channel_count); 649c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ALOGV("in_get_channels() = 0x%X count:%d", channel_mask, channel_count); 650c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * return channel_mask; 651c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 652c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels 653c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean rewrite this to return the ACTUAL channel format */ 65430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return AUDIO_CHANNEL_IN_STEREO; 655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream) 658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 659c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO Here is the code we need when we support arbitrary input formats 660c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * alsa_device_proxy * proxy = ((struct stream_in*)stream)->proxy; 661c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * audio_format_t format = audio_format_from_pcm_format(proxy_get_format(proxy)); 662c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ALOGV("in_get_format() = %d", format); 663c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * return format; 664c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 665c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Input only supports PCM16 */ 666c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary input formats 667c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean rewrite this to return the ACTUAL channel format (above) */ 668c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return AUDIO_FORMAT_PCM_16_BIT; 669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format) 672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 673c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ALOGV("in_set_format(%d) - NOPE", format); 674c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream) 679eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 680c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct stream_in *in = (struct stream_in *)stream; 68130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 68230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 68330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 68430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 68530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (!in->standby) { 686c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_close(&in->proxy); 68730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 68830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 68930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 69030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 69130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->dev->lock); 69230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 693eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 694eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 695eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd) 697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 698eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 699eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 700eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 701eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs) 702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 70330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs); 704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)stream; 706c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char value[32]; 708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 709eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int routing = 0; 710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 711eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 712c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct str_parms * parms = str_parms_create_str(kvpairs); 713c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 714f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&in->dev->lock); 715f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&in->lock); 716eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 71730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean bool recache_device_params = false; 71830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 719c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Card/Device */ 720eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 721eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 722f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean in->profile->card = atoi(value); 72330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 724eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 725eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 726eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 727eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 728f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean in->profile->device = atoi(value); 72930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 730eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 731eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 732f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean if (recache_device_params && in->profile->card >= 0 && in->profile->device >= 0) { 733c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret_value = profile_read_device_info(in->profile) ? 0 : -EINVAL; 734c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } 735eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 736f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&in->lock); 737f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&in->dev->lock); 738c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 739eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(parms); 740eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 741eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 742eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 743eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 744c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys) 745c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 74630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 747c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 748f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&in->dev->lock); 749f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_lock(&in->lock); 75030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 751c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean char * params_str = device_get_parameters(in->profile, keys); 75230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 753f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&in->lock); 754f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean pthread_mutex_unlock(&in->dev->lock); 7556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 756f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean return params_str; 757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 764eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 76930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain) 77030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 77430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */ 775c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int start_input_stream(struct stream_in *in) 776c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 77730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)", 778f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean in->profile->card, in->profile->device); 77930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 780c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return proxy_open(&in->proxy); 78130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 78230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 783e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */ 78430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) 78530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 78688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t num_read_buff_bytes = 0; 78730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * read_buff = buffer; 78830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * out_buff = buffer; 78930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 790c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct stream_in * in = (struct stream_in *)stream; 79130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 79230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 79330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 794c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean pthread_mutex_unlock(&in->dev->lock); 79530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 79630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->standby) { 79730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (start_input_stream(in) != 0) { 79830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean goto err; 79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 80030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = false; 80130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 80230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 803c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean alsa_device_profile * profile = in->profile; 804c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 805c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* 806c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * OK, we need to figure out how much data to read to be able to output the requested 807c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * number of bytes in the HAL format (16-bit, stereo). 808c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 80930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = bytes; 810c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean int num_device_channels = proxy_get_channel_count(&in->proxy); 81130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_req_channels = 2; /* always, for now */ 81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 814cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels; 81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 81630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 817c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean enum pcm_format format = proxy_get_format(&in->proxy); 818c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (format == PCM_FORMAT_S24_3LE) { 8196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 24-bit USB device */ 82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = (3 * num_read_buff_bytes) / 2; 821c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else if (format == PCM_FORMAT_S32_LE) { 8226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 32-bit USB device */ 8236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = num_read_buff_bytes * 2; 82430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 82530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 826c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Setup/Realloc the conversion buffer (if necessary). */ 82730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes != bytes) { 82830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes > in->conversion_buffer_size) { 829e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 830e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean (and do these conversions themselves) */ 83130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = num_read_buff_bytes; 83230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size); 83330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 83430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean read_buff = in->conversion_buffer; 83530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 83630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 837c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (proxy_read(&in->proxy, read_buff, num_read_buff_bytes) == 0) { 83830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 83930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Do any conversions necessary to send the data in the format specified to/by the HAL 84030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan. 84130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 842c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (format != PCM_FORMAT_S16_LE) { 843c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* we need to convert */ 84430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 84530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = read_buff; 84630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 84730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 848c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean if (format == PCM_FORMAT_S24_3LE) { 8496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = 8506b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff); 851c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else if (format == PCM_FORMAT_S32_LE) { 8526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = 8536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff); 854c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else { 8556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean goto err; 8566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 85730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 85930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 860c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean // ALOGV("chans dev:%d req:%d", num_device_channels, num_req_channels); 861c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 86230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = buffer; 86330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* Num Channels conversion */ 864eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean if (num_device_channels != num_req_channels) { 865eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean audio_format_t audio_format = in_get_format(&(in->stream.common)); 866eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean unsigned sample_size_in_bytes = audio_bytes_per_sample(audio_format); 867eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean 868fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent num_read_buff_bytes = 869eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean adjust_channels(read_buff, num_device_channels, 870eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean out_buff, num_req_channels, 871eb192973f39b0a2f9ecab671f6c719e917e52cc7Paul McLean sample_size_in_bytes, num_read_buff_bytes); 872cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean } 87330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 87430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 87630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr: 87730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 87830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 87930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_read_buff_bytes; 880eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 88230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) 88330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 88746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev, 88846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 88946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 89030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_config *config, 8917d973adff4c9b344b530dd7c585f789d02c605daGlenn Kasten struct audio_stream_in **stream_in, 892f5e2469c02825f018df6336125882812003b8e64Eric Laurent audio_input_flags_t flags __unused, 893f5e2469c02825f018df6336125882812003b8e64Eric Laurent const char *address __unused, 894f5e2469c02825f018df6336125882812003b8e64Eric Laurent audio_source_t source __unused) 89519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 89688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8, 89730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->sample_rate, config->channel_mask, config->format); 898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); 9007661a484021f6e7c3b219bd21659118eef94e45bEric Laurent int ret = 0; 9017661a484021f6e7c3b219bd21659118eef94e45bEric Laurent 902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (in == NULL) 903eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 904eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 905c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* setup function pointers */ 906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_sample_rate = in_get_sample_rate; 907eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_sample_rate = in_set_sample_rate; 908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_buffer_size = in_get_buffer_size; 909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_channels = in_get_channels; 910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_format = in_get_format; 911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_format = in_set_format; 912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.standby = in_standby; 913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.dump = in_dump; 914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_parameters = in_set_parameters; 915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_parameters = in_get_parameters; 916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.add_audio_effect = in_add_audio_effect; 917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.remove_audio_effect = in_remove_audio_effect; 918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.set_gain = in_set_gain; 920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.read = in_read; 921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.get_input_frames_lost = in_get_input_frames_lost; 922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 92330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->dev = (struct audio_device *)dev; 924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 925c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean in->profile = &in->dev->in_profile; 926f62d75ebc600a0e56db3350cf5c972b1efc0acdcPaul McLean 927c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean struct pcm_config proxy_config; 928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 9296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Rate */ 9306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->sample_rate == 0) { 931c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile); 932c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean } else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) { 933c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate; 9346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else { 935c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile); 936c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean ret = -EINVAL; 9376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 9387661a484021f6e7c3b219bd21659118eef94e45bEric Laurent 9396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Format */ 9406b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* until the framework supports format conversion, just take what it asks for 9416b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * i.e. AUDIO_FORMAT_PCM_16_BIT */ 9426b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->format == AUDIO_FORMAT_DEFAULT) { 9436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input 9446b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 9456b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 946c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = PCM_FORMAT_S16_LE; 9476b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) { 9486b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input 9496b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 950c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = PCM_FORMAT_S16_LE; 95130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } else { 9526b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* When the framework support other formats, validate here */ 9536b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 954c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.format = PCM_FORMAT_S16_LE; 9556b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ret = -EINVAL; 9566b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 9586b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->channel_mask == AUDIO_CHANNEL_NONE) { 9596b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* just return AUDIO_CHANNEL_IN_STEREO until the framework supports other input 9606b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 9616b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->channel_mask = AUDIO_CHANNEL_IN_STEREO; 962c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 9636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) { 9646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* allow only stereo capture for now */ 9656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->channel_mask = AUDIO_CHANNEL_IN_STEREO; 9666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ret = -EINVAL; 967eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 968c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean // proxy_config.channels = 0; /* don't change */ 969c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_config.channels = profile_get_default_channel_count(in->profile); 970c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 971c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean proxy_prepare(&in->proxy, in->profile, &proxy_config); 972eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 97430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 97530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = NULL; 97630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = 0; 97730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 978eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *stream_in = &in->stream; 979eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 9807661a484021f6e7c3b219bd21659118eef94e45bEric Laurent return ret; 98119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 98219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 98330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) 98419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 98530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 987c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean /* Close the pcm device */ 98830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in_standby(&stream->common); 98930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 99030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(in->conversion_buffer); 99130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 99230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(stream); 99319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 99419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 995c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean/* 996c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean * ADEV Functions 997c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean */ 998c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) 999c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1000c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return 0; 1001c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1002c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1003c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys) 1004c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1005c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return strdup(""); 1006c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1007c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1008c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_init_check(const struct audio_hw_device *dev) 1009c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1010c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return 0; 1011c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1012c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1013c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume) 1014c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1015c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return -ENOSYS; 1016c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1017c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1018c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume) 1019c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1020c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return -ENOSYS; 1021c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1022c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1023c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) 1024c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1025c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return 0; 1026c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1027c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1028c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state) 1029c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1030c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return -ENOSYS; 1031c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1032c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 1033c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLeanstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) 1034c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean{ 1035c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean return -ENOSYS; 1036c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean} 1037c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd) 103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 104319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device) 104419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 1045eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = (struct audio_device *)device; 104619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(device); 1047eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 104819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 104919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 105019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 105130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) 105219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 105319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) 105419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 105519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1056eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = calloc(1, sizeof(struct audio_device)); 105719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!adev) 105819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 105919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1060c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean profile_init(&adev->out_profile, PCM_OUT); 1061c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean profile_init(&adev->in_profile, PCM_IN); 1062c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean 106319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; 106485e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; 1065c88e6ae584a5f7ea65ab6df89e381c2c7bf8e84ePaul McLean adev->hw_device.common.module = (struct hw_module_t *)module; 106619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.close = adev_close; 106719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 106819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.init_check = adev_init_check; 106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_voice_volume = adev_set_voice_volume; 107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_master_volume = adev_set_master_volume; 107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mode = adev_set_mode; 107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mic_mute = adev_set_mic_mute; 107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_mic_mute = adev_get_mic_mute; 107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_parameters = adev_set_parameters; 107519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_parameters = adev_get_parameters; 107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; 107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_output_stream = adev_open_output_stream; 107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_output_stream = adev_close_output_stream; 107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_input_stream = adev_open_input_stream; 108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_input_stream = adev_close_input_stream; 108119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.dump = adev_dump; 108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *device = &adev->hw_device.common; 108419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 108619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 108719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 108819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = { 108919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .open = adev_open, 109019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = { 109319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .common = { 109419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .tag = HARDWARE_MODULE_TAG, 109546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .module_api_version = AUDIO_MODULE_API_VERSION_0_1, 109646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .hal_api_version = HARDWARE_HAL_API_VERSION, 109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .id = AUDIO_HARDWARE_MODULE_ID, 109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .name = "USB audio HW HAL", 109919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .author = "The Android Open Source Project", 110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .methods = &hal_module_methods, 110119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson }, 110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 1103