From: Simon Wilson Date: Fri, 6 Apr 2012 23:17:12 +0000 (-0700) Subject: usbaudio: add initial usbaudio default HAL X-Git-Tag: android-x86-4.4-r1~287 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=19957a37a0f92257d8cccb5cbcb6e57a836d33ac;p=android-x86%2Fhardware-libhardware.git usbaudio: add initial usbaudio default HAL Change-Id: I6e93b2512883f3697683a74cadb9a29113966bc0 --- diff --git a/modules/Android.mk b/modules/Android.mk index b8b83ba..871b984 100644 --- a/modules/Android.mk +++ b/modules/Android.mk @@ -1,2 +1,2 @@ -hardware_modules := gralloc hwcomposer audio nfc local_time power +hardware_modules := gralloc hwcomposer audio nfc local_time power usbaudio include $(call all-named-subdir-makefiles,$(hardware_modules)) diff --git a/modules/usbaudio/Android.mk b/modules/usbaudio/Android.mk new file mode 100644 index 0000000..6b5e66d --- /dev/null +++ b/modules/usbaudio/Android.mk @@ -0,0 +1,29 @@ +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := audio.usb.default +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw +LOCAL_SRC_FILES := \ + audio_hw.c +LOCAL_C_INCLUDES += \ + external/tinyalsa/include +LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) + diff --git a/modules/usbaudio/audio_hw.c b/modules/usbaudio/audio_hw.c new file mode 100644 index 0000000..4022efd --- /dev/null +++ b/modules/usbaudio/audio_hw.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "usb_audio_hw" +/*#define LOG_NDEBUG 0*/ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +struct pcm_config pcm_config = { + .channels = 2, + .rate = 44100, + .period_size = 1024, + .period_count = 4, + .format = PCM_FORMAT_S16_LE, +}; + +struct audio_device { + struct audio_hw_device hw_device; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + int card; + int device; + bool standby; +}; + +struct stream_out { + struct audio_stream_out stream; + + pthread_mutex_t lock; /* see note below on mutex acquisition order */ + struct pcm *pcm; + bool standby; + + struct audio_device *dev; +}; + +/** + * NOTE: when multiple mutexes have to be acquired, always respect the + * following order: hw device > out stream + */ + +/* Helper functions */ + +/* must be called with hw device and output stream mutexes locked */ +static int start_output_stream(struct stream_out *out) +{ + struct audio_device *adev = out->dev; + int i; + + if ((adev->card < 0) || (adev->device < 0)) + return -EINVAL; + + out->pcm = pcm_open(adev->card, adev->device, PCM_OUT, &pcm_config); + + if (out->pcm && !pcm_is_ready(out->pcm)) { + ALOGE("pcm_open() failed: %s", pcm_get_error(out->pcm)); + pcm_close(out->pcm); + return -ENOMEM; + } + + return 0; +} + +/* API functions */ + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + return pcm_config.rate; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + return 0; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + return pcm_config.period_size * + audio_stream_frame_size((struct audio_stream *)stream); +} + +static uint32_t out_get_channels(const struct audio_stream *stream) +{ + return AUDIO_CHANNEL_OUT_STEREO; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + return 0; +} + +static int out_standby(struct audio_stream *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + + if (!out->standby) { + pcm_close(out->pcm); + out->pcm = NULL; + out->standby = true; + } + + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + + return 0; +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + return 0; +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + struct stream_out *out = (struct stream_out *)stream; + struct audio_device *adev = out->dev; + struct str_parms *parms; + char value[32]; + int ret; + int routing = 0; + + parms = str_parms_create_str(kvpairs); + pthread_mutex_lock(&adev->lock); + + adev->card = -1; + adev->device = -1; + + ret = str_parms_get_str(parms, "card", value, sizeof(value)); + if (ret >= 0) + adev->card = atoi(value); + + ret = str_parms_get_str(parms, "device", value, sizeof(value)); + if (ret >= 0) + adev->device = atoi(value); + + pthread_mutex_unlock(&adev->lock); + str_parms_destroy(parms); + + return 0; +} + +static char * out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + return strdup(""); +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + return (pcm_config.period_size * pcm_config.period_count * 1000) / + out_get_sample_rate(&stream->common); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + return -ENOSYS; +} + +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, + size_t bytes) +{ + int ret; + struct stream_out *out = (struct stream_out *)stream; + + pthread_mutex_lock(&out->dev->lock); + pthread_mutex_lock(&out->lock); + if (out->standby) { + ret = start_output_stream(out); + if (ret != 0) { + goto err; + } + out->standby = false; + } + + pcm_write(out->pcm, (void *)buffer, bytes); + + pthread_mutex_unlock(&out->lock); + pthread_mutex_unlock(&out->dev->lock); + + return bytes; + +err: + pthread_mutex_unlock(&out->lock); + + if (ret != 0) { + usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) / + out_get_sample_rate(&stream->common)); + } + + return bytes; +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + return -EINVAL; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + return -EINVAL; +} + +static int adev_open_output_stream(struct audio_hw_device *dev, + uint32_t devices, audio_format_t *format, + uint32_t *channels, uint32_t *sample_rate, + struct audio_stream_out **stream_out) +{ + struct audio_device *adev = (struct audio_device *)dev; + struct stream_out *out; + int ret; + + out = (struct stream_out *)calloc(1, sizeof(struct stream_out)); + if (!out) + return -ENOMEM; + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + + out->dev = adev; + + *format = out_get_format(&out->stream.common); + *channels = out_get_channels(&out->stream.common); + *sample_rate = out_get_sample_rate(&out->stream.common); + + out->standby = true; + + *stream_out = &out->stream; + return 0; + +err_open: + free(out); + *stream_out = NULL; + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + struct stream_out *out = (struct stream_out *)stream; + + out_standby(&stream->common); + free(stream); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + return 0; +} + +static char * adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + return strdup(""); +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + return 0; +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + return -ENOSYS; +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + return -ENOSYS; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + return -ENOSYS; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + uint32_t sample_rate, audio_format_t format, + int channel_count) +{ + return 0; +} + +static int adev_open_input_stream(struct audio_hw_device *dev, uint32_t devices, + audio_format_t *format, uint32_t *channel_mask, + uint32_t *sample_rate, + audio_in_acoustics_t acoustics, + struct audio_stream_in **stream_in) +{ + return -ENOSYS; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ +} + +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + return 0; +} + +static int adev_close(hw_device_t *device) +{ + struct audio_device *adev = (struct audio_device *)device; + + free(device); + return 0; +} + +static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) +{ + return AUDIO_DEVICE_OUT_ALL_USB; +} + +static int adev_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + struct audio_device *adev; + int ret; + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + adev = calloc(1, sizeof(struct audio_device)); + if (!adev) + return -ENOMEM; + + adev->hw_device.common.tag = HARDWARE_DEVICE_TAG; + adev->hw_device.common.version = 0; + adev->hw_device.common.module = (struct hw_module_t *) module; + adev->hw_device.common.close = adev_close; + + adev->hw_device.get_supported_devices = adev_get_supported_devices; + adev->hw_device.init_check = adev_init_check; + adev->hw_device.set_voice_volume = adev_set_voice_volume; + adev->hw_device.set_master_volume = adev_set_master_volume; + adev->hw_device.set_mode = adev_set_mode; + adev->hw_device.set_mic_mute = adev_set_mic_mute; + adev->hw_device.get_mic_mute = adev_get_mic_mute; + adev->hw_device.set_parameters = adev_set_parameters; + adev->hw_device.get_parameters = adev_get_parameters; + adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size; + adev->hw_device.open_output_stream = adev_open_output_stream; + adev->hw_device.close_output_stream = adev_close_output_stream; + adev->hw_device.open_input_stream = adev_open_input_stream; + adev->hw_device.close_input_stream = adev_close_input_stream; + adev->hw_device.dump = adev_dump; + + *device = &adev->hw_device.common; + + return 0; +} + +static struct hw_module_methods_t hal_module_methods = { + .open = adev_open, +}; + +struct audio_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .version_major = 1, + .version_minor = 0, + .id = AUDIO_HARDWARE_MODULE_ID, + .name = "USB audio HW HAL", + .author = "The Android Open Source Project", + .methods = &hal_module_methods, + }, +};