audio_hal.c revision 30f4185da772fcc679db35e01148eca6eeafe15f
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" 1830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* #define LOG_NDEBUG 0 */ 1919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 2019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <errno.h> 2119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <pthread.h> 2219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdint.h> 2319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <sys/time.h> 2419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdlib.h> 2519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 2619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/log.h> 2719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/str_parms.h> 2819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/properties.h> 2919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 3019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/hardware.h> 3119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <system/audio.h> 3219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/audio.h> 3319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 3419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <tinyalsa/asoundlib.h> 3519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 36eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* This is the default configuration to hand to The Framework on the initial 37eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream(). Actual device attributes will be used on the subsequent 38eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream() after the card and device number have been set in out_set_parameters() 39eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 40eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_SIZE 1024 41eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_COUNT 4 42eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_SAMPLING_RATE 44100 43eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 44eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_out_config = { 4519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .channels = 2, 46eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .rate = OUT_SAMPLING_RATE, 47eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_size = OUT_PERIOD_SIZE, 48eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_count = OUT_PERIOD_COUNT, 4919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .format = PCM_FORMAT_S16_LE, 5019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 5119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 52eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 53eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Input defaults. See comment above. 54eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_SIZE 1024 56eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_COUNT 4 57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_SAMPLING_RATE 44100 58eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 59eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_in_config = { 60eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .channels = 2, 61eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .rate = IN_SAMPLING_RATE, 62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_size = IN_PERIOD_SIZE, 63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .period_count = IN_PERIOD_COUNT, 64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .format = PCM_FORMAT_S16_LE, 65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .start_threshold = 1, 66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean .stop_threshold = (IN_PERIOD_SIZE * IN_PERIOD_COUNT), 67eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}; 68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 6919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device { 7019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_hw_device hw_device; 7119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 73eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 74eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* output */ 75eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int out_card; 76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int out_device; 77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* input */ 79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int in_card; 80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int in_device; 81eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 8219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 8319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 8419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 8519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out { 8619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out stream; 8719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 88eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_t lock; /* see note below on mutex acquisition order */ 89eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm *pcm; /* state of the stream */ 90eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool standby; 91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *dev; /* hardware information */ 93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean void * conversion_buffer; /* any conversions are put into here 95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * they could come from here too if 96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * there was a previous conversion */ 97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean size_t conversion_buffer_size; /* in bytes */ 98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}; 99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Output Configuration Cache 10230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure 103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * but that will involve changes in The Framework. 104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 105eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic struct pcm_config cached_output_hardware_config; 106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic bool output_hardware_config_is_cached = false; 107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 108eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in { 109eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_stream_in stream; 110eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 11119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_t lock; /* see note below on mutex acquisition order */ 11219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct pcm *pcm; 11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson bool standby; 11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 11519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *dev; 116eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 117eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_config hal_pcm_config; 118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// struct resampler_itfe *resampler; 120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// struct resampler_buffer_provider buf_provider; 12130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 122eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int read_status; 12330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 12430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // We may need to read more data from the device in order to data reduce to 16bit, 4chan */ 12530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * conversion_buffer; /* any conversions are put into here 12630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * they could come from here too if 12730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * there was a previous conversion */ 12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t conversion_buffer_size; /* in bytes */ 12919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 13019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 131eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Input Configuration Cache 13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure 13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * but that will involve changes in The Framework. 13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 13630f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic struct pcm_config cached_input_hardware_config; 13730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic bool input_hardware_config_is_cached = false; 13830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 140eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Utility 141eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 142eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 143eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Translates from ALSA format ID to ANDROID_AUDIO_CORE format ID 144eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * (see master/system/core/include/core/audio.h) 145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean) Replace with audio_format_from_pcm_format() (in hardware/audio_alsaops.h). 146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * post-integration. 14719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */ 148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t alsa_to_fw_format_id(int alsa_fmt_id) 149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean switch (alsa_fmt_id) { 151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S8: 152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return AUDIO_FORMAT_PCM_8_BIT; 15319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 154eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S24_3LE: 155eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean) make sure this is the 'right' sort of 24-bit 156eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return AUDIO_FORMAT_PCM_8_24_BIT; 15719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 158eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S32_LE: 159eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S24_LE: 160eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return AUDIO_FORMAT_PCM_32_BIT; 161eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return AUDIO_FORMAT_PCM_16_BIT; 164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 166eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 167eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions 168eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 169eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 170eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Convert a buffer of PCM16LE samples to packed (3-byte) PCM24LE samples. 171eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * in_buff points to the buffer of PCM16 samples 172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * num_in_samples size of input buffer in SAMPLES 173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * out_buff points to the buffer to receive converted PCM24 LE samples. 17430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 17530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support PCM24_3LE (24-bit, packed). 17830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: 17930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We're just filling the low-order byte of the PCM24LE samples with 0. 18030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 181eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module. 182eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 18330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t convert_16_to_24_3(short * in_buff, size_t num_in_samples, unsigned char * out_buff) { 184eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 185eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Move from back to front so that the conversion can be done in-place 186eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * i.e. in_buff == out_buff 187eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 188eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int in_buff_size_in_bytes = num_in_samples * 2; 189eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* we need 3 bytes in the output for every 2 bytes in the input */ 190eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int out_buff_size_in_bytes = ((3 * in_buff_size_in_bytes) / 2); 191eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean unsigned char* dst_ptr = out_buff + out_buff_size_in_bytes - 1; 19230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t src_smpl_index; 193eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean unsigned char* src_ptr = ((unsigned char *)in_buff) + in_buff_size_in_bytes - 1; 194eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *dst_ptr-- = *src_ptr--; /* hi-byte */ 196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *dst_ptr-- = *src_ptr--; /* low-byte */ 19730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /*TODO(pmclean) - we might want to consider dithering the lowest byte. */ 198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *dst_ptr-- = 0; /* zero-byte */ 199eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 200eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 201eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* return number of *bytes* generated */ 202eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return out_buff_size_in_bytes; 203eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 204eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 205eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 20630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples. 20730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM24LE samples 208eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * num_in_samples size of input buffer in SAMPLES 20930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff points to the buffer to receive converted PCM16LE LE samples. 21030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 21130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 21230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to 21330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed). 21430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: 21530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We're just filling the low-order byte of the PCM24LE samples with 0. 21630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff). 21730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * TODO(pmclean, hung) Move this to a utilities module. 21830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 21930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t convert_24_3_to_16(unsigned char * in_buff, size_t num_in_samples, short * out_buff) { 22030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 22130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Move from front to back so that the conversion can be done in-place 22230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * i.e. in_buff == out_buff 22330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 22430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* we need 2 bytes in the output for every 3 bytes in the input */ 22530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned char* dst_ptr = (unsigned char*)out_buff; 22630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned char* src_ptr = in_buff; 22730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t src_smpl_index; 22830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) { 22930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean src_ptr++; /* lowest-(skip)-byte */ 23030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* low-byte */ 23130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; /* high-byte */ 23230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 23330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 23430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* return number of *bytes* generated: */ 23530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_in_samples * 2; 23630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 23730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 23830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 23930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels 24030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N < M). 24130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM16 samples 24230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff_channels Specifies the number of channels in the input buffer. 243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * out_buff points to the buffer to receive converted PCM16 samples. 24430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff_channels Specifies the number of channels in the output buffer. 24530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * num_in_samples size of input buffer in SAMPLES 24630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 24730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 24830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE 24930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * channels > N are filled with silence. 25030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff) 251eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to 252eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support 4-channel devices. 253eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module. 254eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 25530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t expand_channels_16(short* in_buff, int in_buff_chans, 25630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* out_buff, int out_buff_chans, 25730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t num_in_samples) { 258eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 259eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Move from back to front so that the conversion can be done in-place 260eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * i.e. in_buff == out_buff 26130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans 26230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 26330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans; 26430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 26530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* dst_ptr = out_buff + num_out_samples - 1; 26630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int src_index; 26730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* src_ptr = in_buff + num_in_samples - 1; 26830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_zero_chans = out_buff_chans - in_buff_chans; 26930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { 27030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int dst_offset; 27130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for(dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) { 27230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr-- = 0; 27330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 27430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for(; dst_offset < out_buff_chans; dst_offset++) { 27530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr-- = *src_ptr--; 27630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 27730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 27830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 27930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* return number of *bytes* generated */ 28030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_out_samples * sizeof(short); 28130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 28230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 28330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* 28430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels 28530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N > M). 28630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff points to the buffer of PCM16 samples 28730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * in_buff_channels Specifies the number of channels in the input buffer. 28830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff points to the buffer to receive converted PCM16 samples. 28930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * out_buff_channels Specifies the number of channels in the output buffer. 29030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * num_in_samples size of input buffer in SAMPLES 29130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns 29230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * the number of BYTES of output data. 29330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE 29430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * channels > N are thrown away. 29530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * This conversion is safe to do in-place (in_buff == out_buff) 29630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to 29730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support 4-channel devices. 29830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * TODO(pmclean, hung) Move this to a utilities module. 29930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 30030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t contract_channels_16(short* in_buff, int in_buff_chans, 30130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* out_buff, int out_buff_chans, 30230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean size_t num_in_samples) { 30330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 30430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Move from front to back so that the conversion can be done in-place 30530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * i.e. in_buff == out_buff 30630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans 307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 30830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans; 30930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 31030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_skip_samples = in_buff_chans - out_buff_chans; 31130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 31230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* dst_ptr = out_buff; 31330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean short* src_ptr = in_buff; 314eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int src_index; 31530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) { 31630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int dst_offset; 31730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean for(dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) { 31830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *dst_ptr++ = *src_ptr++; 31930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 32030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean src_ptr += num_skip_samples; 321eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* return number of *bytes* generated */ 32430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_out_samples * sizeof(short); 325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 327eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * ALSA Utilities 329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 331eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * gets the ALSA bit-format flag from a bits-per-sample value. 332eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * TODO(pmclean, hung) Move this to a utilities module. 333eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 334eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int bits_to_alsa_format(int bits_per_sample, int default_format) 33519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean enum pcm_format format; 337eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean for (format = PCM_FORMAT_S16_LE; format < PCM_FORMAT_MAX; format++) { 338eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (pcm_format_to_bits(format) == bits_per_sample) { 33930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return format; 34030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 341eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 342eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return default_format; 343eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 34419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 345eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 346eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Reads and decodes configuration info from the specified ALSA card/device 347eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 348eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config) 349eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 35030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",card, device, io_type); 35119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 352eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (card < 0 || device < 0) { 353eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -EINVAL; 354eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 35519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 356eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type); 357eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (alsa_hw_params == NULL) { 358eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -EINVAL; 35919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 36019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 361eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 362eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * This Logging will be useful when testing new USB devices. 363eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 364eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_SAMPLE_BITS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS)); */ 365eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_FRAME_BITS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_FRAME_BITS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_FRAME_BITS)); */ 366eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_CHANNELS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS)); */ 367eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_RATE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE)); */ 368eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_TIME)); */ 369eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_SIZE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE)); */ 370eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_BYTES min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_BYTES), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_BYTES)); */ 371eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_PERIODS min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS), pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS)); */ 372eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_TIME)); */ 373eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_SIZE min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_SIZE)); */ 374eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_BYTES min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_BYTES), pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_BYTES)); */ 375eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* ALOGV("usb:audio_hw - PCM_PARAM_TICK_TIME min:%d, max:%d", pcm_params_get_min(alsa_hw_params, PCM_PARAM_TICK_TIME), pcm_params_get_max(alsa_hw_params, PCM_PARAM_TICK_TIME)); */ 376eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 377eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 378eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 379eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->period_size = pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS); 380eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS); 381eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 382eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int bits_per_sample = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS); 383eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->format = bits_to_alsa_format(bits_per_sample, PCM_FORMAT_S16_LE); 384eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 38519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 38619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 38719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 388eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* 389eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions 390eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 391eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/** 392eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the 393eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream 394eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 39519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 396eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */ 39719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream) 39819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 399eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return cached_output_hardware_config.rate; 40019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 40119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 40219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) 40319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 40419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 40519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 40619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 40719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream) 40819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return cached_output_hardware_config.period_size * audio_stream_frame_size(stream); 41019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 41119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 41219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream) 41319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 414eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always Stero for now. We will do *some* conversions in this HAL. 415eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary channels 416eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // rewrite this to return the ACTUAL channel format 41719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return AUDIO_CHANNEL_OUT_STEREO; 41819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 41919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 42019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream) 42119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 422eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always return 16-bit PCM. We will do *some* conversions in this HAL. 423eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // TODO(pmclean) When AudioPolicyManager & AudioFlinger supports arbitrary PCM formats 424eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // rewrite this to return the ACTUAL data format 42519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return AUDIO_FORMAT_PCM_16_BIT; 42619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 42719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 42819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format) 42919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 43019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 43119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 43219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 43319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream) 43419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 43519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 43619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 43719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 43819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 43919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 44019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out->standby) { 44119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pcm_close(out->pcm); 44219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->pcm = NULL; 44319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = true; 44419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 44519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 44619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 44719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->dev->lock); 44819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 44919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 45019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 45119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 45219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd) 45319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 45419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 45519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 45619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 45719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs) 45819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 459eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs); 460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 46119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 46219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *adev = out->dev; 46319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct str_parms *parms; 46419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson char value[32]; 465eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 46619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int routing = 0; 467eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 46819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 46919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson parms = str_parms_create_str(kvpairs); 47019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&adev->lock); 47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 472eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean bool recache_device_params = false; 473eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 474eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 475eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->out_card = atoi(value); 476eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 477eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 478eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 479eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->out_device = atoi(value); 482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean recache_device_params = true; 483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 48419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 485eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) { 486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT, 48730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean &cached_output_hardware_config); 488eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean output_hardware_config_is_cached = (ret_value == 0); 489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 49019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 49119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&adev->lock); 49219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson str_parms_destroy(parms); 49319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 494eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 49519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 49619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 497eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters() 498eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type) 499eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 50030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys) 50130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 50230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys); 50330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 504eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_out *out = (struct stream_out *) stream; 505eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = out->dev; 506eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 50730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (adev->out_card < 0 || adev->out_device < 0) 50830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 50930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 510eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean unsigned min, max; 511eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 512eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *query = str_parms_create_str(keys); 513eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *result = str_parms_create(); 514eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 515eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_written = 0; 516eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char buffer[256]; 517eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int buffer_size = sizeof(buffer) / sizeof(buffer[0]); 518eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char* result_str = NULL; 519eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 520eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT); 521eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 522eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // These keys are from hardware/libhardware/include/audio.h 523eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported sample rates 524eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { 525eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so 526eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // if they are different, return a list containing those two values, otherwise just the one. 527eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 528eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE); 529eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 530eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (min != max) { 53130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 532eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 533eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, 534eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean buffer); 535eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES 536eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 537eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported channel counts 538eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { 539eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Similarly for output channels count 540eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 541eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 542eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 543eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (min != max) { 544eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 545eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 546eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer); 547eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_CHANNELS 548eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 549eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // supported sample formats 550eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { 551eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Similarly for output channels count 552eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean): this is wrong. 553eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS); 554eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS); 555eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 556eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (min != max) { 557eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 558eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 559eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer); 560eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } // AUDIO_PARAMETER_STREAM_SUP_FORMATS 561eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 562eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean result_str = str_parms_to_str(result); 563eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 564eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // done with these... 565eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(query); 566eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(result); 567eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 568eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return result_str; 56919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 57019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 57119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream) 57219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 57330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_out *out = (struct stream_out *) stream; 574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 575eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean): Do we need a term here for the USB latency 576eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // (as reported in the USB descriptors)? 57730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean uint32_t latency = (cached_output_hardware_config.period_size 57830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * cached_output_hardware_config.period_count * 1000) / out_get_sample_rate(&stream->common); 579eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return latency; 58019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 58119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 58230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right) 58319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 58419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 58519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 58619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 587eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */ 588eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out) 589eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 590eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = out->dev; 591eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int return_val = 0; 592eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 59330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)", 59430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean adev->out_card, adev->out_device); 595eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 596eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config); 597eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (out->pcm == NULL) { 598eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 599eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 600eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 601eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (out->pcm && !pcm_is_ready(out->pcm)) { 602eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGE("audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(out->pcm)); 603eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pcm_close(out->pcm); 604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 605eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 606eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 607eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 608eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 609eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 610eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) 61119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 61219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson int ret; 61319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 61419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 61519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->dev->lock); 61619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_lock(&out->lock); 61719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (out->standby) { 61819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson ret = start_output_stream(out); 61919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 62019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson goto err; 62119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 62219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->standby = false; 62319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 62419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 62530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Setup conversion buffer 62630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // compute maximum potential buffer size. 62730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // * 2 for stereo -> quad conversion 62830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // * 3/2 for 16bit -> 24 bit conversion 62930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int required_conversion_buffer_size = (bytes * 3 * 2) / 2; 63030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (required_conversion_buffer_size > out->conversion_buffer_size) { 63130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean) - remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 63230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // (and do these conversions themselves) 63330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer_size = required_conversion_buffer_size; 63430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size); 63530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 63630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 637eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean void * write_buff = buffer; 638eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_write_buff_bytes = bytes; 639eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 640eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 641eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Num Channels conversion 642eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 643eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_device_channels = cached_output_hardware_config.channels; 644eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int num_req_channels = 2; /* always, for now */ 64530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 646eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean num_write_buff_bytes = 64730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean expand_channels_16(write_buff, num_req_channels, 64830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer, num_device_channels, 64930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_write_buff_bytes / sizeof(short)); 650eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean write_buff = out->conversion_buffer; 651eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 652eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 653eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean /* 654eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * 16 vs 24-bit logic here 655eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */ 656eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean switch (cached_output_hardware_config.format) { 657eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S16_LE: 658eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // the output format is the same as the input format, so just write it out 659eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean break; 660eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 661eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean case PCM_FORMAT_S24_3LE: 662eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // 16-bit LE2 - 24-bit LE3 66330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_write_buff_bytes = convert_16_to_24_3(write_buff, 66430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_write_buff_bytes / sizeof(short), 66530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out->conversion_buffer); 666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean write_buff = out->conversion_buffer; 667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean break; 668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean default: 670eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // hmmmmm..... 671eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:Unknown Format!!!"); 672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean break; 673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 675eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (write_buff != NULL && num_write_buff_bytes != 0) { 676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pcm_write(out->pcm, write_buff, num_write_buff_bytes); 677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 67819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 67919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 68019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->dev->lock); 68119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 68219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 68319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 68419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr: 68519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson pthread_mutex_unlock(&out->lock); 686f9953b7d52bcf560b15efde807f41cf0903e875dAmit Shekhar pthread_mutex_unlock(&out->dev->lock); 68719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (ret != 0) { 68819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / 68919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_get_sample_rate(&stream->common)); 69019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson } 69119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 69219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return bytes; 69319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 69419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 69530f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames) 69619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 69719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 69819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 69919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 70019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 70119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 70219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 70319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 70419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 70519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 70619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 70719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 70819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 70919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 71030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp) 71119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 71219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 71319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 71419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 71519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev, 71646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 71746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 71846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_output_flags_t flags, 71946a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood struct audio_config *config, 72019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out **stream_out) 72119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 72230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X", 723eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean handle, devices, flags); 724eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 72519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_device *adev = (struct audio_device *)dev; 726eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 72719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out; 72819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 72919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); 73019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!out) 73119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 73219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 733eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // setup function pointers 73419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_sample_rate = out_get_sample_rate; 73519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_sample_rate = out_set_sample_rate; 73619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_buffer_size = out_get_buffer_size; 73719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_channels = out_get_channels; 73819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_format = out_get_format; 73919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_format = out_set_format; 74019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.standby = out_standby; 74119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.dump = out_dump; 74219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.set_parameters = out_set_parameters; 74319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.get_parameters = out_get_parameters; 74419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.add_audio_effect = out_add_audio_effect; 74519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.common.remove_audio_effect = out_remove_audio_effect; 74619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_latency = out_get_latency; 74719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.set_volume = out_set_volume; 74819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.write = out_write; 74919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_render_position = out_get_render_position; 75019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->stream.get_next_write_timestamp = out_get_next_write_timestamp; 75119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 75219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out->dev = adev; 75319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 754eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (output_hardware_config_is_cached) { 755eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->sample_rate = cached_output_hardware_config.rate; 75619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 757eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->format = alsa_to_fw_format_id(cached_output_hardware_config.format); 758eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (config->format != AUDIO_FORMAT_PCM_16_BIT) { 759eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always report PCM16 for now. AudioPolicyManagerBase/AudioFlinger dont' understand 760eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // formats with more other format, so we won't get chosen (say with a 24bit DAC). 761eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean) remove this when the above restriction is removed. 762eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 763eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 76419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 765eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = 766eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean audio_channel_out_mask_from_count(cached_output_hardware_config.channels); 767eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) { 768eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Always report STEREO for now. AudioPolicyManagerBase/AudioFlinger dont' understand 769eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // formats with more channels, so we won't get chosen (say with a 4-channel DAC). 770eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean) remove this when the above restriction is removed. 771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 773eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } else { 774eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean cached_output_hardware_config = default_alsa_out_config; 775eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 776eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->format = out_get_format(&out->stream.common); 777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->channel_mask = out_get_channels(&out->stream.common); 778eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean config->sample_rate = out_get_sample_rate(&out->stream.common); 779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 780eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 781eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 782eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 783eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 784eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->standby = true; 78546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood 78619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = &out->stream; 78719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 78819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 78919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open: 79019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(out); 79119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *stream_out = NULL; 792eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 79319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 79419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 79519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev, 79619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_out *stream) 79719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 798eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean ALOGV("usb:audio_hw::out adev_close_output_stream()"); 79919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct stream_out *out = (struct stream_out *)stream; 80019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 801eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean //TODO(pmclean) why are we doing this when stream get's freed at the end 802eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // because it closes the pcm device 80319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson out_standby(&stream->common); 804eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 805eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean free(out->conversion_buffer); 806eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer = NULL; 807eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean out->conversion_buffer_size = 0; 808eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 80919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(stream); 81019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 81119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 81219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) 81319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 81419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 81519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 81619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 81730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys) 81819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 81919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return strdup(""); 82019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 82119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 82219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev) 82319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 82419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 82519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 82619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 82719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume) 82819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 82919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 83019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 83119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 83219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume) 83319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 83419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 83519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 83619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 83719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) 83819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 83919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 84019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 84119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 84219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state) 84319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 84419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 84519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 84619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 84719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) 84819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 84919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOSYS; 85019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 85119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 85219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, 85346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood const struct audio_config *config) 85419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 85519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 85619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 85719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */ 859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream) 860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 86130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return cached_input_hardware_config.rate; 862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 864eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) 865eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 866eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 867eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 868eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream) 870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 87130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb: in_get_buffer_size() = %d", 87230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean cached_input_hardware_config.period_size * audio_stream_frame_size(stream)); 87330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return cached_input_hardware_config.period_size * audio_stream_frame_size(stream); 87430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 876eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 877eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream) 878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 87930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // just report stereo for now 88030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return AUDIO_CHANNEL_IN_STEREO; 881eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 882eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 883eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream) 884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 885eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // just report 16-bit, pcm for now. 886eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return AUDIO_FORMAT_PCM_16_BIT; 887eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 888eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format) 890eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 891eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOSYS; 892eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 893eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 894eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream) 895eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 89630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *) stream; 89730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 89830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 89930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 90030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 90130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (!in->standby) { 90230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pcm_close(in->pcm); 90330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->pcm = NULL; 90430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 90530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 90630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 90730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 90830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->dev->lock); 90930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd) 914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs) 919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 92030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs); 921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 922eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)stream; 923eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = in->dev; 924eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct str_parms *parms; 925eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean char value[32]; 926eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int param_val; 927eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int routing = 0; 928eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean int ret_value = 0; 929eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 930eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean parms = str_parms_create_str(kvpairs); 931eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_lock(&adev->lock); 932eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 93330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean bool recache_device_params = false; 93430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 935eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // Card/Device 936eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "card", value, sizeof(value)); 937eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 938eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->in_card = atoi(value); 93930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 940eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 941eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 942eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean param_val = str_parms_get_str(parms, "device", value, sizeof(value)); 943eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (param_val >= 0) { 944eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean adev->in_device = atoi(value); 94530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean recache_device_params = true; 946eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 947eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 94830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (recache_device_params && adev->in_card >= 0 && adev->in_device >= 0) { 94930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ret_value = read_alsa_device_config(adev->in_card, adev->in_device, 95030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean PCM_IN, &(cached_input_hardware_config)); 95130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean input_hardware_config_is_cached = (ret_value == 0); 952eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean pthread_mutex_unlock(&adev->lock); 955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean str_parms_destroy(parms); 956eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return ret_value; 958eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 959eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 960eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//TODO(pmclean) it seems like both out_get_parameters() and in_get_parameters() 961eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean// could be written in terms of a get_device_parameters(io_type) 962eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 96330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys) { 96430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys); 96530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 96630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 96730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_device *adev = in->dev; 96830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 96930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (adev->in_card < 0 || adev->in_device < 0) 97030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 97130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 97230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN); 97330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (alsa_hw_params == NULL) 97430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return strdup(""); 97530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 97630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct str_parms *query = str_parms_create_str(keys); 97730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct str_parms *result = str_parms_create(); 978eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 97930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_written = 0; 98030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean char buffer[256]; 98130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int buffer_size = sizeof(buffer) / sizeof(buffer[0]); 98230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean char* result_str = NULL; 983eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean unsigned min, max; 98530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 98630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // These keys are from hardware/libhardware/include/audio.h 98730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported sample rates 98830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { 98930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so 99030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // if they are different, return a list containing those two values, otherwise just the one. 99130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE); 99230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE); 99330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 99430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (min != max) { 99530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 99630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 99730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer); 99830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES 999eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 100030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported channel counts 100130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { 100230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Similarly for output channels count 100330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS); 100430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS); 100530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 100630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (min != max) { 100730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 100830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 100930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer); 101030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_CHANNELS 101130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 101230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // supported sample formats 101330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { 101430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean): this is wrong. 101530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS); 101630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS); 101730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_written = snprintf(buffer, buffer_size, "%d", min); 101830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (min != max) { 101930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean snprintf(buffer + num_written, buffer_size - num_written, "|%d", max); 102030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 102130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buffer); 102230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } // AUDIO_PARAMETER_STREAM_SUP_FORMATS 102330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 102430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean result_str = str_parms_to_str(result); 102530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 102630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // done with these... 102730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_destroy(query); 102830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean str_parms_destroy(result); 102930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 103030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return result_str; 1031eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1032eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1033eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 1034eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1035eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1036eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1037eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1038eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) 1039eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{ 1040eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1041eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1042eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 104330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain) 104430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 1045eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1046eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1047eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 104830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */ 104930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int start_input_stream(struct stream_in *in) { 105030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_device *adev = in->dev; 105130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int return_val = 0; 105230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 105330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)", 105430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean adev->in_card, adev->in_device); 105530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 105630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->pcm = pcm_open(adev->in_card, adev->in_device, PCM_IN, &cached_input_hardware_config); 105730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->pcm == NULL) { 105830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGE("usb:audio_hw pcm_open() in->pcm == NULL"); 105930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return -ENOMEM; 106030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 106130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 106230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->pcm && !pcm_is_ready(in->pcm)) { 106330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGE("usb:audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(in->pcm)); 106430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pcm_close(in->pcm); 106530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return -ENOMEM; 106630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 106730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 106830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return 0; 106930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean} 107030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 107130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean//TODO(pmclean) mutex stuff here (see out_write) 107230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) 107330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 107430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_read_buff_bytes = 0; 107530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * read_buff = buffer; 107630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean void * out_buff = buffer; 107730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 107830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in * in = (struct stream_in *) stream; 107930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 108030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->dev->lock); 108130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_lock(&in->lock); 108230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 108330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (in->standby) { 108430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (start_input_stream(in) != 0) { 108530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean goto err; 108630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 108730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = false; 108830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 108930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 109030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // OK, we need to figure out how much data to read to be able to output the requested 109130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // number of bytes in the HAL format (16-bit, stereo). 109230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = bytes; 109330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_device_channels = cached_input_hardware_config.channels; 109430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean int num_req_channels = 2; /* always, for now */ 109530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 109630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 109730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes *= num_device_channels/num_req_channels; 109830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 109930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 110030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (cached_output_hardware_config.format == PCM_FORMAT_S24_3LE) { 110130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = (3 * num_read_buff_bytes) / 2; 110230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 110330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 110430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Setup/Realloc the conversion buffer (if necessary). 110530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes != bytes) { 110630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_read_buff_bytes > in->conversion_buffer_size) { 110730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean) - remove this when AudioPolicyManger/AudioFlinger support arbitrary formats 110830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // (and do these conversions themselves) 110930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = num_read_buff_bytes; 111030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size); 111130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 111230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean read_buff = in->conversion_buffer; 111330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 111430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 111530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (pcm_read(in->pcm, read_buff, num_read_buff_bytes) == 0) { 111630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* 111730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Do any conversions necessary to send the data in the format specified to/by the HAL 111830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan. 111930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */ 112030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (cached_output_hardware_config.format == PCM_FORMAT_S24_3LE) { 112130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 112230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = read_buff; 112330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 112430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 112530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* Bit Format Conversion */ 112630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = 112730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff); 112830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 1129eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 113030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (num_device_channels != num_req_channels) { 113130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff = buffer; 113230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean /* Num Channels conversion */ 113330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes = 113430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean contract_channels_16(read_buff, num_device_channels, 113530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean out_buff, num_req_channels, 113630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean num_read_buff_bytes / sizeof(short)); 113730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 113830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 1139eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 114030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr: 114130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->lock); 114230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean pthread_mutex_unlock(&in->dev->lock); 114330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 114430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean return num_read_buff_bytes; 1145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 114730f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) 114830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{ 1149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 1150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean} 1151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 115246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev, 115346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_io_handle_t handle, 115446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood audio_devices_t devices, 115530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct audio_config *config, 115619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson struct audio_stream_in **stream_in) 115719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 115830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean ALOGV("usb: in adev_open_input_stream() rate:%d, chanMask:0x%X, fmt:%d", 115930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->sample_rate, config->channel_mask, config->format); 1160eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1161eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in)); 1162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean if (in == NULL) 1163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return -ENOMEM; 1164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean // setup function pointers 1166eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_sample_rate = in_get_sample_rate; 1167eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_sample_rate = in_set_sample_rate; 1168eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_buffer_size = in_get_buffer_size; 1169eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_channels = in_get_channels; 1170eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_format = in_get_format; 1171eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_format = in_set_format; 1172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.standby = in_standby; 1173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.dump = in_dump; 1174eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.set_parameters = in_set_parameters; 1175eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.get_parameters = in_get_parameters; 1176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.add_audio_effect = in_add_audio_effect; 1177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.common.remove_audio_effect = in_remove_audio_effect; 1178eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1179eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.set_gain = in_set_gain; 1180eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.read = in_read; 1181eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean in->stream.get_input_frames_lost = in_get_input_frames_lost; 1182eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 118330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->dev = (struct audio_device *)dev; 1184eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 118530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (output_hardware_config_is_cached) { 118630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->sample_rate = cached_output_hardware_config.rate; 1187eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 118830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->format = alsa_to_fw_format_id(cached_output_hardware_config.format); 118930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (config->format != AUDIO_FORMAT_PCM_16_BIT) { 119030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Always report PCM16 for now. AudioPolicyManagerBase/AudioFlinger dont' understand 119130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // formats with more other format, so we won't get chosen (say with a 24bit DAC). 119230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean) remove this when the above restriction is removed. 119330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->format = AUDIO_FORMAT_PCM_16_BIT; 119430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 1195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 119630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->channel_mask = audio_channel_out_mask_from_count( 119730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean cached_output_hardware_config.channels); 119830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) { 119930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // Always report STEREO for now. AudioPolicyManagerBase/AudioFlinger dont' understand 120030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // formats with more channels, so we won't get chosen (say with a 4-channel DAC). 120130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean) remove this when the above restriction is removed. 120230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; 120330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } 120430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean } else { 120530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean cached_input_hardware_config = default_alsa_in_config; 1206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 120730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->format = out_get_format(&in->stream.common); 120830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->channel_mask = out_get_channels(&in->stream.common); 120930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean config->sample_rate = out_get_sample_rate(&in->stream.common); 1210eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean } 1211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 121230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->standby = true; 121330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 121430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer = NULL; 121530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in->conversion_buffer_size = 0; 121630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 1217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *stream_in = &in->stream; 1218eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1219eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean return 0; 122019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 122119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 122230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream) 122319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 122430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean struct stream_in *in = (struct stream_in *)stream; 122530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 122630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean //TODO(pmclean) why are we doing this when stream get's freed at the end 122730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean // because it closes the pcm device 122830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean in_standby(&stream->common); 122930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 123030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(in->conversion_buffer); 123130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean 123230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean free(stream); 123319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 123419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 123519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd) 123619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 123719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 123819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 123919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 124019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device) 124119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 1242eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = (struct audio_device *)device; 124319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson free(device); 1244eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 1245eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean output_hardware_config_is_cached = false; 124630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean input_hardware_config_is_cached = false; 1247eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean 124819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 124919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 125019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 125130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) 125219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{ 125319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) 125419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -EINVAL; 125519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 1256eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean struct audio_device *adev = calloc(1, sizeof(struct audio_device)); 125719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson if (!adev) 125819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return -ENOMEM; 125919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 126019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; 126185e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0; 126219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.module = (struct hw_module_t *) module; 126319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.common.close = adev_close; 126419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 126519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.init_check = adev_init_check; 126619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_voice_volume = adev_set_voice_volume; 126719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_master_volume = adev_set_master_volume; 126819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mode = adev_set_mode; 126919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_mic_mute = adev_set_mic_mute; 127019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_mic_mute = adev_get_mic_mute; 127119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.set_parameters = adev_set_parameters; 127219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_parameters = adev_get_parameters; 127319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; 127419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_output_stream = adev_open_output_stream; 127519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_output_stream = adev_close_output_stream; 127619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.open_input_stream = adev_open_input_stream; 127719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.close_input_stream = adev_close_input_stream; 127819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson adev->hw_device.dump = adev_dump; 127919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 128019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *device = &adev->hw_device.common; 128119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 128219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson return 0; 128319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson} 128419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 128519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = { 128619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .open = adev_open, 128719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 128819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson 128919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = { 129019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .common = { 129119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .tag = HARDWARE_MODULE_TAG, 129246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .module_api_version = AUDIO_MODULE_API_VERSION_0_1, 129346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood .hal_api_version = HARDWARE_HAL_API_VERSION, 129419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .id = AUDIO_HARDWARE_MODULE_ID, 129519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .name = "USB audio HW HAL", 129619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .author = "The Android Open Source Project", 129719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson .methods = &hal_module_methods, 129819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson }, 129919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}; 1300