Moving device profile structures into streams rather than the device.
Decoupling this worthwhile change from the rest of multi-usb stuff. Bug:111397675 Test: Connect to various USB interfaces and confirm correct behavior. Change-Id: I8a5a89a1e99547a168423becea4c424b627bff9c
This commit is contained in:
parent
61d8776303
commit
cf5310a9eb
1 changed files with 68 additions and 97 deletions
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
|
||||
#define LOG_TAG "modules.usbaudio.audio_hal"
|
||||
/*#define LOG_NDEBUG 0*/
|
||||
/* #define LOG_NDEBUG 0 */
|
||||
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
@ -56,11 +56,9 @@ struct audio_device {
|
|||
pthread_mutex_t lock; /* see note below on mutex acquisition order */
|
||||
|
||||
/* output */
|
||||
alsa_device_profile out_profile;
|
||||
struct listnode output_stream_list;
|
||||
|
||||
/* input */
|
||||
alsa_device_profile in_profile;
|
||||
struct listnode input_stream_list;
|
||||
|
||||
/* lock input & output sample rates */
|
||||
|
@ -69,8 +67,6 @@ struct audio_device {
|
|||
|
||||
bool mic_muted;
|
||||
|
||||
bool standby;
|
||||
|
||||
int32_t inputs_open; /* number of input streams currently open. */
|
||||
};
|
||||
|
||||
|
@ -82,16 +78,13 @@ struct stream_lock {
|
|||
struct stream_out {
|
||||
struct audio_stream_out stream;
|
||||
|
||||
struct stream_lock lock;
|
||||
struct stream_lock lock;
|
||||
|
||||
bool standby;
|
||||
|
||||
struct audio_device *adev; /* hardware information - only using this for the lock */
|
||||
|
||||
const alsa_device_profile *profile; /* Points to the alsa_device_profile in the audio_device.
|
||||
* Const, so modifications go through adev->out_profile
|
||||
* and thus should have the hardware lock and ensure
|
||||
* stream is not active and no other open output streams.
|
||||
alsa_device_profile profile; /* The profile of the ALSA device connected to the stream.
|
||||
*/
|
||||
|
||||
alsa_device_proxy proxy; /* state of the stream */
|
||||
|
@ -124,10 +117,7 @@ struct stream_in {
|
|||
|
||||
struct audio_device *adev; /* hardware information - only using this for the lock */
|
||||
|
||||
const alsa_device_profile *profile; /* Points to the alsa_device_profile in the audio_device.
|
||||
* Const, so modifications go through adev->out_profile
|
||||
* and thus should have the hardware lock and ensure
|
||||
* stream is not active and no other open input streams.
|
||||
alsa_device_profile profile; /* The profile of the ALSA device connected to the stream.
|
||||
*/
|
||||
|
||||
alsa_device_proxy proxy; /* state of the stream */
|
||||
|
@ -347,9 +337,7 @@ static int out_standby(struct audio_stream *stream)
|
|||
|
||||
stream_lock(&out->lock);
|
||||
if (!out->standby) {
|
||||
device_lock(out->adev);
|
||||
proxy_close(&out->proxy);
|
||||
device_unlock(out->adev);
|
||||
out->standby = true;
|
||||
}
|
||||
stream_unlock(&out->lock);
|
||||
|
@ -361,7 +349,7 @@ static int out_dump(const struct audio_stream *stream, int fd) {
|
|||
|
||||
if (out_stream != NULL) {
|
||||
dprintf(fd, "Output Profile:\n");
|
||||
profile_dump(out_stream->profile, fd);
|
||||
profile_dump(&out_stream->profile, fd);
|
||||
|
||||
dprintf(fd, "Output Proxy:\n");
|
||||
proxy_dump(&out_stream->proxy, fd);
|
||||
|
@ -386,27 +374,23 @@ static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
|
|||
}
|
||||
|
||||
stream_lock(&out->lock);
|
||||
/* Lock the device because that is where the profile lives */
|
||||
device_lock(out->adev);
|
||||
|
||||
if (!profile_is_cached_for(out->profile, card, device)) {
|
||||
if (!profile_is_cached_for(&out->profile, card, device)) {
|
||||
/* cannot read pcm device info if playback is active */
|
||||
if (!out->standby)
|
||||
ret_value = -ENOSYS;
|
||||
else {
|
||||
int saved_card = out->profile->card;
|
||||
int saved_device = out->profile->device;
|
||||
out->adev->out_profile.card = card;
|
||||
out->adev->out_profile.device = device;
|
||||
ret_value = profile_read_device_info(&out->adev->out_profile) ? 0 : -EINVAL;
|
||||
int saved_card = out->profile.card;
|
||||
int saved_device = out->profile.device;
|
||||
out->profile.card = card;
|
||||
out->profile.device = device;
|
||||
ret_value = profile_read_device_info(&out->profile) ? 0 : -EINVAL;
|
||||
if (ret_value != 0) {
|
||||
out->adev->out_profile.card = saved_card;
|
||||
out->adev->out_profile.device = saved_device;
|
||||
out->profile.card = saved_card;
|
||||
out->profile.device = saved_device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
device_unlock(out->adev);
|
||||
stream_unlock(&out->lock);
|
||||
|
||||
return ret_value;
|
||||
|
@ -416,11 +400,7 @@ static char * out_get_parameters(const struct audio_stream *stream, const char *
|
|||
{
|
||||
struct stream_out *out = (struct stream_out *)stream;
|
||||
stream_lock(&out->lock);
|
||||
device_lock(out->adev);
|
||||
|
||||
char * params_str = device_get_parameters(out->profile, keys);
|
||||
|
||||
device_unlock(out->adev);
|
||||
char * params_str = device_get_parameters(&out->profile, keys);
|
||||
stream_unlock(&out->lock);
|
||||
return params_str;
|
||||
}
|
||||
|
@ -439,7 +419,7 @@ static int out_set_volume(struct audio_stream_out *stream, float left, float rig
|
|||
/* must be called with hw device and output stream mutexes locked */
|
||||
static int start_output_stream(struct stream_out *out)
|
||||
{
|
||||
ALOGV("start_output_stream(card:%d device:%d)", out->profile->card, out->profile->device);
|
||||
ALOGV("start_output_stream(card:%d device:%d)", out->profile.card, out->profile.device);
|
||||
|
||||
return proxy_open(&out->proxy);
|
||||
}
|
||||
|
@ -451,9 +431,7 @@ static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, si
|
|||
|
||||
stream_lock(&out->lock);
|
||||
if (out->standby) {
|
||||
device_lock(out->adev);
|
||||
ret = start_output_stream(out);
|
||||
device_unlock(out->adev);
|
||||
if (ret != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
@ -576,44 +554,45 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
|
|||
stream_lock_init(&out->lock);
|
||||
|
||||
out->adev = (struct audio_device *)hw_dev;
|
||||
device_lock(out->adev);
|
||||
out->profile = &out->adev->out_profile;
|
||||
|
||||
profile_init(&out->profile, PCM_OUT);
|
||||
|
||||
// build this to hand to the alsa_device_proxy
|
||||
struct pcm_config proxy_config;
|
||||
memset(&proxy_config, 0, sizeof(proxy_config));
|
||||
|
||||
/* Pull out the card/device pair */
|
||||
parse_card_device_params(address, &out->adev->out_profile.card, &out->adev->out_profile.device);
|
||||
parse_card_device_params(address, &out->profile.card, &out->profile.device);
|
||||
|
||||
profile_read_device_info(&out->adev->out_profile);
|
||||
profile_read_device_info(&out->profile);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
/* Rate */
|
||||
if (config->sample_rate == 0) {
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
|
||||
} else if (profile_is_sample_rate_valid(out->profile, config->sample_rate)) {
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&out->profile);
|
||||
} else if (profile_is_sample_rate_valid(&out->profile, config->sample_rate)) {
|
||||
proxy_config.rate = config->sample_rate;
|
||||
} else {
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(out->profile);
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&out->profile);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* TODO: This is a problem if the input does not support this rate */
|
||||
device_lock(out->adev);
|
||||
out->adev->device_sample_rate = config->sample_rate;
|
||||
device_unlock(out->adev);
|
||||
|
||||
/* Format */
|
||||
if (config->format == AUDIO_FORMAT_DEFAULT) {
|
||||
proxy_config.format = profile_get_default_format(out->profile);
|
||||
proxy_config.format = profile_get_default_format(&out->profile);
|
||||
config->format = audio_format_from_pcm_format(proxy_config.format);
|
||||
} else {
|
||||
enum pcm_format fmt = pcm_format_from_audio_format(config->format);
|
||||
if (profile_is_format_valid(out->profile, fmt)) {
|
||||
if (profile_is_format_valid(&out->profile, fmt)) {
|
||||
proxy_config.format = fmt;
|
||||
} else {
|
||||
proxy_config.format = profile_get_default_format(out->profile);
|
||||
proxy_config.format = profile_get_default_format(&out->profile);
|
||||
config->format = audio_format_from_pcm_format(proxy_config.format);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -623,7 +602,7 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
|
|||
bool calc_mask = false;
|
||||
if (config->channel_mask == AUDIO_CHANNEL_NONE) {
|
||||
/* query case */
|
||||
out->hal_channel_count = profile_get_default_channel_count(out->profile);
|
||||
out->hal_channel_count = profile_get_default_channel_count(&out->profile);
|
||||
calc_mask = true;
|
||||
} else {
|
||||
/* explicit case */
|
||||
|
@ -651,8 +630,9 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
|
|||
// Validate the "logical" channel count against support in the "actual" profile.
|
||||
// if they differ, choose the "actual" number of channels *closest* to the "logical".
|
||||
// and store THAT in proxy_config.channels
|
||||
proxy_config.channels = profile_get_closest_channel_count(out->profile, out->hal_channel_count);
|
||||
proxy_prepare(&out->proxy, out->profile, &proxy_config);
|
||||
proxy_config.channels =
|
||||
profile_get_closest_channel_count(&out->profile, out->hal_channel_count);
|
||||
proxy_prepare(&out->proxy, &out->profile, &proxy_config);
|
||||
|
||||
/* TODO The retry mechanism isn't implemented in AudioPolicyManager/AudioFlinger
|
||||
* So clear any errors that may have occurred above.
|
||||
|
@ -676,9 +656,7 @@ static void adev_close_output_stream(struct audio_hw_device *hw_dev,
|
|||
struct audio_stream_out *stream)
|
||||
{
|
||||
struct stream_out *out = (struct stream_out *)stream;
|
||||
ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile->card, out->profile->device);
|
||||
|
||||
adev_remove_stream_from_list(out->adev, &out->list_node);
|
||||
ALOGV("adev_close_output_stream(c:%d d:%d)", out->profile.card, out->profile.device);
|
||||
|
||||
/* Close the pcm device */
|
||||
out_standby(&stream->common);
|
||||
|
@ -688,6 +666,8 @@ static void adev_close_output_stream(struct audio_hw_device *hw_dev,
|
|||
out->conversion_buffer = NULL;
|
||||
out->conversion_buffer_size = 0;
|
||||
|
||||
adev_remove_stream_from_list(out->adev, &out->list_node);
|
||||
|
||||
device_lock(out->adev);
|
||||
out->adev->device_sample_rate = 0;
|
||||
device_unlock(out->adev);
|
||||
|
@ -750,12 +730,9 @@ static int in_standby(struct audio_stream *stream)
|
|||
|
||||
stream_lock(&in->lock);
|
||||
if (!in->standby) {
|
||||
device_lock(in->adev);
|
||||
proxy_close(&in->proxy);
|
||||
device_unlock(in->adev);
|
||||
in->standby = true;
|
||||
}
|
||||
|
||||
stream_unlock(&in->lock);
|
||||
|
||||
return 0;
|
||||
|
@ -766,7 +743,7 @@ static int in_dump(const struct audio_stream *stream, int fd)
|
|||
const struct stream_in* in_stream = (const struct stream_in*)stream;
|
||||
if (in_stream != NULL) {
|
||||
dprintf(fd, "Input Profile:\n");
|
||||
profile_dump(in_stream->profile, fd);
|
||||
profile_dump(&in_stream->profile, fd);
|
||||
|
||||
dprintf(fd, "Input Proxy:\n");
|
||||
proxy_dump(&in_stream->proxy, fd);
|
||||
|
@ -793,19 +770,20 @@ static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
|
|||
stream_lock(&in->lock);
|
||||
device_lock(in->adev);
|
||||
|
||||
if (card >= 0 && device >= 0 && !profile_is_cached_for(in->profile, card, device)) {
|
||||
/* cannot read pcm device info if playback is active, or more than one open stream */
|
||||
if (card >= 0 && device >= 0 && !profile_is_cached_for(&in->profile, card, device)) {
|
||||
/* cannot read pcm device info if capture is active, or more than one open stream */
|
||||
if (!in->standby || in->adev->inputs_open > 1)
|
||||
ret_value = -ENOSYS;
|
||||
else {
|
||||
int saved_card = in->profile->card;
|
||||
int saved_device = in->profile->device;
|
||||
in->adev->in_profile.card = card;
|
||||
in->adev->in_profile.device = device;
|
||||
ret_value = profile_read_device_info(&in->adev->in_profile) ? 0 : -EINVAL;
|
||||
int saved_card = in->profile.card;
|
||||
int saved_device = in->profile.device;
|
||||
in->profile.card = card;
|
||||
in->profile.device = device;
|
||||
ret_value = profile_read_device_info(&in->profile) ? 0 : -EINVAL;
|
||||
if (ret_value != 0) {
|
||||
in->adev->in_profile.card = saved_card;
|
||||
in->adev->in_profile.device = saved_device;
|
||||
ALOGE("Can't read device profile. card:%d, device:%d", card, device);
|
||||
in->profile.card = saved_card;
|
||||
in->profile.device = saved_device;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -821,11 +799,7 @@ static char * in_get_parameters(const struct audio_stream *stream, const char *k
|
|||
struct stream_in *in = (struct stream_in *)stream;
|
||||
|
||||
stream_lock(&in->lock);
|
||||
device_lock(in->adev);
|
||||
|
||||
char * params_str = device_get_parameters(in->profile, keys);
|
||||
|
||||
device_unlock(in->adev);
|
||||
char * params_str = device_get_parameters(&in->profile, keys);
|
||||
stream_unlock(&in->lock);
|
||||
|
||||
return params_str;
|
||||
|
@ -849,7 +823,7 @@ static int in_set_gain(struct audio_stream_in *stream, float gain)
|
|||
/* must be called with hw device and output stream mutexes locked */
|
||||
static int start_input_stream(struct stream_in *in)
|
||||
{
|
||||
ALOGV("start_input_stream(card:%d device:%d)", in->profile->card, in->profile->device);
|
||||
ALOGV("start_input_stream(card:%d device:%d)", in->profile.card, in->profile.device);
|
||||
|
||||
return proxy_open(&in->proxy);
|
||||
}
|
||||
|
@ -866,9 +840,7 @@ static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t byte
|
|||
|
||||
stream_lock(&in->lock);
|
||||
if (in->standby) {
|
||||
device_lock(in->adev);
|
||||
ret = start_input_stream(in);
|
||||
device_unlock(in->adev);
|
||||
if (ret != 0) {
|
||||
goto err;
|
||||
}
|
||||
|
@ -994,32 +966,34 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
|
|||
stream_lock_init(&in->lock);
|
||||
|
||||
in->adev = (struct audio_device *)hw_dev;
|
||||
device_lock(in->adev);
|
||||
|
||||
in->profile = &in->adev->in_profile;
|
||||
profile_init(&in->profile, PCM_IN);
|
||||
|
||||
struct pcm_config proxy_config;
|
||||
memset(&proxy_config, 0, sizeof(proxy_config));
|
||||
|
||||
int ret = 0;
|
||||
device_lock(in->adev);
|
||||
int num_open_inputs = in->adev->inputs_open;
|
||||
device_unlock(in->adev);
|
||||
|
||||
/* Check if an input stream is already open */
|
||||
if (in->adev->inputs_open > 0) {
|
||||
if (!profile_is_cached_for(in->profile, card, device)) {
|
||||
if (num_open_inputs > 0) {
|
||||
if (!profile_is_cached_for(&in->profile, card, device)) {
|
||||
ALOGW("%s fail - address card:%d device:%d doesn't match existing profile",
|
||||
__func__, card, device);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/* Read input profile only if necessary */
|
||||
in->adev->in_profile.card = card;
|
||||
in->adev->in_profile.device = device;
|
||||
if (!profile_read_device_info(&in->adev->in_profile)) {
|
||||
in->profile.card = card;
|
||||
in->profile.device = device;
|
||||
if (!profile_read_device_info(&in->profile)) {
|
||||
ALOGW("%s fail - cannot read profile", __func__);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
if (ret != 0) {
|
||||
device_unlock(in->adev);
|
||||
free(in);
|
||||
*stream_in = NULL;
|
||||
return ret;
|
||||
|
@ -1028,13 +1002,13 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
|
|||
/* Rate */
|
||||
int request_config_rate = config->sample_rate;
|
||||
if (config->sample_rate == 0) {
|
||||
config->sample_rate = profile_get_default_sample_rate(in->profile);
|
||||
config->sample_rate = profile_get_default_sample_rate(&in->profile);
|
||||
}
|
||||
|
||||
if (in->adev->device_sample_rate != 0 && /* we are playing, so lock the rate if possible */
|
||||
in->adev->device_sample_rate >= RATELOCK_THRESHOLD) {/* but only for high sample rates */
|
||||
if (config->sample_rate != in->adev->device_sample_rate) {
|
||||
unsigned highest_rate = profile_get_highest_sample_rate(in->profile);
|
||||
unsigned highest_rate = profile_get_highest_sample_rate(&in->profile);
|
||||
if (highest_rate == 0) {
|
||||
ret = -EINVAL; /* error with device */
|
||||
} else {
|
||||
|
@ -1049,25 +1023,23 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (profile_is_sample_rate_valid(in->profile, config->sample_rate)) {
|
||||
} else if (profile_is_sample_rate_valid(&in->profile, config->sample_rate)) {
|
||||
proxy_config.rate = config->sample_rate;
|
||||
} else {
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(in->profile);
|
||||
proxy_config.rate = config->sample_rate = profile_get_default_sample_rate(&in->profile);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
device_unlock(in->adev);
|
||||
|
||||
/* Format */
|
||||
if (config->format == AUDIO_FORMAT_DEFAULT) {
|
||||
proxy_config.format = profile_get_default_format(in->profile);
|
||||
proxy_config.format = profile_get_default_format(&in->profile);
|
||||
config->format = audio_format_from_pcm_format(proxy_config.format);
|
||||
} else {
|
||||
enum pcm_format fmt = pcm_format_from_audio_format(config->format);
|
||||
if (profile_is_format_valid(in->profile, fmt)) {
|
||||
if (profile_is_format_valid(&in->profile, fmt)) {
|
||||
proxy_config.format = fmt;
|
||||
} else {
|
||||
proxy_config.format = profile_get_default_format(in->profile);
|
||||
proxy_config.format = profile_get_default_format(&in->profile);
|
||||
config->format = audio_format_from_pcm_format(proxy_config.format);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -1077,7 +1049,7 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
|
|||
bool calc_mask = false;
|
||||
if (config->channel_mask == AUDIO_CHANNEL_NONE) {
|
||||
/* query case */
|
||||
in->hal_channel_count = profile_get_default_channel_count(in->profile);
|
||||
in->hal_channel_count = profile_get_default_channel_count(&in->profile);
|
||||
calc_mask = true;
|
||||
} else {
|
||||
/* explicit case */
|
||||
|
@ -1114,8 +1086,8 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
|
|||
// if they differ, choose the "actual" number of channels *closest* to the "logical".
|
||||
// and store THAT in proxy_config.channels
|
||||
proxy_config.channels =
|
||||
profile_get_closest_channel_count(in->profile, in->hal_channel_count);
|
||||
ret = proxy_prepare(&in->proxy, in->profile, &proxy_config);
|
||||
profile_get_closest_channel_count(&in->profile, in->hal_channel_count);
|
||||
ret = proxy_prepare(&in->proxy, &in->profile, &proxy_config);
|
||||
if (ret == 0) {
|
||||
in->standby = true;
|
||||
|
||||
|
@ -1155,7 +1127,7 @@ static void adev_close_input_stream(struct audio_hw_device *hw_dev,
|
|||
struct audio_stream_in *stream)
|
||||
{
|
||||
struct stream_in *in = (struct stream_in *)stream;
|
||||
ALOGV("adev_close_input_stream(c:%d d:%d)", in->profile->card, in->profile->device);
|
||||
ALOGV("adev_close_input_stream(c:%d d:%d)", in->profile.card, in->profile.device);
|
||||
|
||||
adev_remove_stream_from_list(in->adev, &in->list_node);
|
||||
|
||||
|
@ -1283,8 +1255,7 @@ static int adev_open(const hw_module_t* module, const char* name, hw_device_t**
|
|||
if (!adev)
|
||||
return -ENOMEM;
|
||||
|
||||
profile_init(&adev->out_profile, PCM_OUT);
|
||||
profile_init(&adev->in_profile, PCM_IN);
|
||||
pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
|
||||
|
||||
list_init(&adev->output_stream_list);
|
||||
list_init(&adev->input_stream_list);
|
||||
|
|
Loading…
Reference in a new issue