audio_hal.c revision 6b1c0fef801c9435ed3446d53cc45d1b1f6fd07e
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 39eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* This is the default configuration to hand to The Framework on the initial 40eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream(). Actual device attributes will be used on the subsequent 41eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream() after the card and device number have been set in out_set_parameters() 42eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 43eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_SIZE 1024 44eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_COUNT 4 45eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_SAMPLING_RATE 44100 46eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 47eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_out_config = { 4819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .channels = 2, 49eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .rate = OUT_SAMPLING_RATE, 50eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_size = OUT_PERIOD_SIZE, 51eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_count = OUT_PERIOD_COUNT, 5219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .format = PCM_FORMAT_S16_LE, 5319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 5419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 56eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Input defaults. See comment above. 57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 58eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_SIZE 1024 59eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_COUNT 4 60eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_SAMPLING_RATE 44100 61eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_in_config = { 63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .channels = 2, 64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .rate = IN_SAMPLING_RATE, 65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_size = IN_PERIOD_SIZE, 66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_count = IN_PERIOD_COUNT, 67eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .format = PCM_FORMAT_S16_LE, 68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .start_threshold = 1, 69eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .stop_threshold = (IN_PERIOD_SIZE * IN_PERIOD_COUNT), 70eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}; 71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device { 7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_hw_device hw_device; 7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 7519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* output */ 78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int out_card; 79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int out_device; 80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 81eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* input */ 82eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int in_card; 83eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int in_device; 84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 8519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 8619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 8719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 8819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out { 8919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out stream; 9019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_t lock; /* see note below on mutex acquisition order */ 92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm *pcm; /* state of the stream */ 93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool standby; 94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *dev; /* hardware information */ 96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean void * conversion_buffer; /* any conversions are put into here 98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * they could come from here too if 99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * there was a previous conversion */ 100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean size_t conversion_buffer_size; /* in bytes */ 101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}; 102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Output Configuration Cache 1056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure. 106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic struct pcm_config cached_output_hardware_config; 108eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic bool output_hardware_config_is_cached = false; 109eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 110eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in { 111eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_stream_in stream; 112eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct pcm *pcm; 11519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 11619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *dev; 118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_config hal_pcm_config; 120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1216b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* this is the format the framework thinks it's using. We may need to convert from the actual 1226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * (24-bit, 32-bit?) format to this theoretical (framework, probably 16-bit) 1236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * format in in_read() */ 1246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean enum pcm_format input_framework_format; 1256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 126eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// struct resampler_itfe *resampler; 127eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// struct resampler_buffer_provider buf_provider; 12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 129eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int read_status; 13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // We may need to read more data from the device in order to data reduce to 16bit, 4chan */ 13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * conversion_buffer; /* any conversions are put into here 13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * they could come from here too if 13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * there was a previous conversion */ 13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t conversion_buffer_size; /* in bytes */ 13619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 13719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 138eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Input Configuration Cache 14030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure 14130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * but that will involve changes in The Framework. 14230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 14330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic struct pcm_config cached_input_hardware_config; 14430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic bool input_hardware_config_is_cached = false; 14530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 14630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 147eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Utility 148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions 151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 15330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples. 15430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM24LE samples 155eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * num_in_samples size of input buffer in SAMPLES 15630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff points to the buffer to receive converted PCM16LE LE samples. 15730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 15830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 15930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 16030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed). 16130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: 16230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 163e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module. 16430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 165e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples, 166e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean short * out_buff) 167e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{ 16830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 16930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Move from front to back so that the conversion can be done in-place 17030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * i.e. in_buff == out_buff 17130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 17230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* we need 2 bytes in the output for every 3 bytes in the input */ 17330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned char* dst_ptr = (unsigned char*)out_buff; 17488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn const unsigned char* src_ptr = in_buff; 17530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t src_smpl_index; 17630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 17730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean src_ptr++; /* lowest-(skip)-byte */ 17830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* low-byte */ 17930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* high-byte */ 18030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 18130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 18230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* return number of *bytes* generated: */ 18330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_in_samples * 2; 18430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 18530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 18630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 1876b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples. 1886b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * in_buff points to the buffer of PCM32 samples 1896b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * num_in_samples size of input buffer in SAMPLES 1906b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * out_buff points to the buffer to receive converted PCM16LE LE samples. 1916b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns 1926b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * the number of BYTES of output data. 1936b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 1946b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit). 1956b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE: 1966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 1976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module. 1986b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */ 1996b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff) 2006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{ 2016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 2026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Move from front to back so that the conversion can be done in-place 2036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * i.e. in_buff == out_buff 2046b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */ 2056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 2066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean short * dst_ptr = out_buff; 2076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean const int32_t* src_ptr = in_buff; 2086b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean size_t src_smpl_index; 2096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 2106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *dst_ptr++ = *src_ptr++ >> 16; 2116b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 2126b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 2136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* return number of *bytes* generated: */ 2146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean return num_in_samples * 2; 2156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean} 2166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 2176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean/* 21830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels 21930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N < M). 22030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM16 samples 22130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff_channels Specifies the number of channels in the input buffer. 222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * out_buff points to the buffer to receive converted PCM16 samples. 22330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff_channels Specifies the number of channels in the output buffer. 22430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * num_in_samples size of input buffer in SAMPLES 22530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 22630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 22730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE 22830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * channels > N are filled with silence. 22930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff) 230eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to 231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support 4-channel devices. 232e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module. 233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 23488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzynstatic size_t expand_channels_16(const short* in_buff, int in_buff_chans, 23530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* out_buff, int out_buff_chans, 236e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean size_t num_in_samples) 237e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{ 238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 239eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Move from back to front so that the conversion can be done in-place 240eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * i.e. in_buff == out_buff 24130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans 24230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 24330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans; 24430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 24530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* dst_ptr = out_buff + num_out_samples - 1; 24688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t src_index; 24788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn const short* src_ptr = in_buff + num_in_samples - 1; 24830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_zero_chans = out_buff_chans - in_buff_chans; 24930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { 25030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int dst_offset; 251e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { 25230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr-- = 0; 25330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 254e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (; dst_offset < out_buff_chans; dst_offset++) { 25530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr-- = *src_ptr--; 25630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 25730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 25830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 25930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* return number of *bytes* generated */ 26030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_out_samples * sizeof(short); 26130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 26230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 26330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 26430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels 26530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N > M). 26630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM16 samples 26730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff_channels Specifies the number of channels in the input buffer. 26830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff points to the buffer to receive converted PCM16 samples. 26930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff_channels Specifies the number of channels in the output buffer. 27030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * num_in_samples size of input buffer in SAMPLES 27130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 27230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 27330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE 27430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * channels > N are thrown away. 27530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff) 27630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to 27730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support 4-channel devices. 278e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module. 27930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 28030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t contract_channels_16(short* in_buff, int in_buff_chans, 28130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* out_buff, int out_buff_chans, 282e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean size_t num_in_samples) 283e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{ 28430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 28530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Move from front to back so that the conversion can be done in-place 28630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * i.e. in_buff == out_buff 28730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans 288eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 28930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans; 29030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 29130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_skip_samples = in_buff_chans - out_buff_chans; 29230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 29330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* dst_ptr = out_buff; 29430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* src_ptr = in_buff; 29588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t src_index; 29630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { 29730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int dst_offset; 298e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) { 29930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; 30030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 30130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean src_ptr += num_skip_samples; 302eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 303eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 304eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* return number of *bytes* generated */ 30530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_out_samples * sizeof(short); 306eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 308eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * ALSA Utilities 310eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 311e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO This table and the function that uses it should be moved to a utilities module (probably) */ 312e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* 313e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps bit-positions in a pcm_mask to the corresponding AUDIO_ format string. 314e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */ 315e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic const char * const format_string_map[] = { 316e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_8_BIT", /* 00 - SNDRV_PCM_FORMAT_S8 */ 317e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_8_BIT", /* 01 - SNDRV_PCM_FORMAT_U8 */ 318e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_16_BIT", /* 02 - SNDRV_PCM_FORMAT_S16_LE */ 319e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 03 - SNDRV_PCM_FORMAT_S16_BE */ 320e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 04 - SNDRV_PCM_FORMAT_U16_LE */ 321e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 05 - SNDRV_PCM_FORMAT_U16_BE */ 322e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_24_BIT_PACKED", /* 06 - SNDRV_PCM_FORMAT_S24_LE */ 323e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 07 - SNDRV_PCM_FORMAT_S24_BE */ 324e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 08 - SNDRV_PCM_FORMAT_U24_LE */ 325e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 09 - SNDRV_PCM_FORMAT_U24_BE */ 326e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_32_BIT", /* 10 - SNDRV_PCM_FORMAT_S32_LE */ 327e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 11 - SNDRV_PCM_FORMAT_S32_BE */ 328e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 12 - SNDRV_PCM_FORMAT_U32_LE */ 329e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 13 - SNDRV_PCM_FORMAT_U32_BE */ 330e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_FLOAT", /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */ 331e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */ 332e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */ 333e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */ 334e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */ 335e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */ 336e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 20 - SNDRV_PCM_FORMAT_MU_LAW */ 337e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 21 - SNDRV_PCM_FORMAT_A_LAW */ 338e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */ 339e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 23 - SNDRV_PCM_FORMAT_MPEG */ 340e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 24 - SNDRV_PCM_FORMAT_GSM */ 341e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, NULL, NULL, NULL, NULL, NULL, /* 25 -> 30 (not assigned) */ 342e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 31 - SNDRV_PCM_FORMAT_SPECIAL */ 343e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "AUDIO_FORMAT_PCM_24_BIT_PACKED", /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */ 344e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 33 - SNDRV_PCM_FORMAT_S24_3BE */ 345e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 34 - SNDRV_PCM_FORMAT_U24_3LE */ 346e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 35 - SNDRV_PCM_FORMAT_U24_3BE */ 347e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 36 - SNDRV_PCM_FORMAT_S20_3LE */ 348e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 37 - SNDRV_PCM_FORMAT_S20_3BE */ 349e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 38 - SNDRV_PCM_FORMAT_U20_3LE */ 350e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 39 - SNDRV_PCM_FORMAT_U20_3BE */ 351e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 40 - SNDRV_PCM_FORMAT_S18_3LE */ 352e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 41 - SNDRV_PCM_FORMAT_S18_3BE */ 353e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 42 - SNDRV_PCM_FORMAT_U18_3LE */ 354e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 43 - SNDRV_PCM_FORMAT_U18_3BE */ 355e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 44 - SNDRV_PCM_FORMAT_G723_24 */ 356e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */ 357e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 46 - SNDRV_PCM_FORMAT_G723_40 */ 358e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */ 359e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL, /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */ 360e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean NULL /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */ 361e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}; 362e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 363e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* 364e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Generate string containing a bar ("|") delimited list of AUDIO_ formats specified in 365e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * the mask parameter. 366e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * 367e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */ 368e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic char* get_format_str_for_mask(struct pcm_mask* mask) 369e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{ 370e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean char buffer[256]; 371e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int buffer_size = sizeof(buffer) / sizeof(buffer[0]); 372e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean buffer[0] = '\0'; 373e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 374e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_slots = sizeof(mask->bits) / sizeof(mask->bits[0]); 375e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int bits_per_slot = sizeof(mask->bits[0]) * 8; 376e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 377e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean const char* format_str = NULL; 378e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int table_size = sizeof(format_string_map)/sizeof(format_string_map[0]); 379e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 380e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int slot_index, bit_index, table_index; 381e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index = 0; 382e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_written = 0; 383e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (slot_index = 0; slot_index < num_slots; slot_index++) { 384e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean unsigned bit_mask = 1; 385e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { 386e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if ((mask->bits[slot_index] & bit_mask) != 0) { 387e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean format_str = table_index < table_size 388e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean ? format_string_map[table_index] 389e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean : NULL; 390e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if (format_str != NULL) { 391e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if (num_written != 0) { 392e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean num_written += snprintf(buffer + num_written, 393e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean buffer_size - num_written, "|"); 394e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 395e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean num_written += snprintf(buffer + num_written, buffer_size - num_written, 396e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean "%s", format_str); 397e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 398e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 399e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean bit_mask <<= 1; 400e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index++; 401e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 402e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 403e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 404e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return strdup(buffer); 405e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean} 406e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 407eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 408e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps from bit position in pcm_mask to AUDIO_ format constants. 409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 4106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic audio_format_t const format_value_map[] = { 411e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_PCM_8_BIT, /* 00 - SNDRV_PCM_FORMAT_S8 */ 412e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_PCM_8_BIT, /* 01 - SNDRV_PCM_FORMAT_U8 */ 413e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_PCM_16_BIT, /* 02 - SNDRV_PCM_FORMAT_S16_LE */ 414e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 03 - SNDRV_PCM_FORMAT_S16_BE */ 415e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 04 - SNDRV_PCM_FORMAT_U16_LE */ 416e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 05 - SNDRV_PCM_FORMAT_U16_BE */ 4176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean AUDIO_FORMAT_INVALID, /* 06 - SNDRV_PCM_FORMAT_S24_LE */ 418e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 07 - SNDRV_PCM_FORMAT_S24_BE */ 419e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 08 - SNDRV_PCM_FORMAT_U24_LE */ 420e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 09 - SNDRV_PCM_FORMAT_U24_BE */ 421e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_PCM_32_BIT, /* 10 - SNDRV_PCM_FORMAT_S32_LE */ 422e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 11 - SNDRV_PCM_FORMAT_S32_BE */ 423e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 12 - SNDRV_PCM_FORMAT_U32_LE */ 424e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 13 - SNDRV_PCM_FORMAT_U32_BE */ 425e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_PCM_FLOAT, /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */ 426e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */ 427e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */ 428e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */ 429e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */ 430e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */ 431e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 20 - SNDRV_PCM_FORMAT_MU_LAW */ 432e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 21 - SNDRV_PCM_FORMAT_A_LAW */ 433e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */ 434e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 23 - SNDRV_PCM_FORMAT_MPEG */ 435e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 24 - SNDRV_PCM_FORMAT_GSM */ 436e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 25 -> 30 (not assigned) */ 437e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, 438e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, 439e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, 440e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, 441e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, 442e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 31 - SNDRV_PCM_FORMAT_SPECIAL */ 4436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean AUDIO_FORMAT_PCM_24_BIT_PACKED, /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ 444e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 33 - SNDRV_PCM_FORMAT_S24_3BE */ 445e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 34 - SNDRV_PCM_FORMAT_U24_3LE */ 446e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 35 - SNDRV_PCM_FORMAT_U24_3BE */ 447e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 36 - SNDRV_PCM_FORMAT_S20_3LE */ 448e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 37 - SNDRV_PCM_FORMAT_S20_3BE */ 449e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 38 - SNDRV_PCM_FORMAT_U20_3LE */ 450e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 39 - SNDRV_PCM_FORMAT_U20_3BE */ 451e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 40 - SNDRV_PCM_FORMAT_S18_3LE */ 452e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 41 - SNDRV_PCM_FORMAT_S18_3BE */ 453e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 42 - SNDRV_PCM_FORMAT_U18_3LE */ 454e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 43 - SNDRV_PCM_FORMAT_U18_3BE */ 455e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 44 - SNDRV_PCM_FORMAT_G723_24 */ 456e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */ 457e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 46 - SNDRV_PCM_FORMAT_G723_40 */ 458e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */ 459e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID, /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */ 460e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean AUDIO_FORMAT_INVALID /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */ 461e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}; 462e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 4636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean/* 4646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Returns true if mask indicates support for PCM_16. 4656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */ 4666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic bool mask_has_pcm_16(struct pcm_mask* mask) { 4676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean return (mask->bits[0] & 0x0004) != 0; 4686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean} 4696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 470e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int get_format_for_mask(struct pcm_mask* mask) 47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 472e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]); 473e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int bits_per_slot = sizeof(mask->bits[0]) * 8; 474e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 475e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int table_size = sizeof(format_value_map) / sizeof(format_value_map[0]); 476e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 477e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int slot_index, bit_index, table_index; 478e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index = 0; 479e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_written = 0; 480e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (slot_index = 0; slot_index < num_slots; slot_index++) { 481e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean unsigned bit_mask = 1; 482e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { 483e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if ((mask->bits[slot_index] & bit_mask) != 0) { 484e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* just return the first one */ 485e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return table_index < table_size 486e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean ? format_value_map[table_index] 487e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean : AUDIO_FORMAT_INVALID; 488e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 489e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean bit_mask <<= 1; 490e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index++; 491e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 492e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 493e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 494e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return AUDIO_FORMAT_INVALID; 495e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean} 496e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 497e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* 498e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps from bit position in pcm_mask to AUDIO_ format constants. 499e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */ 500e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int const pcm_format_value_map[] = { 501e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean PCM_FORMAT_S8, /* 00 - SNDRV_PCM_FORMAT_S8 */ 502e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 01 - SNDRV_PCM_FORMAT_U8 */ 503e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean PCM_FORMAT_S16_LE, /* 02 - SNDRV_PCM_FORMAT_S16_LE */ 504e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 03 - SNDRV_PCM_FORMAT_S16_BE */ 505e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 04 - SNDRV_PCM_FORMAT_U16_LE */ 506e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 05 - SNDRV_PCM_FORMAT_U16_BE */ 507e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean PCM_FORMAT_S24_3LE, /* 06 - SNDRV_PCM_FORMAT_S24_LE */ 508e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 07 - SNDRV_PCM_FORMAT_S24_BE */ 509e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 08 - SNDRV_PCM_FORMAT_U24_LE */ 510e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 09 - SNDRV_PCM_FORMAT_U24_BE */ 511e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean PCM_FORMAT_S32_LE, /* 10 - SNDRV_PCM_FORMAT_S32_LE */ 512e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 11 - SNDRV_PCM_FORMAT_S32_BE */ 513e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 12 - SNDRV_PCM_FORMAT_U32_LE */ 514e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 13 - SNDRV_PCM_FORMAT_U32_BE */ 515e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */ 516e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */ 517e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */ 518e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */ 519e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */ 520e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */ 521e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 20 - SNDRV_PCM_FORMAT_MU_LAW */ 522e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 21 - SNDRV_PCM_FORMAT_A_LAW */ 523e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */ 524e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 23 - SNDRV_PCM_FORMAT_MPEG */ 525e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 24 - SNDRV_PCM_FORMAT_GSM */ 526e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 25 -> 30 (not assigned) */ 527e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, 528e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, 529e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, 530e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, 531e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, 532e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 31 - SNDRV_PCM_FORMAT_SPECIAL */ 533e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean PCM_FORMAT_S24_3LE, /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */ 534e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 33 - SNDRV_PCM_FORMAT_S24_3BE */ 535e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 34 - SNDRV_PCM_FORMAT_U24_3LE */ 536e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 35 - SNDRV_PCM_FORMAT_U24_3BE */ 537e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 36 - SNDRV_PCM_FORMAT_S20_3LE */ 538e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 37 - SNDRV_PCM_FORMAT_S20_3BE */ 539e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 38 - SNDRV_PCM_FORMAT_U20_3LE */ 540e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 39 - SNDRV_PCM_FORMAT_U20_3BE */ 541e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 40 - SNDRV_PCM_FORMAT_S18_3LE */ 542e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 41 - SNDRV_PCM_FORMAT_S18_3BE */ 543e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 42 - SNDRV_PCM_FORMAT_U18_3LE */ 544e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 43 - SNDRV_PCM_FORMAT_U18_3BE */ 545e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 44 - SNDRV_PCM_FORMAT_G723_24 */ 546e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */ 547e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 46 - SNDRV_PCM_FORMAT_G723_40 */ 548e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */ 549e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0, /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */ 550e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 0 /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */ 551e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}; 552e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 553e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int get_pcm_format_for_mask(struct pcm_mask* mask) { 554e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]); 555e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int bits_per_slot = sizeof(mask->bits[0]) * 8; 556e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 557e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int table_size = sizeof(pcm_format_value_map) / sizeof(pcm_format_value_map[0]); 558e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 559e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int slot_index, bit_index, table_index; 560e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index = 0; 561e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_written = 0; 562e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (slot_index = 0; slot_index < num_slots; slot_index++) { 563e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean unsigned bit_mask = 1; 564e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { 565e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if ((mask->bits[slot_index] & bit_mask) != 0) { 566e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* just return the first one */ 567e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return table_index < table_size 568e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean ? pcm_format_value_map[table_index] 569e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean : AUDIO_FORMAT_INVALID; 570e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 571e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean bit_mask <<= 1; 572e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean table_index++; 57330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 575e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 576e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return 0; // is this right? 577e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean} 578e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 579e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic void log_pcm_mask(const char* mask_name, struct pcm_mask* mask) { 580e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean char buff[512]; 581e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean char bit_buff[32]; 582e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int buffSize = sizeof(buff)/sizeof(buff[0]); 583e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 584e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean buff[0] = '\0'; 585e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 586e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int num_slots = sizeof(mask->bits) / sizeof(mask->bits[0]); 587e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int bits_per_slot = sizeof(mask->bits[0]) * 8; 588e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 589e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean int slot_index, bit_index; 590e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean strcat(buff, "["); 591e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (slot_index = 0; slot_index < num_slots; slot_index++) { 592e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean unsigned bit_mask = 1; 593e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean for (bit_index = 0; bit_index < bits_per_slot; bit_index++) { 594e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean strcat(buff, (mask->bits[slot_index] & bit_mask) != 0 ? "1" : "0"); 595e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean bit_mask <<= 1; 596e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 597e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean if (slot_index < num_slots - 1) { 598e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean strcat(buff, ","); 599e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 600e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean } 601e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean strcat(buff, "]"); 602e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 603e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean ALOGV("usb:audio_hw - %s mask:%s", mask_name, buff); 604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 60519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 606cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLeanstatic void log_pcm_params(struct pcm_params * alsa_hw_params) { 607cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_SAMPLE_BITS min:%u, max:%u", 608cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS), 609cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS)); 610cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_FRAME_BITS min:%u, max:%u", 611cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_FRAME_BITS), 612cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_FRAME_BITS)); 613e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean log_pcm_mask("PCM_PARAM_FORMAT", pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); 614e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean log_pcm_mask("PCM_PARAM_SUBFORMAT", pcm_params_get_mask(alsa_hw_params, PCM_PARAM_SUBFORMAT)); 615cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_CHANNELS min:%u, max:%u", 616cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), 617cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); 618cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_RATE min:%u, max:%u", 619cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), 620cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); 621cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_TIME min:%u, max:%u", 622cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_TIME), 623cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_TIME)); 624cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_SIZE min:%u, max:%u", 625cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE), 626cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE)); 627cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_BYTES min:%u, max:%u", 628cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_BYTES), 629cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_BYTES)); 630cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_PERIODS min:%u, max:%u", 631cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS), 632cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS)); 633cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_TIME min:%u, max:%u", 634cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_TIME), 635cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_TIME)); 636cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_SIZE min:%u, max:%u", 637cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE), 638cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_SIZE)); 639cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_BYTES min:%u, max:%u", 640cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_BYTES), 641cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_BYTES)); 642cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean ALOGV("usb:audio_hw - PCM_PARAM_TICK_TIME min:%u, max:%u", 643cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_min(alsa_hw_params, PCM_PARAM_TICK_TIME), 644cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean pcm_params_get_max(alsa_hw_params, PCM_PARAM_TICK_TIME)); 645cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean} 646cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean 647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 64833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean * Returns the supplied value rounded up to the next even multiple of 16 64933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean */ 65033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLeanstatic unsigned int round_to_16_mult(unsigned int size) { 65133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean return (size + 15) & 0xFFFFFFF0; 65233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean} 65333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean 654e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO - Evaluate if this value should/can be retrieved from a device-specific property */ 65533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean#define MIN_BUFF_TIME 5 /* milliseconds */ 65633a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean 65733a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean/* 65833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean * Returns the system defined minimum period size based on the supplied sample rate 65933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean */ 66033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLeanstatic unsigned int calc_min_period_size(unsigned int sample_rate) { 66133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean unsigned int period_size = (sample_rate * MIN_BUFF_TIME) / 1000; 66233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean return round_to_16_mult(period_size); 66333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean} 66433a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean 66533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean/* 666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Reads and decodes configuration info from the specified ALSA card/device 667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config) 669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 67030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",card, device, io_type); 67119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (card < 0 || device < 0) { 673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -EINVAL; 674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 67519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type); 677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (alsa_hw_params == NULL) { 678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -EINVAL; 67919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 68019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 681eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * This Logging will be useful when testing new USB devices. 683eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 684cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean /* log_pcm_params(alsa_hw_params); */ 685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 686eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 68833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean config->period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE); 68933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean /* round this up to a multiple of 16 */ 69033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean config->period_size = round_to_16_mult(config->period_size); 69133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean /* make sure it is above a minimum value to minimize jitter */ 69233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean unsigned int min_period_size = calc_min_period_size(config->rate); 69333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean if (config->period_size < min_period_size) { 69433a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean config->period_size = min_period_size; 69533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean } 696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS); 697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 698e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); 69919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 70019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 70119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions 704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/** 706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the 707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream 708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 70919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */ 71119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream) 71219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 713eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return cached_output_hardware_config.rate; 71419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 71519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 71619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) 71719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 71819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 71919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 72019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 72119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream) 72219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 723eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return cached_output_hardware_config.period_size * audio_stream_frame_size(stream); 72419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 72519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 72619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream) 72719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 728eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always Stero for now. We will do *some* conversions in this HAL. 729e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels 730e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean rewrite this to return the ACTUAL channel format */ 73119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return AUDIO_CHANNEL_OUT_STEREO; 73219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 73319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 73419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream) 73519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 736e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean return audio_format_from_pcm_format(cached_output_hardware_config.format); 73719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 73819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 73919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format) 74019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 741e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean cached_output_hardware_config.format = pcm_format_from_audio_format(format); 74219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 74319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 74419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 74519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream) 74619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 74719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 74819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 74919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 75019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 75119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 75219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out->standby) { 75319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pcm_close(out->pcm); 75419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->pcm = NULL; 75519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = true; 75619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 75719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 75819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 75919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->dev->lock); 76019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 76119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 76219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 76319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 76419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd) 76519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 76619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 76719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 76819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 76919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs) 77019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs); 772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 77319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 77419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *adev = out->dev; 77519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct str_parms *parms; 77619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson char value[32]; 777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 77819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int routing = 0; 779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 78019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 78119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson parms = str_parms_create_str(kvpairs); 78219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&adev->lock); 78319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 784eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool recache_device_params = false; 785eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 786eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 787eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->out_card = atoi(value); 788eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 789eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 790eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 791eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 792eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 793eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->out_device = atoi(value); 794eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 795eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 79619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 797eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) { 798eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT, 79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean &cached_output_hardware_config); 800eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean output_hardware_config_is_cached = (ret_value == 0); 801eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 80219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 80319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&adev->lock); 80419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson str_parms_destroy(parms); 80519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 806eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 80719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 80819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 809e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO it seems like both out_get_parameters() and in_get_parameters() 810e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean could be written in terms of a get_device_parameters(io_type) */ 811eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys) 81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 81430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys); 81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 816eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_out *out = (struct stream_out *) stream; 817eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = out->dev; 818eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 81930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (adev->out_card < 0 || adev->out_device < 0) 82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 82130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 822eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean unsigned min, max; 823eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 824eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *query = str_parms_create_str(keys); 825eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *result = str_parms_create(); 826eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 827eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_written = 0; 828eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char buffer[256]; 829eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int buffer_size = sizeof(buffer) / sizeof(buffer[0]); 830eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char* result_str = NULL; 831eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 832eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT); 833eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 834eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // These keys are from hardware/libhardware/include/audio.h 835eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported sample rates 836eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { 837eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so 838eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // if they are different, return a list containing those two values, otherwise just the one. 839eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 840eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE); 84188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn num_written = snprintf(buffer, buffer_size, "%u", min); 842eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (min != max) { 84388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn snprintf(buffer + num_written, buffer_size - num_written, "|%u", max); 844eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 845eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, 846eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean buffer); 847eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES 848eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 849eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported channel counts 850eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { 851eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Similarly for output channels count 852e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* TODO - This is wrong, we need format strings, not numbers (another CL) */ 853eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 854eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 85588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn num_written = snprintf(buffer, buffer_size, "%u", min); 856eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (min != max) { 85788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn snprintf(buffer + num_written, buffer_size - num_written, "|%u", max); 858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer); 860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_CHANNELS 861eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported sample formats 863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { 864e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean char * format_params = 865e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean get_format_str_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT)); 866e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params); 867e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean free(format_params); 868eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_FORMATS 869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean result_str = str_parms_to_str(result); 871eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 872eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // done with these... 873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(query); 874eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(result); 875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 876e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean ALOGV("usb:audio_hw::out out_get_parameters() = %s", result_str); 877e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return result_str; 87919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 88019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 88119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream) 88219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 88330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_out *out = (struct stream_out *) stream; 884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 885e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /*TODO Do we need a term here for the USB latency (as reported in the USB descriptors)? */ 88630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean uint32_t latency = (cached_output_hardware_config.period_size 887e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * cached_output_hardware_config.period_count * 1000) 888e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean / out_get_sample_rate(&stream->common); 889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return latency; 89019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 89119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 89230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right) 89319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 89419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 89519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 89619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */ 898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out) 899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = out->dev; 901eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int return_val = 0; 902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 90330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)", 90430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean adev->out_card, adev->out_device); 905eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config); 907e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean 908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (out->pcm == NULL) { 909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (out->pcm && !pcm_is_ready(out->pcm)) { 913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGE("audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(out->pcm)); 914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pcm_close(out->pcm); 915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) 92219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 92319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int ret; 92419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 92519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 92619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 92719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 92819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (out->standby) { 92919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson ret = start_output_stream(out); 93019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 93119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson goto err; 93219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 93319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = false; 93419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 93519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 93630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Setup conversion buffer 93730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // compute maximum potential buffer size. 93830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // * 2 for stereo -> quad conversion 93930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // * 3/2 for 16bit -> 24 bit conversion 94088e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t required_conversion_buffer_size = (bytes * 3 * 2) / 2; 94130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (required_conversion_buffer_size > out->conversion_buffer_size) { 942e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /* TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 943e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean (and do these conversions themselves) */ 94430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer_size = required_conversion_buffer_size; 94530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size); 94630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 94730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 94888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn const void * write_buff = buffer; 949eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_write_buff_bytes = bytes; 950eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 951eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 952eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Num Channels conversion 953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_device_channels = cached_output_hardware_config.channels; 955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_req_channels = 2; /* always, for now */ 95630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_write_buff_bytes = 95830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean expand_channels_16(write_buff, num_req_channels, 95930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer, num_device_channels, 96030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_write_buff_bytes / sizeof(short)); 961eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean write_buff = out->conversion_buffer; 962eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 963eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 964eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (write_buff != NULL && num_write_buff_bytes != 0) { 965eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pcm_write(out->pcm, write_buff, num_write_buff_bytes); 966eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 96719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 96819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 96919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->dev->lock); 97019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 97119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 97219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 97319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr: 97419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 975f9953b7d52bcf560b15efde807f41cf0903e875dAmit Shekhar pthread_mutex_unlock(&out->dev->lock); 97619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 97719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / 97819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_get_sample_rate(&stream->common)); 97919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 98019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 98119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 98219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 98319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) 98519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 98619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 98719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 98819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 98919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 99019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 99119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 99219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 99319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 99419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 99519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 99619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 99719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 99819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 99930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp) 100019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 100119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 100219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 100319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 100419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev, 100546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 100646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 100746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_output_flags_t flags, 100846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood struct audio_config *config, 100919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out **stream_out) 101019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 101130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X", 1012eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean handle, devices, flags); 1013eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 101419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *adev = (struct audio_device *)dev; 1015eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 101619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out; 101719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 101819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); 101919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out) 102019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 102119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1022eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // setup function pointers 102319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_sample_rate = out_get_sample_rate; 102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_sample_rate = out_set_sample_rate; 102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_buffer_size = out_get_buffer_size; 102619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_channels = out_get_channels; 102719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_format = out_get_format; 102819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_format = out_set_format; 102919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.standby = out_standby; 103019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.dump = out_dump; 103119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_parameters = out_set_parameters; 103219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_parameters = out_get_parameters; 103319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.add_audio_effect = out_add_audio_effect; 103419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.remove_audio_effect = out_remove_audio_effect; 103519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_latency = out_get_latency; 103619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.set_volume = out_set_volume; 103719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.write = out_write; 103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_render_position = out_get_render_position; 103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_next_write_timestamp = out_get_next_write_timestamp; 104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->dev = adev; 104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1043eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (output_hardware_config_is_cached) { 1044eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->sample_rate = cached_output_hardware_config.rate; 104519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1046e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean config->format = audio_format_from_pcm_format(cached_output_hardware_config.format); 104719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1048eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = 1049eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean audio_channel_out_mask_from_count(cached_output_hardware_config.channels); 1050eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) { 1051eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always report STEREO for now. AudioPolicyManagerBase/AudioFlinger dont' understand 1052eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // formats with more channels, so we won't get chosen (say with a 4-channel DAC). 1053e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /*TODO remove this when the above restriction is removed. */ 1054eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 1055eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1056eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } else { 1057eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean cached_output_hardware_config = default_alsa_out_config; 1058eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1059eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->format = out_get_format(&out->stream.common); 1060eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = out_get_channels(&out->stream.common); 1061eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->sample_rate = out_get_sample_rate(&out->stream.common); 1062eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1063eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1064eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 1065eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 1066eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1067eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->standby = true; 106846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood 106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = &out->stream; 107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open: 107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(out); 107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = NULL; 1075eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev, 107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out *stream) 108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 1081eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out adev_close_output_stream()"); 108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1084e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean // Close the pcm device 108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_standby(&stream->common); 1086eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1087eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean free(out->conversion_buffer); 1088eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 1089eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 1090eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(stream); 109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 109319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 109419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) 109519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 109619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 109930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys) 110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 110119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return strdup(""); 110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 110319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 110419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev) 110519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 110619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 110719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 110819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 110919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume) 111019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 111119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 111219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 111319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 111419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume) 111519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 111619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 111719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 111819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 111919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) 112019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 112119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 112219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 112319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 112419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state) 112519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 112619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 112719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 112819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 112919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) 113019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 113119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 113219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 113319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 113419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, 113546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood const struct audio_config *config) 113619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 113719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 113819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 113919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1140eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */ 1141eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream) 1142eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 114330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return cached_input_hardware_config.rate; 1144eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) 1147eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 1149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream) 1152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 115388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn ALOGV("usb: in_get_buffer_size() = %zu", 115430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean cached_input_hardware_config.period_size * audio_stream_frame_size(stream)); 115530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return cached_input_hardware_config.period_size * audio_stream_frame_size(stream); 1156eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1157eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1158eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream) 1159eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 116030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // just report stereo for now 116130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return AUDIO_CHANNEL_IN_STEREO; 1162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream) 1165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 11666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean const struct stream_in * in_stream = (const struct stream_in *)stream; 11676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 11686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ALOGV("in_get_format() = %d -> %d", in_stream->input_framework_format, 11696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean audio_format_from_pcm_format(in_stream->input_framework_format)); 11706b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* return audio_format_from_pcm_format(cached_input_hardware_config.format); */ 11716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean return audio_format_from_pcm_format(in_stream->input_framework_format); 1172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1174eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format) 1175eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 1177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1178eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1179eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream) 1180eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 118130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *) stream; 118230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 118330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 118430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 118530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 118630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (!in->standby) { 118730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pcm_close(in->pcm); 118830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->pcm = NULL; 118930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 119030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 119130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 119230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 119330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->dev->lock); 119430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1197eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd) 1199eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1200eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1201eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1202eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1203eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs) 1204eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 120530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs); 1206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1207eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)stream; 1208eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = in->dev; 1209eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *parms; 1210eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char value[32]; 1211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 1212eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int routing = 0; 1213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 1214eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1215eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean parms = str_parms_create_str(kvpairs); 1216eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_lock(&adev->lock); 1217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 121830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean bool recache_device_params = false; 121930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1220eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Card/Device 1221eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 1222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 1223eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->in_card = atoi(value); 122430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 1225eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1226eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1227eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 1228eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 1229eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->in_device = atoi(value); 123030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 1231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 123330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (recache_device_params && adev->in_card >= 0 && adev->in_device >= 0) { 123430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ret_value = read_alsa_device_config(adev->in_card, adev->in_device, 123530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean PCM_IN, &(cached_input_hardware_config)); 123630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean input_hardware_config_is_cached = (ret_value == 0); 1237eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1239eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_unlock(&adev->lock); 1240eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(parms); 1241eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1242eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 1243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1244eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1245e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO it seems like both out_get_parameters() and in_get_parameters() 1246e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean could be written in terms of a get_device_parameters(io_type) */ 1247eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 124830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys) { 124930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys); 125030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 125130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 125230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_device *adev = in->dev; 125330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 125430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (adev->in_card < 0 || adev->in_device < 0) 125530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 125630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 125730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN); 125830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (alsa_hw_params == NULL) 125930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 126030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 126130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct str_parms *query = str_parms_create_str(keys); 126230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct str_parms *result = str_parms_create(); 1263eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 126430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_written = 0; 126530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean char buffer[256]; 126630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int buffer_size = sizeof(buffer) / sizeof(buffer[0]); 126730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean char* result_str = NULL; 1268eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 126930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned min, max; 127030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 127130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // These keys are from hardware/libhardware/include/audio.h 127230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported sample rates 127330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { 127430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so 127530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // if they are different, return a list containing those two values, otherwise just the one. 127630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 127730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE); 127888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn num_written = snprintf(buffer, buffer_size, "%u", min); 127930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (min != max) { 128088e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn snprintf(buffer + num_written, buffer_size - num_written, "|%u", max); 128130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 128230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer); 128330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES 1284eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 128530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported channel counts 128630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { 128730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Similarly for output channels count 1288e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean // TODO This is wrong, we need format strings, not numbers (another CL) 128930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 129030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 129188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn num_written = snprintf(buffer, buffer_size, "%u", min); 129230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (min != max) { 129388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn snprintf(buffer + num_written, buffer_size - num_written, "|%u", max); 129430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 129530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer); 129630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_CHANNELS 129730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 129830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported sample formats 129930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { 13006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT); 13016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean char * format_params = get_format_str_for_mask(format_mask); 13026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (!mask_has_pcm_16(format_mask)) { 13036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* For now, always support PCM_16 and convert locally if necessary */ 13046b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean char buff[256]; 13056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean snprintf(buff, sizeof(buff), "AUDIO_FORMAT_PCM_16_BIT|%s", format_params); 13066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean free(format_params); 13076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buff); 13086b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else { 13096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params); 131030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 131130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_FORMATS 131230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 131330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean result_str = str_parms_to_str(result); 131430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 131530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // done with these... 131630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_destroy(query); 131730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_destroy(result); 131830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ALOGV("usb:audio_hw::in in_get_parameters() = %s", result_str); 13206b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 132130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return result_str; 1322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1324eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 1325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1327eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 1330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1331eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1332eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1333eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 133430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain) 133530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 1336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1337eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1338eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 133930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */ 134030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int start_input_stream(struct stream_in *in) { 134130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_device *adev = in->dev; 134230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int return_val = 0; 134330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 134430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)", 134530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean adev->in_card, adev->in_device); 134630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 134730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->pcm = pcm_open(adev->in_card, adev->in_device, PCM_IN, &cached_input_hardware_config); 134830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->pcm == NULL) { 134930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGE("usb:audio_hw pcm_open() in->pcm == NULL"); 135030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return -ENOMEM; 135130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 135230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 135330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->pcm && !pcm_is_ready(in->pcm)) { 135430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGE("usb:audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(in->pcm)); 135530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pcm_close(in->pcm); 135630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return -ENOMEM; 135730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 135830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 135930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return 0; 136030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 136130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1362e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */ 136330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) 136430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 136588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn size_t num_read_buff_bytes = 0; 136630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * read_buff = buffer; 136730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * out_buff = buffer; 136830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 136930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in * in = (struct stream_in *) stream; 137030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 137130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 137230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 137330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 137430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->standby) { 137530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (start_input_stream(in) != 0) { 137630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean goto err; 137730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 137830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = false; 137930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 138030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 138130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // OK, we need to figure out how much data to read to be able to output the requested 138230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // number of bytes in the HAL format (16-bit, stereo). 138330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = bytes; 138430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_device_channels = cached_input_hardware_config.channels; 138530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_req_channels = 2; /* always, for now */ 138630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 138730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 1388cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels; 138930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 139030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13916b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Assume (for now) that in->input_framework_format == PCM_FORMAT_S16_LE */ 13927661a484021f6e7c3b219bd21659118eef94e45bEric Laurent if (cached_input_hardware_config.format == PCM_FORMAT_S24_3LE) { 13936b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 24-bit USB device */ 139430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = (3 * num_read_buff_bytes) / 2; 13956b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (cached_input_hardware_config.format == PCM_FORMAT_S32_LE) { 13966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* 32-bit USB device */ 13976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = num_read_buff_bytes * 2; 139830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 139930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 140030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Setup/Realloc the conversion buffer (if necessary). 140130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes != bytes) { 140230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes > in->conversion_buffer_size) { 1403e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 1404e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean (and do these conversions themselves) */ 140530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = num_read_buff_bytes; 140630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size); 140730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 140830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean read_buff = in->conversion_buffer; 140930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 141030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 141130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (pcm_read(in->pcm, read_buff, num_read_buff_bytes) == 0) { 141230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 141330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Do any conversions necessary to send the data in the format specified to/by the HAL 141430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan. 141530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 14166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (cached_input_hardware_config.format != PCM_FORMAT_S16_LE) { 14176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean // we need to convert 141830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 141930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = read_buff; 142030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 142130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 14226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (cached_input_hardware_config.format == PCM_FORMAT_S24_3LE) { 14236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = 14246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff); 14256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (cached_input_hardware_config.format == PCM_FORMAT_S32_LE) { 14266b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean num_read_buff_bytes = 14276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff); 14286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 14296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean else { 14306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean goto err; 14316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 143230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 1433eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 143430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 143530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = buffer; 143630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* Num Channels conversion */ 1437cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean if (num_device_channels < num_req_channels) { 1438cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean num_read_buff_bytes = 1439cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean expand_channels_16(read_buff, num_device_channels, 1440cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean out_buff, num_req_channels, 1441cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean num_read_buff_bytes / sizeof(short)); 1442fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent } else { 1443fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent num_read_buff_bytes = 1444fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent contract_channels_16(read_buff, num_device_channels, 1445fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent out_buff, num_req_channels, 1446fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent num_read_buff_bytes / sizeof(short)); 1447cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean } 144830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 144930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 1450eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 145130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr: 145230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 145330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->dev->lock); 145430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 145530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_read_buff_bytes; 1456eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1457eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 145830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) 145930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 1460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1461eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1462eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 146346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev, 146446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 146546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 146630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_config *config, 146719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_in **stream_in) 146819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 146988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8, 147030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->sample_rate, config->channel_mask, config->format); 1471eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1472eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); 14737661a484021f6e7c3b219bd21659118eef94e45bEric Laurent int ret = 0; 14747661a484021f6e7c3b219bd21659118eef94e45bEric Laurent 1475eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (in == NULL) 1476eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 1477eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1478eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // setup function pointers 1479eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_sample_rate = in_get_sample_rate; 1480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_sample_rate = in_set_sample_rate; 1481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_buffer_size = in_get_buffer_size; 1482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_channels = in_get_channels; 1483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_format = in_get_format; 1484eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_format = in_set_format; 1485eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.standby = in_standby; 1486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.dump = in_dump; 1487eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_parameters = in_set_parameters; 1488eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_parameters = in_get_parameters; 1489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.add_audio_effect = in_add_audio_effect; 1490eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.remove_audio_effect = in_remove_audio_effect; 1491eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1492eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.set_gain = in_set_gain; 1493eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.read = in_read; 1494eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.get_input_frames_lost = in_get_input_frames_lost; 1495eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 14966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean in->input_framework_format = PCM_FORMAT_S16_LE; 14976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean 149830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->dev = (struct audio_device *)dev; 1499eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 15006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (!input_hardware_config_is_cached) { 15016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean // just return defaults until we can actually query the device. 15026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean cached_input_hardware_config = default_alsa_in_config; 15036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 1504eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 15056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Rate */ 15066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* TODO Check that the requested rate is valid for the connected device */ 15076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->sample_rate == 0) { 15087661a484021f6e7c3b219bd21659118eef94e45bEric Laurent config->sample_rate = cached_input_hardware_config.rate; 15096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else { 15106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean cached_input_hardware_config.rate = config->sample_rate; 15116b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 15127661a484021f6e7c3b219bd21659118eef94e45bEric Laurent 15136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Format */ 15146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* until the framework supports format conversion, just take what it asks for 15156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * i.e. AUDIO_FORMAT_PCM_16_BIT */ 15166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* config->format = audio_format_from_pcm_format(cached_input_hardware_config.format); */ 15176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->format == AUDIO_FORMAT_DEFAULT) { 15186b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input 15196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 15206b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 15216b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) { 15226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input 15236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 152430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } else { 15256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* When the framework support other formats, validate here */ 15266b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 15276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ret = -EINVAL; 15286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } 1529eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 15306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* don't change the cached_input_hardware_config, we will open it as what it is and 15316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * convert as necessary */ 15326b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean if (config->channel_mask == AUDIO_CHANNEL_NONE) { 15336b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* just return AUDIO_CHANNEL_IN_STEREO until the framework supports other input 15346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * formats */ 15356b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->channel_mask = AUDIO_CHANNEL_IN_STEREO; 15366b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean } else if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) { 15376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean /* allow only stereo capture for now */ 15386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean config->channel_mask = AUDIO_CHANNEL_IN_STEREO; 15396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean ret = -EINVAL; 1540eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1541eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 154230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 154330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 154430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = NULL; 154530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = 0; 154630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1547eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *stream_in = &in->stream; 1548eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 15497661a484021f6e7c3b219bd21659118eef94e45bEric Laurent return ret; 155019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 155119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 155230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) 155319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 155430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 155530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1556e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean // Close the pcm device 155730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in_standby(&stream->common); 155830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 155930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(in->conversion_buffer); 156030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 156130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(stream); 156219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 156319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 156419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd) 156519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 156619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 156719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 156819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 156919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device) 157019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 1571eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = (struct audio_device *)device; 157219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(device); 1573eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean output_hardware_config_is_cached = false; 157530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean input_hardware_config_is_cached = false; 1576eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 157719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 157819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 157919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 158030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) 158119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 158219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) 158319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 158419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1585eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = calloc(1, sizeof(struct audio_device)); 158619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!adev) 158719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 158819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 158919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; 159085e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; 159119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.module = (struct hw_module_t *) module; 159219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.close = adev_close; 159319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 159419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.init_check = adev_init_check; 159519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_voice_volume = adev_set_voice_volume; 159619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_master_volume = adev_set_master_volume; 159719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mode = adev_set_mode; 159819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mic_mute = adev_set_mic_mute; 159919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_mic_mute = adev_get_mic_mute; 160019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_parameters = adev_set_parameters; 160119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_parameters = adev_get_parameters; 160219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; 160319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_output_stream = adev_open_output_stream; 160419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_output_stream = adev_close_output_stream; 160519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_input_stream = adev_open_input_stream; 160619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_input_stream = adev_close_input_stream; 160719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.dump = adev_dump; 160819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 160919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *device = &adev->hw_device.common; 161019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 161119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 161219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 161319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 161419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = { 161519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .open = adev_open, 161619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 161719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 161819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = { 161919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .common = { 162019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .tag = HARDWARE_MODULE_TAG, 162146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .module_api_version = AUDIO_MODULE_API_VERSION_0_1, 162246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .hal_api_version = HARDWARE_HAL_API_VERSION, 162319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .id = AUDIO_HARDWARE_MODULE_ID, 162419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .name = "USB audio HW HAL", 162519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .author = "The Android Open Source Project", 162619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .methods = &hal_module_methods, 162719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson }, 162819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 1629